/* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "drm_utils.h" #include "drm_crtc.h" #include "drm_property.h" namespace sde_drm { using std::string; using std::stringstream; using std::unique_ptr; using std::mutex; using std::lock_guard; using std::pair; using std::vector; // CRTC Security Levels static uint8_t SECURE_NON_SECURE = 0; static uint8_t SECURE_ONLY = 1; // CWB Capture Modes static uint8_t CAPTURE_MIXER_OUT = 0; static uint8_t CAPTURE_DSPP_OUT = 1; // Idle PC states static uint8_t IDLE_PC_STATE_NONE = 0; static uint8_t IDLE_PC_STATE_ENABLE = 1; static uint8_t IDLE_PC_STATE_DISABLE = 2; static void PopulateSecurityLevels(drmModePropertyRes *prop) { static bool security_levels_populated = false; if (!security_levels_populated) { for (auto i = 0; i < prop->count_enums; i++) { string enum_name(prop->enums[i].name); if (enum_name == "sec_and_non_sec") { SECURE_NON_SECURE = prop->enums[i].value; } else if (enum_name == "sec_only") { SECURE_ONLY = prop->enums[i].value; } } security_levels_populated = true; } } static void PopulateCWbCaptureModes(drmModePropertyRes *prop) { static bool capture_modes_populated = false; if (!capture_modes_populated) { for (auto i = 0; i < prop->count_enums; i++) { string enum_name(prop->enums[i].name); if (enum_name == "capture_mixer_out") { CAPTURE_MIXER_OUT = prop->enums[i].value; } else if (enum_name == "capture_pp_out") { CAPTURE_DSPP_OUT = prop->enums[i].value; } } capture_modes_populated = true; } } static void PopulateIdlePCStates(drmModePropertyRes *prop) { static bool idle_pc_state_populated = false; if (!idle_pc_state_populated) { for (auto i = 0; i < prop->count_enums; i++) { string enum_name(prop->enums[i].name); if (enum_name == "idle_pc_none") { IDLE_PC_STATE_NONE = prop->enums[i].value; } else if (enum_name == "idle_pc_enable") { IDLE_PC_STATE_ENABLE = prop->enums[i].value; } else if (enum_name == "idle_pc_disable") { IDLE_PC_STATE_DISABLE = prop->enums[i].value; } } idle_pc_state_populated = true; } } #define __CLASS__ "DRMCrtcManager" void DRMCrtcManager::Init(drmModeRes *resource) { for (int i = 0; i < resource->count_crtcs; i++) { unique_ptr crtc(new DRMCrtc(fd_, i)); drmModeCrtc *libdrm_crtc = drmModeGetCrtc(fd_, resource->crtcs[i]); if (libdrm_crtc) { crtc->InitAndParse(libdrm_crtc); object_pool_[resource->crtcs[i]] = std::move(crtc); } else { DRM_LOGE("Critical error: drmModeGetCrtc() failed for crtc %d.", resource->crtcs[i]); } } } void DRMCrtcManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args) { lock_guard lock(lock_); auto crtc = GetObject(obj_id); if (crtc == nullptr) { DRM_LOGE("Invalid crtc id %d", obj_id); return; } if (code == DRMOps::CRTC_SET_DEST_SCALER_CONFIG) { if (crtc->ConfigureScalerLUT(dir_lut_blob_id_, cir_lut_blob_id_, sep_lut_blob_id_)) { DRM_LOGD("CRTC %d: Configuring scaler LUTs", obj_id); } } crtc->Perform(code, req, args); } void DRMCrtcManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) { // qseed3lite lut is hardcoded in HW. No need to program from sw. DRMCrtcInfo info; object_pool_.begin()->second->GetInfo(&info); if (info.qseed_version == QSEEDVersion::V3LITE) { return; } if (lut_info.dir_lut_size) { drmModeCreatePropertyBlob(fd_, reinterpret_cast(lut_info.dir_lut), lut_info.dir_lut_size, &dir_lut_blob_id_); } if (lut_info.cir_lut_size) { drmModeCreatePropertyBlob(fd_, reinterpret_cast(lut_info.cir_lut), lut_info.cir_lut_size, &cir_lut_blob_id_); } if (lut_info.sep_lut_size) { drmModeCreatePropertyBlob(fd_, reinterpret_cast(lut_info.sep_lut), lut_info.sep_lut_size, &sep_lut_blob_id_); } } void DRMCrtcManager::UnsetScalerLUT() { if (dir_lut_blob_id_) { drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_); dir_lut_blob_id_ = 0; } if (cir_lut_blob_id_) { drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_); cir_lut_blob_id_ = 0; } if (sep_lut_blob_id_) { drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_); sep_lut_blob_id_ = 0; } } int DRMCrtcManager::GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info) { if (crtc_id == 0) { object_pool_.begin()->second->GetInfo(info); } else { auto crtc = GetObject(crtc_id); if (crtc == nullptr) { DRM_LOGE("Invalid crtc id %d", crtc_id); return -ENODEV; } else { crtc->GetInfo(info); } } return 0; } void DRMCrtcManager::GetPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info) { auto crtc = GetObject(crtc_id); if (crtc == nullptr) { DRM_LOGE("Invalid crtc id %d", crtc_id); return; } crtc->GetPPInfo(info); } int DRMCrtcManager::Reserve(const std::set &possible_crtc_indices, DRMDisplayToken *token) { for (auto &item : object_pool_) { if (item.second->GetStatus() == DRMStatus::FREE) { if (possible_crtc_indices.find(item.second->GetIndex()) != possible_crtc_indices.end()) { item.second->Lock(); token->crtc_id = item.first; token->crtc_index = item.second->GetIndex(); return 0; } } } return -ENODEV; } void DRMCrtcManager::Free(DRMDisplayToken *token) { lock_guard lock(lock_); object_pool_.at(token->crtc_id)->Unlock(); token->crtc_id = 0; token->crtc_index = 0; } // ==============================================================================================// #undef __CLASS__ #define __CLASS__ "DRMCrtc" DRMCrtc::DRMCrtc(int fd, uint32_t crtc_index) : DRMObject(prop_mgr_), fd_(fd), crtc_index_(crtc_index) {} DRMCrtc::~DRMCrtc() { if (drm_crtc_) { drmModeFreeCrtc(drm_crtc_); } } void DRMCrtc::ParseProperties() { drmModeObjectProperties *props = drmModeObjectGetProperties(fd_, drm_crtc_->crtc_id, DRM_MODE_OBJECT_CRTC); if (!props || !props->props || !props->prop_values) { drmModeFreeObjectProperties(props); return; } for (uint32_t j = 0; j < props->count_props; j++) { drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]); if (!info) { continue; } string property_name(info->name); DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name); if (prop_enum == DRMProperty::INVALID) { DRM_LOGD("DRMProperty %s missing from global property mapping", info->name); drmModeFreeProperty(info); continue; } if (prop_enum == DRMProperty::SECURITY_LEVEL) { PopulateSecurityLevels(info); } if (prop_enum == DRMProperty::CAPTURE_MODE) { crtc_info_.concurrent_writeback = true; PopulateCWbCaptureModes(info); } if (prop_enum == DRMProperty::IDLE_PC_STATE) { PopulateIdlePCStates(info); } prop_mgr_.SetPropertyId(prop_enum, info->prop_id); if (prop_enum == DRMProperty::CAPABILITIES) { ParseCapabilities(props->prop_values[j]); } drmModeFreeProperty(info); } drmModeFreeObjectProperties(props); } void DRMCrtc::ParseCapabilities(uint64_t blob_id) { drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id); if (!blob) { return; } if (!blob->data) { return; } char *fmt_str = new char[blob->length + 1]; memcpy (fmt_str, blob->data, blob->length); fmt_str[blob->length] = '\0'; stringstream stream(fmt_str); DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(), static_cast(blob->data), blob->length); string line = {}; string max_blendstages = "max_blendstages="; string qseed_type = "qseed_type="; string has_src_split = "has_src_split="; string sdma_rev = "smart_dma_rev="; string core_ib_ff = "core_ib_ff="; string dest_scale_prefill_lines = "dest_scale_prefill_lines="; string undersized_prefill_lines = "undersized_prefill_lines="; string macrotile_prefill_lines = "macrotile_prefill_lines="; string yuv_nv12_prefill_lines = "yuv_nv12_prefill_lines="; string linear_prefill_lines = "linear_prefill_lines="; string downscaling_prefill_lines = "downscaling_prefill_lines="; string xtra_prefill_lines = "xtra_prefill_lines="; string amortizable_threshold = "amortizable_threshold="; string max_bandwidth_low = "max_bandwidth_low="; string max_bandwidth_high = "max_bandwidth_high="; string max_mdp_clk = "max_mdp_clk="; string core_clk_ff = "core_clk_ff="; string comp_ratio_rt = "comp_ratio_rt="; string comp_ratio_nrt = "comp_ratio_nrt="; string hw_version = "hw_version="; string solidfill_stages = "dim_layer_v1_max_layers="; string has_hdr = "has_hdr="; string has_micro_idle = "has_uidle="; string min_prefill_lines = "min_prefill_lines="; string num_mnocports = "num_mnoc_ports="; string mnoc_bus_width = "axi_bus_width="; crtc_info_.max_solidfill_stages = 0; // default _ string dest_scaler_count = "dest_scaler_count="; string max_dest_scale_up = "max_dest_scale_up="; string max_dest_scaler_input_width = "max_dest_scaler_input_width="; string max_dest_scaler_output_width = "max_dest_scaler_output_width="; string sec_ui_blendstage = "sec_ui_blendstage="; string vig = "vig="; string dma = "dma="; string scaling = "scale="; string rotation = "inline_rot="; string linewidth_constraints = "sspp_linewidth_usecases="; string linewidth_values = "sspp_linewidth_values="; string limit_constraint = "limit_usecase="; string limit_value = "limit_value="; string use_baselayer_for_stage = "use_baselayer_for_stage="; string ubwc_version = "UBWC version="; while (std::getline(stream, line)) { if (line.find(max_blendstages) != string::npos) { crtc_info_.max_blend_stages = std::stoi(string(line, max_blendstages.length())); } else if (line.find(qseed_type) != string::npos) { if (string(line, qseed_type.length()) == "qseed2") { crtc_info_.qseed_version = QSEEDVersion::V2; } else if (string(line, qseed_type.length()) == "qseed3") { crtc_info_.qseed_version = QSEEDVersion::V3; } else if (string(line, qseed_type.length()) == "qseed3lite") { crtc_info_.qseed_version = QSEEDVersion::V3LITE; } } else if (line.find(has_src_split) != string::npos) { crtc_info_.has_src_split = std::stoi(string(line, has_src_split.length())); } else if (line.find(sdma_rev) != string::npos) { if (string(line, sdma_rev.length()) == "smart_dma_v2p5") crtc_info_.smart_dma_rev = SmartDMARevision::V2p5; else if (string(line, sdma_rev.length()) == "smart_dma_v2") crtc_info_.smart_dma_rev = SmartDMARevision::V2; else if (string(line, sdma_rev.length()) == "smart_dma_v1") crtc_info_.smart_dma_rev = SmartDMARevision::V1; } else if (line.find(core_ib_ff) != string::npos) { crtc_info_.ib_fudge_factor = std::stof(string(line, core_ib_ff.length())); } else if (line.find(dest_scale_prefill_lines) != string::npos) { crtc_info_.dest_scale_prefill_lines = std::stoi(string(line, dest_scale_prefill_lines.length())); } else if (line.find(undersized_prefill_lines) != string::npos) { crtc_info_.undersized_prefill_lines = std::stoi(string(line, undersized_prefill_lines.length())); } else if (line.find(macrotile_prefill_lines) != string::npos) { crtc_info_.macrotile_prefill_lines = std::stoi(string(line, macrotile_prefill_lines.length())); } else if (line.find(yuv_nv12_prefill_lines) != string::npos) { crtc_info_.nv12_prefill_lines = std::stoi(string(line, yuv_nv12_prefill_lines.length())); } else if (line.find(linear_prefill_lines) != string::npos) { crtc_info_.linear_prefill_lines = std::stoi(string(line, linear_prefill_lines.length())); } else if (line.find(downscaling_prefill_lines) != string::npos) { crtc_info_.downscale_prefill_lines = std::stoi(string(line, downscaling_prefill_lines.length())); } else if (line.find(xtra_prefill_lines) != string::npos) { crtc_info_.extra_prefill_lines = std::stoi(string(line, xtra_prefill_lines.length())); } else if (line.find(amortizable_threshold) != string::npos) { crtc_info_.amortized_threshold = std::stoi(string(line, amortizable_threshold.length())); } else if (line.find(max_bandwidth_low) != string::npos) { crtc_info_.max_bandwidth_low = std::stoull(string(line, max_bandwidth_low.length())); } else if (line.find(max_bandwidth_high) != string::npos) { crtc_info_.max_bandwidth_high = std::stoull(string(line, max_bandwidth_high.length())); } else if (line.find(max_mdp_clk) != string::npos) { crtc_info_.max_sde_clk = std::stoi(string(line, max_mdp_clk.length())); } else if (line.find(core_clk_ff) != string::npos) { crtc_info_.clk_fudge_factor = std::stof(string(line, core_clk_ff.length())); } else if (line.find(comp_ratio_rt) != string::npos) { ParseCompRatio(line.substr(comp_ratio_rt.length()), true); } else if (line.find(comp_ratio_nrt) != string::npos) { ParseCompRatio(line.substr(comp_ratio_nrt.length()), false); } else if (line.find(hw_version) != string::npos) { crtc_info_.hw_version = std::stoi(string(line, hw_version.length())); } else if (line.find(solidfill_stages) != string::npos) { crtc_info_.max_solidfill_stages = std::stoi(string(line, solidfill_stages.length())); } else if (line.find(dest_scaler_count) != string::npos) { crtc_info_.dest_scaler_count = std::stoi(string(line, dest_scaler_count.length())); } else if (line.find(max_dest_scale_up) != string::npos) { crtc_info_.max_dest_scale_up = std::stoi(string(line, max_dest_scale_up.length())); } else if (line.find(max_dest_scaler_input_width) != string::npos) { crtc_info_.max_dest_scaler_input_width = std::stoi(string(line, max_dest_scaler_input_width.length())); } else if (line.find(max_dest_scaler_output_width) != string::npos) { crtc_info_.max_dest_scaler_output_width = std::stoi(string(line, max_dest_scaler_output_width.length())); } else if (line.find(has_hdr) != string::npos) { crtc_info_.has_hdr = std::stoi(string(line, has_hdr.length())); } else if (line.find(min_prefill_lines) != string::npos) { crtc_info_.min_prefill_lines = std::stoi(string(line, min_prefill_lines.length())); } else if (line.find(sec_ui_blendstage) != string::npos) { crtc_info_.secure_disp_blend_stage = std::stoi(string(line, (sec_ui_blendstage).length())); } else if (line.find(num_mnocports) != string::npos) { crtc_info_.num_mnocports = std::stoi(string(line, num_mnocports.length())); } else if (line.find(mnoc_bus_width) != string::npos) { crtc_info_.mnoc_bus_width = std::stoi(string(line, mnoc_bus_width.length())); } else if (line.find(linewidth_constraints) != string::npos) { crtc_info_.line_width_constraints_count = std::stoi(string(line, (linewidth_constraints).length())); } else if (line.find(vig) != string::npos) { crtc_info_.vig_limit_index = std::stoi(string(line, (vig).length())); } else if (line.find(dma) != string::npos) { crtc_info_.dma_limit_index = std::stoi(string(line, (dma).length())); } else if (line.find(scaling) != string::npos) { crtc_info_.scaling_limit_index = std::stoi(string(line, (scaling).length())); } else if (line.find(rotation) != string::npos) { crtc_info_.rotation_limit_index = std::stoi(string(line, (rotation).length())); } else if (line.find(linewidth_values) != string::npos) { uint32_t num_linewidth_values = std::stoi(string(line, (linewidth_values).length())); vector< pair > constraint_vector; for (uint32_t i = 0; i < num_linewidth_values; i++) { uint32_t constraint = 0; uint32_t value = 0; std::getline(stream, line); if (line.find(limit_constraint) != string::npos) { constraint = std::stoi(string(line, (limit_constraint).length())); } std::getline(stream, line); if (line.find(limit_value) != string::npos) { value = std::stoi(string(line, (limit_value).length())); } if (value) { constraint_vector.push_back(std::make_pair(constraint,value)); } } crtc_info_.line_width_limits = std::move(constraint_vector); } else if (line.find(has_micro_idle) != string::npos) { crtc_info_.has_micro_idle = std::stoi(string(line, (has_micro_idle).length())); } else if (line.find(use_baselayer_for_stage) != string::npos) { crtc_info_.use_baselayer_for_stage = std::stoi(string(line, use_baselayer_for_stage.length())); } else if (line.find(ubwc_version) != string::npos) { crtc_info_.ubwc_version = (std::stoi(string(line, ubwc_version.length()))) >> 28; } } drmModeFreePropertyBlob(blob); delete[] fmt_str; } void DRMCrtc::ParseCompRatio(string line, bool real_time) { CompRatioMap &comp_ratio_map = real_time ? crtc_info_.comp_ratio_rt_map : crtc_info_.comp_ratio_nrt_map; std::vector format_cr_list; Tokenize(line, &format_cr_list, ' '); for (uint32_t i = 0; i < format_cr_list.size(); i++) { std::vector format_cr; Tokenize(format_cr_list.at(i), &format_cr, '/'); std::string format = format_cr.at(0); uint64_t vendor_code = stoi(format_cr.at(1)); uint64_t fmt_modifier = stoi(format_cr.at(2)); float comp_ratio = std::stof(format_cr.at(3)); uint64_t modifier = 0; if (vendor_code == DRM_FORMAT_MOD_VENDOR_QCOM) { // Macro from drm_fourcc.h to form modifier modifier = fourcc_mod_code(QCOM, fmt_modifier); } std::pair drm_format = std::make_pair(fourcc_code(format[0], format[1], format[2], format[3]), modifier); comp_ratio_map.insert(std::make_pair(drm_format, comp_ratio)); } } void DRMCrtc::GetInfo(DRMCrtcInfo *info) { *info = crtc_info_; } void DRMCrtc::Lock() { status_ = DRMStatus::BUSY; } void DRMCrtc::Unlock() { if (mode_blob_id_) { drmModeDestroyPropertyBlob(fd_, mode_blob_id_); mode_blob_id_ = 0; } ClearProperties(); status_ = DRMStatus::FREE; } void DRMCrtc::SetModeBlobID(uint64_t blob_id) { if (mode_blob_id_) { drmModeDestroyPropertyBlob(fd_, mode_blob_id_); } mode_blob_id_ = blob_id; } void DRMCrtc::InitAndParse(drmModeCrtc *crtc) { drm_crtc_ = crtc; ParseProperties(); pp_mgr_ = std::unique_ptr(new DRMPPManager(fd_)); pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_CRTC); } void DRMCrtc::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) { uint32_t obj_id = drm_crtc_->crtc_id; switch (code) { case DRMOps::CRTC_SET_MODE: { drmModeModeInfo *mode = va_arg(args, drmModeModeInfo *); uint32_t blob_id = 0; if (mode) { if (drmModeCreatePropertyBlob(fd_, (const void *)mode, sizeof(drmModeModeInfo), &blob_id)) { DRM_LOGE("drmModeCreatePropertyBlob failed for CRTC_SET_MODE, crtc %d", obj_id); return; } } AddProperty(DRMProperty::MODE_ID, blob_id, true); SetModeBlobID(blob_id); DRM_LOGD("CRTC %d: Set mode %s", obj_id, mode ? mode->name : "null"); } break; case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET: { uint32_t offset = va_arg(args, uint32_t); AddProperty(DRMProperty::OUTPUT_FENCE_OFFSET, offset); }; break; case DRMOps::CRTC_SET_CORE_CLK: { uint32_t core_clk = va_arg(args, uint32_t); AddProperty(DRMProperty::CORE_CLK, core_clk); }; break; case DRMOps::CRTC_SET_CORE_AB: { uint64_t core_ab = va_arg(args, uint64_t); AddProperty(DRMProperty::CORE_AB, core_ab); }; break; case DRMOps::CRTC_SET_CORE_IB: { uint64_t core_ib = va_arg(args, uint64_t); AddProperty(DRMProperty::CORE_IB, core_ib); }; break; case DRMOps::CRTC_SET_LLCC_AB: { uint64_t llcc_ab = va_arg(args, uint64_t); AddProperty(DRMProperty::LLCC_AB, llcc_ab); }; break; case DRMOps::CRTC_SET_LLCC_IB: { uint64_t llcc_ib = va_arg(args, uint64_t); AddProperty(DRMProperty::LLCC_IB, llcc_ib); }; break; case DRMOps::CRTC_SET_DRAM_AB: { uint64_t dram_ab = va_arg(args, uint64_t); AddProperty(DRMProperty::DRAM_AB, dram_ab); }; break; case DRMOps::CRTC_SET_DRAM_IB: { uint64_t dram_ib = va_arg(args, uint64_t); AddProperty(DRMProperty::DRAM_IB, dram_ib); }; break; case DRMOps::CRTC_SET_ROT_PREFILL_BW: { uint64_t rot_bw = va_arg(args, uint64_t); AddProperty(DRMProperty::ROT_PREFILL_BW, rot_bw); }; break; case DRMOps::CRTC_SET_ROT_CLK: { uint32_t rot_clk = va_arg(args, uint32_t); AddProperty(DRMProperty::ROT_CLK, rot_clk); }; break; case DRMOps::CRTC_GET_RELEASE_FENCE: { int64_t *fence = va_arg(args, int64_t *); *fence = -1; AddProperty(DRMProperty::OUTPUT_FENCE, reinterpret_cast(fence), true); } break; case DRMOps::CRTC_SET_ACTIVE: { uint32_t enable = va_arg(args, uint32_t); AddProperty(DRMProperty::ACTIVE, enable); DRM_LOGD("CRTC %d: Set active %d", obj_id, enable); if (enable == 0) { ClearVotesCache(); } } break; case DRMOps::CRTC_SET_POST_PROC: { DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*); if (data) pp_mgr_->SetPPFeature(req, obj_id, *data); DRM_LOGD("CRTC %d: Set post proc", obj_id); } break; case DRMOps::CRTC_SET_ROI: { uint32_t num_roi = va_arg(args, uint32_t); DRMRect *crtc_rois = va_arg(args, DRMRect*); SetROI(num_roi, crtc_rois); } break; case DRMOps::CRTC_SET_SECURITY_LEVEL: { int security_level = va_arg(args, int); uint32_t crtc_security_level = SECURE_NON_SECURE; if (security_level == (int)DRMSecurityLevel::SECURE_ONLY) { crtc_security_level = SECURE_ONLY; } AddProperty(DRMProperty::SECURITY_LEVEL, crtc_security_level); } break; case DRMOps::CRTC_SET_SOLIDFILL_STAGES: { uint64_t dim_stages = va_arg(args, uint64_t); const std::vector *solid_fills = reinterpret_cast *> (dim_stages); SetSolidfillStages(solid_fills); } break; case DRMOps::CRTC_SET_IDLE_TIMEOUT: { uint32_t timeout_ms = va_arg(args, uint32_t); AddProperty(DRMProperty::IDLE_TIME, timeout_ms); } break; case DRMOps::CRTC_SET_DEST_SCALER_CONFIG: { uint64_t dest_scaler = va_arg(args, uint64_t); static sde_drm_dest_scaler_data dest_scale_copy = {}; sde_drm_dest_scaler_data *ds_data = reinterpret_cast (dest_scaler); dest_scale_copy = *ds_data; AddProperty(DRMProperty::DEST_SCALER, reinterpret_cast(&dest_scale_copy), true); } break; case DRMOps::CRTC_SET_CAPTURE_MODE: { int capture_mode = va_arg(args, int); uint32_t cwb_capture_mode = CAPTURE_MIXER_OUT; if (capture_mode == (int)DRMCWbCaptureMode::DSPP_OUT) { cwb_capture_mode = CAPTURE_DSPP_OUT; } AddProperty(DRMProperty::CAPTURE_MODE, cwb_capture_mode); } break; case DRMOps::CRTC_SET_IDLE_PC_STATE: { if (!prop_mgr_.IsPropertyAvailable(DRMProperty::IDLE_PC_STATE)) { return; } int drm_idle_pc_state = va_arg(args, int); uint32_t idle_pc_state = IDLE_PC_STATE_NONE; switch (drm_idle_pc_state) { case static_cast(DRMIdlePCState::ENABLE): idle_pc_state = IDLE_PC_STATE_ENABLE; break; case static_cast(DRMIdlePCState::DISABLE): idle_pc_state = IDLE_PC_STATE_DISABLE; break; default: idle_pc_state = IDLE_PC_STATE_NONE; break; } AddProperty(DRMProperty::IDLE_PC_STATE, idle_pc_state); DRM_LOGD("CRTC %d: Set idle_pc_state %d", obj_id, idle_pc_state); }; break; default: DRM_LOGE("Invalid opcode %d to set the property on crtc %d", code, obj_id); break; } } void DRMCrtc::SetROI(uint32_t num_roi, DRMRect *crtc_rois) { #ifdef SDE_MAX_ROI_V1 if (num_roi > SDE_MAX_ROI_V1 || !prop_mgr_.IsPropertyAvailable(DRMProperty::ROI_V1)) { return; } if (!num_roi || !crtc_rois) { AddProperty(DRMProperty::ROI_V1, 0, true); DRM_LOGD("CRTC ROI is set to NULL to indicate full frame update"); return; } memset(&roi_v1_, 0, sizeof(roi_v1_)); roi_v1_.num_rects = num_roi; for (uint32_t i = 0; i < num_roi; i++) { roi_v1_.roi[i].x1 = crtc_rois[i].left; roi_v1_.roi[i].x2 = crtc_rois[i].right; roi_v1_.roi[i].y1 = crtc_rois[i].top; roi_v1_.roi[i].y2 = crtc_rois[i].bottom; DRM_LOGD("CRTC %d, ROI[l,t,b,r][%d %d %d %d]", GetObjectId(), roi_v1_.roi[i].x1, roi_v1_.roi[i].y1, roi_v1_.roi[i].x2, roi_v1_.roi[i].y2); } AddProperty(DRMProperty::ROI_V1, reinterpret_cast(&roi_v1_), true); #endif } void DRMCrtc::SetSolidfillStages(const std::vector *solid_fills) { #if defined SDE_MAX_DIM_LAYERS memset(&drm_dim_layer_v1_, 0, sizeof(drm_dim_layer_v1_)); uint32_t shift; drm_dim_layer_v1_.num_layers = static_cast (solid_fills->size()); for (uint32_t i = 0; i < solid_fills->size(); i++) { const DRMSolidfillStage &sf = solid_fills->at(i); float plane_alpha = (sf.plane_alpha / 255.0f); drm_dim_layer_v1_.layer_cfg[i].stage = sf.z_order; drm_dim_layer_v1_.layer_cfg[i].rect.x1 = (uint16_t)sf.bounding_rect.left; drm_dim_layer_v1_.layer_cfg[i].rect.y1 = (uint16_t)sf.bounding_rect.top; drm_dim_layer_v1_.layer_cfg[i].rect.x2 = (uint16_t)sf.bounding_rect.right; drm_dim_layer_v1_.layer_cfg[i].rect.y2 = (uint16_t)sf.bounding_rect.bottom; drm_dim_layer_v1_.layer_cfg[i].flags = sf.is_exclusion_rect ? SDE_DRM_DIM_LAYER_EXCLUSIVE : SDE_DRM_DIM_LAYER_INCLUSIVE; // @sde_mdss_color: expects in [g b r a] order where as till now solidfill is in [a r g b]. // As no support for passing plane alpha, Multiply Alpha color component with plane_alpa. shift = kSolidFillHwBitDepth - sf.color_bit_depth; drm_dim_layer_v1_.layer_cfg[i].color_fill.color_0 = (sf.green & 0x3FF) << shift; drm_dim_layer_v1_.layer_cfg[i].color_fill.color_1 = (sf.blue & 0x3FF) << shift; drm_dim_layer_v1_.layer_cfg[i].color_fill.color_2 = (sf.red & 0x3FF) << shift; // alpha is 8 bit drm_dim_layer_v1_.layer_cfg[i].color_fill.color_3 = ((uint32_t)((((sf.alpha & 0xFF)) * plane_alpha))); } AddProperty(DRMProperty::DIM_STAGES_V1, reinterpret_cast (&drm_dim_layer_v1_), true); #endif } void DRMCrtc::Dump() { DRM_LOGE("id: %d\tbuffer_id: %d\tpos:(%d, %d)\tsize:(%dx%d)\n", drm_crtc_->crtc_id, drm_crtc_->buffer_id, drm_crtc_->x, drm_crtc_->y, drm_crtc_->width, drm_crtc_->height); } bool DRMCrtc::ConfigureScalerLUT(uint32_t dir_lut_blob_id, uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) { if (is_lut_configured_ && is_lut_validated_) { return false; } if (dir_lut_blob_id) { AddProperty(DRMProperty::DS_LUT_ED, dir_lut_blob_id, true); } if (cir_lut_blob_id) { AddProperty(DRMProperty::DS_LUT_CIR, cir_lut_blob_id, true); } if (sep_lut_blob_id) { AddProperty(DRMProperty::DS_LUT_SEP, sep_lut_blob_id, true); } is_lut_validation_in_progress_ = true; return true; } void DRMCrtc::PostCommit(bool success) { if (success) { if (is_lut_validated_) { is_lut_configured_ = true; } CommitProperties(); } } void DRMCrtc::PostValidate() { if (is_lut_validation_in_progress_) { is_lut_validated_ = true; } } void DRMCrtc::ClearVotesCache() { RemoveProperty(DRMProperty::CORE_CLK); RemoveProperty(DRMProperty::CORE_AB); RemoveProperty(DRMProperty::CORE_IB); RemoveProperty(DRMProperty::LLCC_AB); RemoveProperty(DRMProperty::LLCC_IB); RemoveProperty(DRMProperty::DRAM_AB); RemoveProperty(DRMProperty::DRAM_IB); } } // namespace sde_drm