/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "hwc-drm-crtc" #include "drmcrtc.h" #include "drmdevice.h" #include "rockchip/utils/drmdebug.h" #include #include #include namespace android { #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) struct plane_mask_name { uint64_t mask; const char *name; }; // RK3588 struct plane_mask_name plane_mask_names_rk3588[] = { { PLANE_RK3588_ALL_CLUSTER0_MASK, "Cluster0" }, { PLANE_RK3588_ALL_CLUSTER1_MASK, "Cluster1" }, { PLANE_RK3588_ALL_CLUSTER2_MASK, "Cluster2" }, { PLANE_RK3588_ALL_CLUSTER3_MASK, "Cluster3" }, { PLANE_RK3588_ALL_ESMART0_MASK, "Esmart0" }, { PLANE_RK3588_ALL_ESMART1_MASK, "Esmart1" }, { PLANE_RK3588_ALL_ESMART2_MASK, "Esmart2" }, { PLANE_RK3588_ALL_ESMART3_MASK, "Esmart3" }, { PLANE_RK3588_Unknown, "unknown" }, }; // RK3528 struct plane_mask_name plane_mask_names_rk3528[] = { { PLANE_RK3528_ALL_CLUSTER0_MASK, "Cluster0" }, { PLANE_RK3528_ALL_ESMART0_MASK, "Esmart0" }, { PLANE_RK3528_ALL_ESMART1_MASK, "Esmart1" }, { PLANE_RK3528_ALL_ESMART2_MASK, "Esmart2" }, { PLANE_RK3528_ALL_ESMART3_MASK, "Esmart3" }, { PLANE_RK3528_Unknown, "unknown" }, }; // RK356x struct plane_mask_name plane_mask_names_rk356x[] = { { DRM_PLANE_TYPE_CLUSTER0_MASK, "Cluster0" }, { DRM_PLANE_TYPE_CLUSTER1_MASK, "Cluster1" }, { DRM_PLANE_TYPE_ESMART0_MASK, "Esmart0" }, { DRM_PLANE_TYPE_ESMART1_MASK, "Esmart1" }, { DRM_PLANE_TYPE_SMART0_MASK, "Smart0" }, { DRM_PLANE_TYPE_SMART1_MASK, "Smart1" }, { DRM_PLANE_TYPE_VOP2_Unknown, "unknown" }, }; // RK3528 struct plane_mask_name plane_mask_names_rk3562[] = { { PLANE_RK3562_ALL_ESMART0_MASK, "Esmart0" }, { PLANE_RK3562_ALL_ESMART1_MASK, "Esmart1" }, { PLANE_RK3562_ALL_ESMART2_MASK, "Esmart2" }, { PLANE_RK3562_ALL_ESMART3_MASK, "Esmart3" }, { PLANE_RK3562_Unknown, "unknown" }, }; // RK3399 struct plane_mask_name plane_mask_names_rk3399[] = { { DRM_PLANE_TYPE_VOP0_MASK, "VOP0-win0" }, { DRM_PLANE_TYPE_VOP0_MASK, "VOP0-win1" }, { DRM_PLANE_TYPE_VOP0_MASK, "VOP0-win2" }, { DRM_PLANE_TYPE_VOP0_MASK, "VOP0-win3" }, { DRM_PLANE_TYPE_VOP1_MASK, "VOP1-win0" }, { DRM_PLANE_TYPE_VOP1_MASK, "VOP1-win1" }, { DRM_PLANE_TYPE_VOP1_Unknown, "unknown" }, }; DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe) : drm_(drm), drm_version_(drm->getDrmVersion()), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) { } int DrmCrtc::Init() { int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_); if (ret) { ALOGE("Failed to get ACTIVE property"); return ret; } ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_); if (ret) { ALOGE("Failed to get MODE_ID property"); return ret; } b_can_overscan_ = true; ret = drm_->GetCrtcProperty(*this, "left margin", &left_margin_property_); if (ret) { ALOGE("Failed to get left margin property"); b_can_overscan_ = false; } ret = drm_->GetCrtcProperty(*this, "right margin", &right_margin_property_); if (ret) { ALOGE("Failed to get right margin property"); b_can_overscan_ = false; } ret = drm_->GetCrtcProperty(*this, "top margin", &top_margin_property_); if (ret) { ALOGE("Failed to get top margin property"); b_can_overscan_ = false; } ret = drm_->GetCrtcProperty(*this, "bottom margin", &bottom_margin_property_); if (ret) { ALOGE("Failed to get bottom margin property"); b_can_overscan_ = false; } ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_); if (ret) { ALOGE("Failed to get OUT_FENCE_PTR property"); } ret = drm_->GetCrtcProperty(*this, "SOC_ID", &soc_type_property_); if (ret) { ALOGE("Failed to get SOC_ID property"); } std::tie(ret, soc_id_) = soc_type_property_.value(); if(ret) ALOGE("Failed to get SOC_ID value"); ret = drm_->GetCrtcProperty(*this, "PORT_ID", &port_id_property_); if (ret) { ALOGE("Failed to get PORT_ID property"); } std::tie(ret, port_id_) = port_id_property_.value(); if(ret) ALOGE("Failed to get PORT_ID value"); ret = drm_->GetCrtcProperty(*this, "ACLK", &aclk_property_); if (ret) { ALOGE("Failed to get ACLK property"); aclk_=0; }else{ std::tie(ret, aclk_) = aclk_property_.value(); if(ret){ ALOGE("Failed to get ACLK value"); } } // Plane mask plane_mask_=0; ret = drm_->GetCrtcProperty(*this, "PLANE_MASK", &plane_mask_property_); if (ret) { ALOGE("Failed to get plane_mask property"); }else{ if(isRK3588(soc_id_)){ for(int i = 0; i < ARRAY_SIZE(plane_mask_names_rk3588); i++){ bool have_mask = false; std::tie(ret,have_mask) = plane_mask_property_.value_bitmask(plane_mask_names_rk3588[i].name); if(have_mask){ plane_mask_ |= plane_mask_names_rk3588[i].mask; } } }else if(isRK356x(soc_id_)){ for(int i = 0; i < ARRAY_SIZE(plane_mask_names_rk356x); i++){ bool have_mask = false; std::tie(ret,have_mask) = plane_mask_property_.value_bitmask(plane_mask_names_rk356x[i].name); if(have_mask){ plane_mask_ |= plane_mask_names_rk356x[i].mask; } } }else if(isRK3399(soc_id_)){ for(int i = 0; i < ARRAY_SIZE(plane_mask_names_rk3399); i++){ bool have_mask = false; std::tie(ret,have_mask) = plane_mask_property_.value_bitmask(plane_mask_names_rk3399[i].name); if(have_mask){ plane_mask_ |= plane_mask_names_rk3399[i].mask; } } }else if(isRK3528(soc_id_)){ for(int i = 0; i < ARRAY_SIZE(plane_mask_names_rk3528); i++){ bool have_mask = false; std::tie(ret,have_mask) = plane_mask_property_.value_bitmask(plane_mask_names_rk3528[i].name); if(have_mask){ plane_mask_ |= plane_mask_names_rk3528[i].mask; } } }else if(isRK3562(soc_id_)){ for(int i = 0; i < ARRAY_SIZE(plane_mask_names_rk3562); i++){ bool have_mask = false; std::tie(ret,have_mask) = plane_mask_property_.value_bitmask(plane_mask_names_rk3562[i].name); if(have_mask){ plane_mask_ |= plane_mask_names_rk3562[i].mask; } } } } // GAMMA LUT ret = drm_->GetCrtcProperty(*this, "GAMMA_LUT", &gamma_lut_property_); if (ret) { ALOGE("Failed to get GAMMA_LUT property"); } ret = drm_->GetCrtcProperty(*this, "GAMMA_LUT_SIZE", &gamma_lut_size_property_); if (ret) { ALOGE("Failed to get GAMMA_LUT_SIZE property"); } // CUBIC LUT ret = drm_->GetCrtcProperty(*this, "CUBIC_LUT", &cubic_lut_property_); if (ret) { ALOGE("Failed to get CUBIC_LUT property"); } ret = drm_->GetCrtcProperty(*this, "CUBIC_LUT_SIZE", &cubic_lut_size_property_); if (ret) { ALOGE("Failed to get CUBIC_LUT_SIZE property"); } // OUTPUT_WIDTH / OUTPUT_DCLK 用来计算VP的输出能力,计算公式为: // 1. 输出分辨率宽度限制: drmModeModeInfo.htotal <= OUTPUT_WIDTH // 2. 输出分辨率高度与刷新率限制: // drmModeModeInfo.htotal * drmModeModeInfo.vtotal * drmModeModeInfo.vrefresh <= OUTPUT_DCLK ret = drm_->GetCrtcProperty(*this, "OUTPUT_WIDTH", &output_width_property_); if (ret) { ALOGE("Failed to get OUTPUT_WIDTH property"); }else{ std::tie(ret, output_width_) = output_width_property_.range_max(); if(ret){ ALOGE("Failed to get OUTPUT_WIDTH value"); } } ret = drm_->GetCrtcProperty(*this, "OUTPUT_DCLK", &output_dclk_property_); if (ret) { ALOGE("Failed to get OUTPUT_DCLK property"); }else{ std::tie(ret, output_dclk_) = output_dclk_property_.range_max(); if(ret){ ALOGE("Failed to get OUTPUT_DCLK value"); } } if(isDrmVerison44(drm_version_)){ // Nothing. }else if(isDrmVerison419(drm_version_)){ // ALPHA_SCALE uint64_t alpha_scale = 0; b_can_alpha_scale_ = true; ret = drm_->GetCrtcProperty(*this, "ALPHA_SCALE", &alpha_scale_property_); if (ret) { ALOGE("Failed to get alpha_scale_property property"); } std::tie(alpha_scale, ret) = alpha_scale_property_.value(); if(alpha_scale == 0) b_can_alpha_scale_ = false; // FEATURE: afbc ret = drm_->GetCrtcProperty(*this, "FEATURE", &feature_property_); if (ret) ALOGE("Could not get FEATURE property"); uint64_t feature=0; b_can_afbc_ = false; feature_property_.set_feature("afbdc"); std::tie(ret,feature) = feature_property_.value(); b_can_afbc_ = (feature ==1)?true:false; // Workround: rk356x if(isRK356x(soc_id_)){ b_can_alpha_scale_ = true; b_can_hdr10_ = false; b_can_next_hdr_ = false; if(port_id_ == 0){ b_can_hdr10_ = true; } } // Workround: rk3528 if(isRK3528(soc_id_)){ b_can_alpha_scale_ = true; b_can_hdr10_ = false; b_can_next_hdr_ = false; if(port_id_ == 0){ b_can_hdr10_ = true; } } }else if(isDrmVerison510(drm_version_) || isDrmVerison6_1(drm_version_) ){ // FEATURE: alpha_scale / HDR10 / Next_HDR ret = drm_->GetCrtcProperty(*this, "FEATURE", &feature_property_); if (ret) ALOGE("Could not get FEATURE property"); b_can_alpha_scale_ = false; b_can_hdr10_ = false; b_can_next_hdr_ = false; std::tie(ret,b_can_alpha_scale_) = feature_property_.value_bitmask("ALPHA_SCALE"); std::tie(ret,b_can_hdr10_) = feature_property_.value_bitmask("HDR10"); std::tie(ret,b_can_next_hdr_) = feature_property_.value_bitmask("NEXT_HDR"); } // Workround: rk3528 if(isRK3528(soc_id_)){ b_can_alpha_scale_ = true; b_can_hdr10_ = false; b_can_next_hdr_ = false; if(port_id_ == 0){ b_can_hdr10_ = true; } } int variable_refresh_rate = 0; int max_refresh_rate = 0; int min_refresh_rate = 0; ret = drm_->GetCrtcProperty(*this, "variable refresh rate", &variable_refresh_rate_); if (ret) ALOGE("Could not get variable_refresh_rate property"); else{ std::tie(ret,variable_refresh_rate) = variable_refresh_rate_.value(); } ret = drm_->GetCrtcProperty(*this, "max refresh rate", &max_refresh_rate_); if (ret) ALOGE("Could not get max_refresh_rate property"); else{ std::tie(ret,max_refresh_rate) = max_refresh_rate_.value(); } ret = drm_->GetCrtcProperty(*this, "min refresh rate", &min_refresh_rate_); if (ret) ALOGE("Could not get min_refresh_rate_ property"); else{ std::tie(ret,min_refresh_rate) = min_refresh_rate_.value(); } HWC2_ALOGI("crtc-id=%d vrr=%d, maxrr=%d minrr=%d",id_, variable_refresh_rate, max_refresh_rate, min_refresh_rate); ret = drm_->GetCrtcProperty(*this, "HDR_EXT_DATA", &hdr_ext_data_); if (ret) ALOGE("Could not get hdr_ext_data_ property"); ret = drm_->GetCrtcProperty(*this, "IS_VIRTUAL", &is_virtual_); if (ret) ALOGE("Could not get IS_VIRTUAL property"); HWC2_ALOGD_IF_DEBUG("crtc-id=%d b_can_alpha_scale_=%d b_can_hdr10_=%d b_can_next_hdr_=%d", id_, b_can_alpha_scale_, b_can_hdr10_, b_can_next_hdr_); return 0; } uint32_t DrmCrtc::id() const { return id_; } unsigned DrmCrtc::pipe() const { return pipe_; } int DrmCrtc::display() const { return display_; } void DrmCrtc::set_display(int display) { display_ = display; } bool DrmCrtc::can_bind(int display) const { return display_ == -1 || display_ == display; } const DrmProperty &DrmCrtc::active_property() const { return active_property_; } const DrmProperty &DrmCrtc::mode_property() const { return mode_property_; } const DrmProperty &DrmCrtc::out_fence_ptr_property() const { return out_fence_ptr_property_; } bool DrmCrtc::can_overscan() const { return b_can_overscan_; } const DrmProperty &DrmCrtc::left_margin_property() const { return left_margin_property_; } const DrmProperty &DrmCrtc::right_margin_property() const { return right_margin_property_; } const DrmProperty &DrmCrtc::top_margin_property() const { return top_margin_property_; } const DrmProperty &DrmCrtc::bottom_margin_property() const { return bottom_margin_property_; } const DrmProperty &DrmCrtc::alpha_scale_property() const { return alpha_scale_property_; } const DrmProperty &DrmCrtc::gamma_lut_property() const{ return gamma_lut_property_; } const DrmProperty &DrmCrtc::gamma_lut_size_property() const{ return gamma_lut_size_property_; } const DrmProperty &DrmCrtc::cubic_lut_property() const{ return cubic_lut_property_; } const DrmProperty &DrmCrtc::cubic_lut_size_property() const{ return cubic_lut_size_property_; } const DrmProperty &DrmCrtc::output_width_property() const{ return output_width_property_; } const DrmProperty &DrmCrtc::output_dclk_property() const{ return output_dclk_property_; } const DrmProperty &DrmCrtc::variable_refresh_rate() const{ return variable_refresh_rate_; } const DrmProperty &DrmCrtc::max_refresh_rate() const{ return max_refresh_rate_; } const DrmProperty &DrmCrtc::min_refresh_rate() const{ return min_refresh_rate_; } const DrmProperty &DrmCrtc::hdr_ext_data() const{ return hdr_ext_data_; } const DrmProperty &DrmCrtc::is_virtual() const{ return is_virtual_; } bool DrmCrtc::get_afbc() const { return b_can_afbc_; } bool DrmCrtc::get_alpha_scale() const { return b_can_alpha_scale_; } bool DrmCrtc::get_hdr() const { return b_can_hdr10_; } bool DrmCrtc::get_next_hdr() const { return b_can_next_hdr_; } const DrmMode &DrmCrtc::kernel_mode() const { return mode_; } } // namespace android