blob: 9736ad0469f6d89168717b7a84584e2f7a7f87ac [file] [log] [blame]
/*
* Copyright (c) 2017, 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.
*/
#define __STDC_FORMAT_MACROS
#include <ctype.h>
#include <drm/drm_fourcc.h>
#include <drm_lib_loader.h>
#include <drm_master.h>
#include <drm_res_mgr.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/fb.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <utils/constants.h>
#include <utils/debug.h>
#include <utils/formats.h>
#include <utils/sys.h>
#include <drm/sde_drm.h>
#include <private/color_params.h>
#include <utils/rect.h>
#include <algorithm>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "hw_device_drm.h"
#include "hw_info_interface.h"
#include "hw_color_manager_drm.h"
#define __CLASS__ "HWDeviceDRM"
#ifndef DRM_FORMAT_MOD_QCOM_COMPRESSED
#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1)
#endif
#ifndef DRM_FORMAT_MOD_QCOM_DX
#define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2)
#endif
#ifndef DRM_FORMAT_MOD_QCOM_TIGHT
#define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4)
#endif
using std::string;
using std::to_string;
using std::fstream;
using std::unordered_map;
using drm_utils::DRMMaster;
using drm_utils::DRMResMgr;
using drm_utils::DRMLibLoader;
using drm_utils::DRMBuffer;
using sde_drm::GetDRMManager;
using sde_drm::DestroyDRMManager;
using sde_drm::DRMDisplayType;
using sde_drm::DRMDisplayToken;
using sde_drm::DRMConnectorInfo;
using sde_drm::DRMPPFeatureInfo;
using sde_drm::DRMRect;
using sde_drm::DRMRotation;
using sde_drm::DRMBlendType;
using sde_drm::DRMSrcConfig;
using sde_drm::DRMOps;
using sde_drm::DRMTopology;
using sde_drm::DRMPowerMode;
using sde_drm::DRMSecureMode;
using sde_drm::DRMSecurityLevel;
namespace sdm {
static void GetDRMFormat(LayerBufferFormat format, uint32_t *drm_format,
uint64_t *drm_format_modifier) {
switch (format) {
case kFormatRGBA8888:
*drm_format = DRM_FORMAT_ABGR8888;
break;
case kFormatRGBA8888Ubwc:
*drm_format = DRM_FORMAT_ABGR8888;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
break;
case kFormatRGBA5551:
*drm_format = DRM_FORMAT_ABGR1555;
break;
case kFormatRGBA4444:
*drm_format = DRM_FORMAT_ABGR4444;
break;
case kFormatBGRA8888:
*drm_format = DRM_FORMAT_ARGB8888;
break;
case kFormatRGBX8888:
*drm_format = DRM_FORMAT_XBGR8888;
break;
case kFormatRGBX8888Ubwc:
*drm_format = DRM_FORMAT_XBGR8888;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
break;
case kFormatBGRX8888:
*drm_format = DRM_FORMAT_XRGB8888;
break;
case kFormatRGB888:
*drm_format = DRM_FORMAT_BGR888;
break;
case kFormatRGB565:
*drm_format = DRM_FORMAT_BGR565;
break;
case kFormatBGR565:
*drm_format = DRM_FORMAT_RGB565;
break;
case kFormatBGR565Ubwc:
*drm_format = DRM_FORMAT_BGR565;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
break;
case kFormatRGBA1010102:
*drm_format = DRM_FORMAT_ABGR2101010;
break;
case kFormatRGBA1010102Ubwc:
*drm_format = DRM_FORMAT_ABGR2101010;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
break;
case kFormatARGB2101010:
*drm_format = DRM_FORMAT_BGRA1010102;
break;
case kFormatRGBX1010102:
*drm_format = DRM_FORMAT_XBGR2101010;
break;
case kFormatRGBX1010102Ubwc:
*drm_format = DRM_FORMAT_XBGR2101010;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
break;
case kFormatXRGB2101010:
*drm_format = DRM_FORMAT_BGRX1010102;
break;
case kFormatBGRA1010102:
*drm_format = DRM_FORMAT_ARGB2101010;
break;
case kFormatABGR2101010:
*drm_format = DRM_FORMAT_RGBA1010102;
break;
case kFormatBGRX1010102:
*drm_format = DRM_FORMAT_XRGB2101010;
break;
case kFormatXBGR2101010:
*drm_format = DRM_FORMAT_RGBX1010102;
break;
case kFormatYCbCr420SemiPlanar:
*drm_format = DRM_FORMAT_NV12;
break;
case kFormatYCbCr420SemiPlanarVenus:
*drm_format = DRM_FORMAT_NV12;
break;
case kFormatYCbCr420SPVenusUbwc:
*drm_format = DRM_FORMAT_NV12;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
break;
case kFormatYCrCb420SemiPlanar:
*drm_format = DRM_FORMAT_NV21;
break;
case kFormatYCrCb420SemiPlanarVenus:
*drm_format = DRM_FORMAT_NV21;
break;
case kFormatYCbCr420P010:
*drm_format = DRM_FORMAT_NV12;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_DX;
break;
case kFormatYCbCr420P010Ubwc:
*drm_format = DRM_FORMAT_NV12;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED |
DRM_FORMAT_MOD_QCOM_DX;
break;
case kFormatYCbCr420TP10Ubwc:
*drm_format = DRM_FORMAT_NV12;
*drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED |
DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT;
break;
case kFormatYCbCr422H2V1SemiPlanar:
*drm_format = DRM_FORMAT_NV16;
break;
case kFormatYCrCb422H2V1SemiPlanar:
*drm_format = DRM_FORMAT_NV61;
break;
case kFormatYCrCb420PlanarStride16:
*drm_format = DRM_FORMAT_YVU420;
break;
default:
DLOGW("Unsupported format %s", GetFormatString(format));
}
}
HWDeviceDRM::Registry::Registry(BufferAllocator *buffer_allocator) :
buffer_allocator_(buffer_allocator) {
DRMMaster *master = nullptr;
DRMMaster::GetInstance(&master);
if (!master) {
DLOGE("Failed to acquire DRM Master instance");
return;
}
// If RMFB is ref-counted, we should immediately make a call to clean up fb_id after commit.
// Driver will release fb_id after its usage. Otherwise speculatively free up fb_id after 3
// cycles assuming driver is done with it.
rmfb_delay_ = master->IsRmFbRefCounted() ? 1 : 3;
hashmap_ = new std::unordered_map<int, uint32_t>[rmfb_delay_];
}
HWDeviceDRM::Registry::~Registry() {
delete [] hashmap_;
}
void HWDeviceDRM::Registry::RegisterCurrent(HWLayers *hw_layers) {
HWLayersInfo &hw_layer_info = hw_layers->info;
uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size());
for (uint32_t i = 0; i < hw_layer_count; i++) {
Layer &layer = hw_layer_info.hw_layers.at(i);
LayerBuffer *input_buffer = &layer.input_buffer;
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[0];
if (hw_rotator_session->mode == kRotatorOffline && hw_rotate_info->valid) {
input_buffer = &hw_rotator_session->output_buffer;
}
MapBufferToFbId(input_buffer);
}
}
void HWDeviceDRM::Registry::MapBufferToFbId(LayerBuffer* buffer) {
int fd = buffer->planes[0].fd;
DRMMaster *master = nullptr;
DRMMaster::GetInstance(&master);
if (!master) {
DLOGE("Failed to acquire DRM Master instance");
return;
}
if (fd >= 0 && hashmap_[current_index_].find(fd) == hashmap_[current_index_].end()) {
AllocatedBufferInfo buf_info{};
DRMBuffer layout{};
buf_info.fd = layout.fd = fd;
buf_info.aligned_width = layout.width = buffer->width;
buf_info.aligned_height = layout.height = buffer->height;
buf_info.format = buffer->format;
GetDRMFormat(buf_info.format, &layout.drm_format, &layout.drm_format_modifier);
buffer_allocator_->GetBufferLayout(buf_info, layout.stride, layout.offset,
&layout.num_planes);
uint32_t fb_id = 0;
int ret = master->CreateFbId(layout, &fb_id);
if (ret < 0) {
DLOGE("CreateFbId failed. width %d, height %d, format: %s, stride %u, error %d",
layout.width, layout.height, GetFormatString(buf_info.format), layout.stride[0],
errno);
} else {
hashmap_[current_index_][fd] = fb_id;
}
}
return;
}
void HWDeviceDRM::Registry::UnregisterNext() {
DRMMaster *master = nullptr;
DRMMaster::GetInstance(&master);
if (!master) {
DLOGE("Failed to acquire DRM Master instance");
return;
}
current_index_ = (current_index_ + 1) % rmfb_delay_;
auto &curr_map = hashmap_[current_index_];
for (auto &pair : curr_map) {
uint32_t fb_id = pair.second;
int ret = master->RemoveFbId(fb_id);
if (ret < 0) {
DLOGE("Removing fb_id %d failed with error %d", fb_id, errno);
}
}
curr_map.clear();
}
void HWDeviceDRM::Registry::Clear() {
for (int i = 0; i < rmfb_delay_; i++) {
UnregisterNext();
}
current_index_ = 0;
}
uint32_t HWDeviceDRM::Registry::GetFbId(int fd) {
auto it = hashmap_[current_index_].find(fd);
return (it == hashmap_[current_index_].end()) ? 0 : it->second;
}
HWDeviceDRM::HWDeviceDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
HWInfoInterface *hw_info_intf)
: hw_info_intf_(hw_info_intf), buffer_sync_handler_(buffer_sync_handler),
registry_(buffer_allocator) {
device_type_ = kDevicePrimary;
disp_type_ = DRMDisplayType::PERIPHERAL;
device_name_ = "Peripheral Display";
hw_info_intf_ = hw_info_intf;
}
DisplayError HWDeviceDRM::Init() {
default_mode_ = (DRMLibLoader::GetInstance()->IsLoaded() == false);
if (!default_mode_) {
DRMMaster *drm_master = {};
DRMMaster::GetInstance(&drm_master);
drm_master->GetHandle(&dev_fd_);
DRMLibLoader::GetInstance()->FuncGetDRMManager()(dev_fd_, &drm_mgr_intf_);
if (drm_mgr_intf_->RegisterDisplay(disp_type_, &token_)) {
DLOGE("RegisterDisplay failed for display %d", disp_type_);
return kErrorResources;
}
drm_mgr_intf_->CreateAtomicReq(token_, &drm_atomic_intf_);
drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
InitializeConfigs();
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode_);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
// Commit to setup pipeline with mode, which then tells us the topology etc
if (!deferred_initialize_) {
if (drm_atomic_intf_->Commit(true /* synchronous */)) {
DRM_LOGI("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id,
token_.conn_id, device_name_);
return kErrorResources;
}
// Reload connector info for updated info after 1st commit
drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
}
}
PopulateDisplayAttributes();
PopulateHWPanelInfo();
UpdateMixerAttributes();
hw_info_intf_->GetHWResourceInfo(&hw_resource_);
// TODO(user): In future, remove has_qseed3 member, add version and pass version to constructor
if (hw_resource_.has_qseed3) {
hw_scale_ = new HWScaleDRM(HWScaleDRM::Version::V2);
}
return kErrorNone;
}
DisplayError HWDeviceDRM::Deinit() {
PowerOff();
delete hw_scale_;
registry_.Clear();
drm_mgr_intf_->DestroyAtomicReq(drm_atomic_intf_);
drm_atomic_intf_ = {};
drm_mgr_intf_->UnregisterDisplay(token_);
return kErrorNone;
}
void HWDeviceDRM::InitializeConfigs() {
// TODO(user): Update modes
current_mode_ = connector_info_.modes[0];
}
DisplayError HWDeviceDRM::PopulateDisplayAttributes() {
drmModeModeInfo mode = {};
uint32_t mm_width = 0;
uint32_t mm_height = 0;
DRMTopology topology = DRMTopology::SINGLE_LM;
if (default_mode_) {
DRMResMgr *res_mgr = nullptr;
int ret = DRMResMgr::GetInstance(&res_mgr);
if (ret < 0) {
DLOGE("Failed to acquire DRMResMgr instance");
return kErrorResources;
}
res_mgr->GetMode(&mode);
res_mgr->GetDisplayDimInMM(&mm_width, &mm_height);
} else {
mode = current_mode_;
mm_width = connector_info_.mmWidth;
mm_height = connector_info_.mmHeight;
topology = connector_info_.topology;
}
display_attributes_.x_pixels = mode.hdisplay;
display_attributes_.y_pixels = mode.vdisplay;
display_attributes_.fps = mode.vrefresh;
display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps);
/*
Active Front Sync Back
Region Porch Porch
<-----------------------><----------------><-------------><-------------->
<----- [hv]display ----->
<------------- [hv]sync_start ------------>
<--------------------- [hv]sync_end --------------------->
<-------------------------------- [hv]total ----------------------------->
*/
display_attributes_.v_front_porch = mode.vsync_start - mode.vdisplay;
display_attributes_.v_pulse_width = mode.vsync_end - mode.vsync_start;
display_attributes_.v_back_porch = mode.vtotal - mode.vsync_end;
display_attributes_.v_total = mode.vtotal;
display_attributes_.h_total = mode.htotal;
uint32_t h_blanking = mode.htotal - mode.hdisplay;
display_attributes_.is_device_split =
(topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_MERGE ||
topology == DRMTopology::DUAL_LM_MERGE_DSC || topology == DRMTopology::DUAL_LM_DSC ||
topology == DRMTopology::DUAL_LM_DSCMERGE);
display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
display_attributes_.x_dpi = (FLOAT(mode.hdisplay) * 25.4f) / FLOAT(mm_width);
display_attributes_.y_dpi = (FLOAT(mode.vdisplay) * 25.4f) / FLOAT(mm_height);
return kErrorNone;
}
void HWDeviceDRM::PopulateHWPanelInfo() {
hw_panel_info_ = {};
snprintf(hw_panel_info_.panel_name, sizeof(hw_panel_info_.panel_name), "%s",
connector_info_.panel_name.c_str());
hw_panel_info_.split_info.left_split = display_attributes_.x_pixels;
if (display_attributes_.is_device_split) {
hw_panel_info_.split_info.left_split = hw_panel_info_.split_info.right_split =
display_attributes_.x_pixels / 2;
}
hw_panel_info_.partial_update = connector_info_.num_roi;
hw_panel_info_.left_roi_count = UINT32(connector_info_.num_roi);
hw_panel_info_.right_roi_count = UINT32(connector_info_.num_roi);
hw_panel_info_.left_align = connector_info_.xstart;
hw_panel_info_.top_align = connector_info_.ystart;
hw_panel_info_.width_align = connector_info_.walign;
hw_panel_info_.height_align = connector_info_.halign;
hw_panel_info_.min_roi_width = connector_info_.wmin;
hw_panel_info_.min_roi_height = connector_info_.hmin;
hw_panel_info_.needs_roi_merge = connector_info_.roi_merge;
hw_panel_info_.dynamic_fps = connector_info_.dynamic_fps;
hw_panel_info_.min_fps = 60;
hw_panel_info_.max_fps = 60;
hw_panel_info_.is_primary_panel = connector_info_.is_primary;
hw_panel_info_.is_pluggable = 0;
hw_panel_info_.hdr_enabled = connector_info_.panel_hdr_prop.hdr_enabled;
hw_panel_info_.peak_luminance = connector_info_.panel_hdr_prop.peak_brightness;
hw_panel_info_.blackness_level = connector_info_.panel_hdr_prop.blackness_level;
hw_panel_info_.primaries.white_point[0] = connector_info_.panel_hdr_prop.display_primaries[0];
hw_panel_info_.primaries.white_point[1] = connector_info_.panel_hdr_prop.display_primaries[1];
hw_panel_info_.primaries.red[0] = connector_info_.panel_hdr_prop.display_primaries[2];
hw_panel_info_.primaries.red[1] = connector_info_.panel_hdr_prop.display_primaries[3];
hw_panel_info_.primaries.green[0] = connector_info_.panel_hdr_prop.display_primaries[4];
hw_panel_info_.primaries.green[1] = connector_info_.panel_hdr_prop.display_primaries[5];
hw_panel_info_.primaries.blue[0] = connector_info_.panel_hdr_prop.display_primaries[6];
hw_panel_info_.primaries.blue[1] = connector_info_.panel_hdr_prop.display_primaries[7];
// no supprt for 90 rotation only flips or 180 supported
hw_panel_info_.panel_orientation.rotation = 0;
hw_panel_info_.panel_orientation.flip_horizontal =
(connector_info_.panel_orientation == DRMRotation::FLIP_H) ||
(connector_info_.panel_orientation == DRMRotation::ROT_180);
hw_panel_info_.panel_orientation.flip_vertical =
(connector_info_.panel_orientation == DRMRotation::FLIP_V) ||
(connector_info_.panel_orientation == DRMRotation::ROT_180);
GetHWDisplayPortAndMode();
GetHWPanelMaxBrightness();
DLOGI("%s, Panel Interface = %s, Panel Mode = %s, Is Primary = %d", device_name_,
interface_str_.c_str(), hw_panel_info_.mode == kModeVideo ? "Video" : "Command",
hw_panel_info_.is_primary_panel);
DLOGI("Partial Update = %d, Dynamic FPS = %d, HDR Panel = %d", hw_panel_info_.partial_update,
hw_panel_info_.dynamic_fps, hw_panel_info_.hdr_enabled);
DLOGI("Align: left = %d, width = %d, top = %d, height = %d", hw_panel_info_.left_align,
hw_panel_info_.width_align, hw_panel_info_.top_align, hw_panel_info_.height_align);
DLOGI("ROI: min_width = %d, min_height = %d, need_merge = %d", hw_panel_info_.min_roi_width,
hw_panel_info_.min_roi_height, hw_panel_info_.needs_roi_merge);
DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split,
hw_panel_info_.split_info.right_split);
}
void HWDeviceDRM::GetHWDisplayPortAndMode() {
hw_panel_info_.port = kPortDefault;
hw_panel_info_.mode =
(connector_info_.panel_mode == sde_drm::DRMPanelMode::VIDEO) ? kModeVideo : kModeCommand;
if (default_mode_) {
return;
}
switch (connector_info_.type) {
case DRM_MODE_CONNECTOR_DSI:
hw_panel_info_.port = kPortDSI;
interface_str_ = "DSI";
break;
case DRM_MODE_CONNECTOR_LVDS:
hw_panel_info_.port = kPortLVDS;
interface_str_ = "LVDS";
break;
case DRM_MODE_CONNECTOR_eDP:
hw_panel_info_.port = kPortEDP;
interface_str_ = "EDP";
break;
case DRM_MODE_CONNECTOR_TV:
case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_HDMIB:
hw_panel_info_.port = kPortDTV;
interface_str_ = "HDMI";
break;
case DRM_MODE_CONNECTOR_VIRTUAL:
hw_panel_info_.port = kPortWriteBack;
interface_str_ = "Virtual";
break;
case DRM_MODE_CONNECTOR_DisplayPort:
// TODO(user): Add when available
interface_str_ = "DisplayPort";
break;
}
return;
}
void HWDeviceDRM::GetHWPanelMaxBrightness() {
char brightness[kMaxStringLength] = {0};
string kMaxBrightnessNode = "/sys/class/backlight/panel0-backlight/max_brightness";
hw_panel_info_.panel_max_brightness = 255;
int fd = Sys::open_(kMaxBrightnessNode.c_str(), O_RDONLY);
if (fd < 0) {
DLOGW("Failed to open max brightness node = %s, error = %s", kMaxBrightnessNode.c_str(),
strerror(errno));
return;
}
if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
hw_panel_info_.panel_max_brightness = atoi(brightness);
DLOGI("Max brightness level = %d", hw_panel_info_.panel_max_brightness);
} else {
DLOGW("Failed to read max brightness level. error = %s", strerror(errno));
}
Sys::close_(fd);
}
DisplayError HWDeviceDRM::GetActiveConfig(uint32_t *active_config) {
*active_config = 0;
return kErrorNone;
}
DisplayError HWDeviceDRM::GetNumDisplayAttributes(uint32_t *count) {
*count = 1;
return kErrorNone;
}
DisplayError HWDeviceDRM::GetDisplayAttributes(uint32_t index,
HWDisplayAttributes *display_attributes) {
*display_attributes = display_attributes_;
return kErrorNone;
}
DisplayError HWDeviceDRM::GetHWPanelInfo(HWPanelInfo *panel_info) {
*panel_info = hw_panel_info_;
return kErrorNone;
}
DisplayError HWDeviceDRM::SetDisplayAttributes(uint32_t index) {
return kErrorNone;
}
DisplayError HWDeviceDRM::SetDisplayAttributes(const HWDisplayAttributes &display_attributes) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::GetConfigIndex(char *mode, uint32_t *index) {
return kErrorNone;
}
DisplayError HWDeviceDRM::PowerOn() {
DTRACE_SCOPED();
if (!drm_atomic_intf_) {
DLOGE("DRM Atomic Interface is null!");
return kErrorUndefined;
}
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
int ret = drm_atomic_intf_->Commit(false /* synchronous */);
if (ret) {
DLOGE("%s failed with error %d", __FUNCTION__, ret);
return kErrorHardware;
}
return kErrorNone;
}
DisplayError HWDeviceDRM::PowerOff() {
if (!drm_atomic_intf_) {
DLOGE("DRM Atomic Interface is null!");
return kErrorUndefined;
}
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::OFF);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
int ret = drm_atomic_intf_->Commit(false /* synchronous */);
if (ret) {
DLOGE("%s failed with error %d", __FUNCTION__, ret);
return kErrorHardware;
}
return kErrorNone;
}
DisplayError HWDeviceDRM::Doze() {
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::DOZE);
return kErrorNone;
}
DisplayError HWDeviceDRM::DozeSuspend() {
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id,
DRMPowerMode::DOZE_SUSPEND);
return kErrorNone;
}
DisplayError HWDeviceDRM::Standby() {
return kErrorNone;
}
void HWDeviceDRM::SetupAtomic(HWLayers *hw_layers, bool validate) {
if (default_mode_) {
return;
}
HWLayersInfo &hw_layer_info = hw_layers->info;
uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size());
HWQosData &qos_data = hw_layers->qos_data;
DRMSecurityLevel crtc_security_level = DRMSecurityLevel::SECURE_NON_SECURE;
solid_fills_.clear();
// TODO(user): Once destination scalar is enabled we can always send ROIs if driver allows
if (hw_panel_info_.partial_update) {
const int kNumMaxROIs = 4;
DRMRect crtc_rects[kNumMaxROIs] = {{0, 0, mixer_attributes_.width, mixer_attributes_.height}};
DRMRect conn_rects[kNumMaxROIs] = {{0, 0, display_attributes_.x_pixels,
display_attributes_.y_pixels}};
for (uint32_t i = 0; i < hw_layer_info.left_frame_roi.size(); i++) {
auto &roi = hw_layer_info.left_frame_roi.at(i);
// TODO(user): In multi PU, stitch ROIs vertically adjacent and upate plane destination
crtc_rects[i].left = UINT32(roi.left);
crtc_rects[i].right = UINT32(roi.right);
crtc_rects[i].top = UINT32(roi.top);
crtc_rects[i].bottom = UINT32(roi.bottom);
// TODO(user): In Dest scaler + PU, populate from HWDestScaleInfo->panel_roi
conn_rects[i].left = UINT32(roi.left);
conn_rects[i].right = UINT32(roi.right);
conn_rects[i].top = UINT32(roi.top);
conn_rects[i].bottom = UINT32(roi.bottom);
}
uint32_t num_rects = std::max(1u, static_cast<uint32_t>(hw_layer_info.left_frame_roi.size()));
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ROI, token_.crtc_id,
num_rects, crtc_rects);
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_ROI, token_.conn_id,
num_rects, conn_rects);
}
for (uint32_t i = 0; i < hw_layer_count; i++) {
Layer &layer = hw_layer_info.hw_layers.at(i);
LayerBuffer *input_buffer = &layer.input_buffer;
HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
if (hw_layers->config[i].use_solidfill_stage) {
AddSolidfillStage(hw_layers->config[i].hw_solidfill_stage, layer.plane_alpha);
continue;
}
for (uint32_t count = 0; count < 2; count++) {
HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe;
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
if (hw_rotator_session->mode == kRotatorOffline && hw_rotate_info->valid) {
input_buffer = &hw_rotator_session->output_buffer;
}
uint32_t fb_id = registry_.GetFbId(input_buffer->planes[0].fd);
if (pipe_info->valid && fb_id) {
uint32_t pipe_id = pipe_info->pipe_id;
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ALPHA, pipe_id, layer.plane_alpha);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ZORDER, pipe_id, pipe_info->z_order);
DRMBlendType blending = {};
SetBlending(layer.blending, &blending);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_BLEND_TYPE, pipe_id, blending);
DRMRect src = {};
SetRect(pipe_info->src_roi, &src);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SRC_RECT, pipe_id, src);
DRMRect rot_dst = {0, 0, 0, 0};
if (hw_rotator_session->mode == kRotatorInline && hw_rotate_info->valid) {
SetRect(hw_rotate_info->dst_roi, &rot_dst);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION_DST_RECT, pipe_id, rot_dst);
}
DRMRect dst = {};
SetRect(pipe_info->dst_roi, &dst);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_DST_RECT, pipe_id, dst);
uint32_t rot_bit_mask = 0;
SetRotation(layer.transform, hw_rotator_session->mode, &rot_bit_mask);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION, pipe_id, rot_bit_mask);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_H_DECIMATION, pipe_id,
pipe_info->horizontal_decimation);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_V_DECIMATION, pipe_id,
pipe_info->vertical_decimation);
DRMSecureMode fb_secure_mode;
DRMSecurityLevel security_level;
SetSecureConfig(layer.input_buffer, &fb_secure_mode, &security_level);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_FB_SECURE_MODE, pipe_id, fb_secure_mode);
if (security_level > crtc_security_level) {
crtc_security_level = security_level;
}
uint32_t config = 0;
SetSrcConfig(layer.input_buffer, &config);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SRC_CONFIG, pipe_id, config);;
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_FB_ID, pipe_id, fb_id);
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_CRTC, pipe_id, token_.crtc_id);
if (!validate && input_buffer->acquire_fence_fd >= 0) {
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_INPUT_FENCE, pipe_id,
input_buffer->acquire_fence_fd);
}
if (hw_scale_) {
SDEScaler scaler_output = {};
hw_scale_->SetPlaneScaler(pipe_info->scale_data, &scaler_output);
// TODO(user): Remove qseed3 and add version check, then send appropriate scaler object
if (hw_resource_.has_qseed3) {
drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SCALER_CONFIG, pipe_id,
reinterpret_cast<uint64_t>(&scaler_output.scaler_v2));
}
}
}
}
}
SetSolidfillStages();
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_CLK, token_.crtc_id, qos_data.clock_hz);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_AB, token_.crtc_id, qos_data.core_ab_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_IB, token_.crtc_id, qos_data.core_ib_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_LLCC_AB, token_.crtc_id, qos_data.llcc_ab_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_LLCC_IB, token_.crtc_id, qos_data.llcc_ib_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DRAM_AB, token_.crtc_id, qos_data.dram_ab_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DRAM_IB, token_.crtc_id, qos_data.dram_ib_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ROT_CLK, token_.crtc_id, qos_data.rot_clock_hz);
DLOGI_IF(kTagDriverConfig, "System Clock=%d Hz, Core: AB=%llu Bps, IB=%llu Bps, " \
"LLCC: AB=%llu Bps, IB=%llu Bps, DRAM AB=%llu Bps, IB=%llu Bps Rot Clock=%d",
qos_data.clock_hz, qos_data.core_ab_bps, qos_data.core_ib_bps, qos_data.llcc_ab_bps,
qos_data.llcc_ib_bps, qos_data.dram_ab_bps, qos_data.dram_ib_bps,
qos_data.rot_clock_hz);
}
void HWDeviceDRM::AddSolidfillStage(const HWSolidfillStage &sf, uint32_t plane_alpha) {
sde_drm::DRMSolidfillStage solidfill;
solidfill.bounding_rect.left = UINT32(sf.roi.left);
solidfill.bounding_rect.top = UINT32(sf.roi.top);
solidfill.bounding_rect.right = UINT32(sf.roi.right);
solidfill.bounding_rect.bottom = UINT32(sf.roi.bottom);
solidfill.is_exclusion_rect = sf.is_exclusion_rect;
solidfill.plane_alpha = plane_alpha;
solidfill.z_order = sf.z_order;
solidfill.color = sf.color;
solid_fills_.push_back(solidfill);
DLOGI_IF(kTagDriverConfig, "Add a solidfill stage at z_order:%d argb_color:%x plane_alpha:%x",
solidfill.z_order, solidfill.color, solidfill.plane_alpha);
}
void HWDeviceDRM::SetSolidfillStages() {
if (hw_resource_.num_solidfill_stages) {
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_SOLIDFILL_STAGES, token_.crtc_id,
reinterpret_cast<uint64_t> (&solid_fills_));
}
}
DisplayError HWDeviceDRM::Validate(HWLayers *hw_layers) {
DTRACE_SCOPED();
registry_.RegisterCurrent(hw_layers);
SetupAtomic(hw_layers, true /* validate */);
int ret = drm_atomic_intf_->Validate();
if (ret) {
DLOGE("%s failed with error %d", __FUNCTION__, ret);
return kErrorHardware;
}
return kErrorNone;
}
DisplayError HWDeviceDRM::Commit(HWLayers *hw_layers) {
DTRACE_SCOPED();
DisplayError err = kErrorNone;
registry_.RegisterCurrent(hw_layers);
if (default_mode_) {
err = DefaultCommit(hw_layers);
} else {
err = AtomicCommit(hw_layers);
}
registry_.UnregisterNext();
return err;
}
DisplayError HWDeviceDRM::DefaultCommit(HWLayers *hw_layers) {
DTRACE_SCOPED();
HWLayersInfo &hw_layer_info = hw_layers->info;
LayerStack *stack = hw_layer_info.stack;
stack->retire_fence_fd = -1;
for (Layer &layer : hw_layer_info.hw_layers) {
layer.input_buffer.release_fence_fd = -1;
}
DRMMaster *master = nullptr;
int ret = DRMMaster::GetInstance(&master);
if (ret < 0) {
DLOGE("Failed to acquire DRMMaster instance");
return kErrorResources;
}
DRMResMgr *res_mgr = nullptr;
ret = DRMResMgr::GetInstance(&res_mgr);
if (ret < 0) {
DLOGE("Failed to acquire DRMResMgr instance");
return kErrorResources;
}
int dev_fd = -1;
master->GetHandle(&dev_fd);
uint32_t connector_id = 0;
res_mgr->GetConnectorId(&connector_id);
uint32_t crtc_id = 0;
res_mgr->GetCrtcId(&crtc_id);
drmModeModeInfo mode;
res_mgr->GetMode(&mode);
uint32_t fb_id = registry_.GetFbId(hw_layer_info.hw_layers.at(0).input_buffer.planes[0].fd);
ret = drmModeSetCrtc(dev_fd, crtc_id, fb_id, 0 /* x */, 0 /* y */, &connector_id,
1 /* num_connectors */, &mode);
if (ret < 0) {
DLOGE("drmModeSetCrtc failed dev fd %d, fb_id %d, crtc id %d, connector id %d, %s", dev_fd,
fb_id, crtc_id, connector_id, strerror(errno));
return kErrorHardware;
}
return kErrorNone;
}
DisplayError HWDeviceDRM::AtomicCommit(HWLayers *hw_layers) {
DTRACE_SCOPED();
SetupAtomic(hw_layers, false /* validate */);
int ret = drm_atomic_intf_->Commit(false /* synchronous */);
if (ret) {
DLOGE("%s failed with error %d crtc %d", __FUNCTION__, ret, token_.crtc_id);
return kErrorHardware;
}
int release_fence = -1;
int retire_fence = -1;
drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence);
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_GET_RETIRE_FENCE, token_.conn_id, &retire_fence);
HWLayersInfo &hw_layer_info = hw_layers->info;
LayerStack *stack = hw_layer_info.stack;
stack->retire_fence_fd = retire_fence;
for (uint32_t i = 0; i < hw_layer_info.hw_layers.size(); i++) {
Layer &layer = hw_layer_info.hw_layers.at(i);
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
if (hw_rotator_session->mode == kRotatorOffline) {
hw_rotator_session->output_buffer.release_fence_fd = Sys::dup_(release_fence);
} else {
layer.input_buffer.release_fence_fd = Sys::dup_(release_fence);
}
}
hw_layer_info.sync_handle = release_fence;
return kErrorNone;
}
DisplayError HWDeviceDRM::Flush() {
return kErrorNone;
}
void HWDeviceDRM::SetBlending(const LayerBlending &source, DRMBlendType *target) {
switch (source) {
case kBlendingPremultiplied:
*target = DRMBlendType::PREMULTIPLIED;
break;
case kBlendingOpaque:
*target = DRMBlendType::OPAQUE;
break;
case kBlendingCoverage:
*target = DRMBlendType::COVERAGE;
break;
default:
*target = DRMBlendType::UNDEFINED;
}
}
void HWDeviceDRM::SetSrcConfig(const LayerBuffer &input_buffer, uint32_t *config) {
if (input_buffer.flags.interlace) {
*config |= (0x01 << UINT32(DRMSrcConfig::DEINTERLACE));
}
}
void HWDeviceDRM::SetRect(const LayerRect &source, DRMRect *target) {
target->left = UINT32(source.left);
target->top = UINT32(source.top);
target->right = UINT32(source.right);
target->bottom = UINT32(source.bottom);
}
void HWDeviceDRM::SetRotation(LayerTransform transform, const HWRotatorMode &mode,
uint32_t* rot_bit_mask) {
// In offline rotation case, rotator will handle flips set via offline rotator interface.
if (mode == kRotatorOffline) {
*rot_bit_mask = 0;
return;
}
// In no rotation case or inline rotation case, plane will handle flips
// In DRM framework rotation is applied in counter-clockwise direction.
if (transform.rotation == 90) {
// a) rotate 90 clockwise = rotate 270 counter-clockwise in DRM
// rotate 270 is translated as hflip + vflip + rotate90
// b) rotate 270 clockwise = rotate 90 counter-clockwise in DRM
// c) hflip + rotate 90 clockwise = vflip + rotate 90 counter-clockwise in DRM
// d) vflip + rotate 90 clockwise = hflip + rotate 90 counter-clockwise in DRM
*rot_bit_mask = UINT32(DRMRotation::ROT_90);
transform.flip_horizontal = !transform.flip_horizontal;
transform.flip_vertical = !transform.flip_vertical;
}
if (transform.flip_horizontal) {
*rot_bit_mask |= UINT32(DRMRotation::FLIP_H);
}
if (transform.flip_vertical) {
*rot_bit_mask |= UINT32(DRMRotation::FLIP_V);
}
}
bool HWDeviceDRM::EnableHotPlugDetection(int enable) {
return true;
}
void HWDeviceDRM::ResetDisplayParams() {}
DisplayError HWDeviceDRM::SetCursorPosition(HWLayers *hw_layers, int x, int y) {
DTRACE_SCOPED();
return kErrorNone;
}
DisplayError HWDeviceDRM::GetPPFeaturesVersion(PPFeatureVersion *vers) {
struct DRMPPFeatureInfo info = {};
for (uint32_t i = 0; i < kMaxNumPPFeatures; i++) {
memset(&info, 0, sizeof(struct DRMPPFeatureInfo));
info.id = HWColorManagerDrm::ToDrmFeatureId(i);
if (info.id >= sde_drm::kPPFeaturesMax)
continue;
// use crtc_id_ = 0 since PP features are same across all CRTCs
drm_mgr_intf_->GetCrtcPPInfo(0, info);
vers->version[i] = HWColorManagerDrm::GetFeatureVersion(info);
}
return kErrorNone;
}
DisplayError HWDeviceDRM::SetPPFeatures(PPFeaturesConfig *feature_list) {
int ret = 0;
PPFeatureInfo *feature = NULL;
while (true) {
DRMPPFeatureInfo kernel_params = {};
ret = feature_list->RetrieveNextFeature(&feature);
if (ret)
break;
if (feature) {
DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_);
if (!HWColorManagerDrm::GetDrmFeature[feature->feature_id_]) {
DLOGE("GetDrmFeature is not valid for feature %d", feature->feature_id_);
continue;
}
ret = HWColorManagerDrm::GetDrmFeature[feature->feature_id_](*feature, &kernel_params);
if (!ret)
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_POST_PROC, token_.crtc_id, &kernel_params);
HWColorManagerDrm::FreeDrmFeatureData(&kernel_params);
}
}
// Once all features were consumed, then destroy all feature instance from feature_list,
feature_list->Reset();
return kErrorNone;
}
DisplayError HWDeviceDRM::SetVSyncState(bool enable) {
return kErrorNotSupported;
}
void HWDeviceDRM::SetIdleTimeoutMs(uint32_t timeout_ms) {}
DisplayError HWDeviceDRM::SetDisplayMode(const HWDisplayMode hw_display_mode) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::SetRefreshRate(uint32_t refresh_rate) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::SetPanelBrightness(int level) {
DisplayError err = kErrorNone;
char buffer[kMaxSysfsCommandLength] = {0};
DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level);
int fd = Sys::open_(kBrightnessNode, O_RDWR);
if (fd < 0) {
DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode,
strerror(errno));
return kErrorFileDescriptor;
}
int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level);
ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
if (ret <= 0) {
DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode,
strerror(errno));
err = kErrorHardware;
}
Sys::close_(fd);
return err;
}
DisplayError HWDeviceDRM::GetPanelBrightness(int *level) {
DisplayError err = kErrorNone;
char brightness[kMaxStringLength] = {0};
if (!level) {
DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer.");
return kErrorParameters;
}
int fd = Sys::open_(kBrightnessNode, O_RDWR);
if (fd < 0) {
DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode,
strerror(errno));
return kErrorFileDescriptor;
}
if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
*level = atoi(brightness);
DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level);
} else {
DLOGV_IF(kTagDriverConfig, "Failed to read panel brightness");
err = kErrorHardware;
}
Sys::close_(fd);
return err;
}
DisplayError HWDeviceDRM::CachePanelBrightness(int level) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::GetHWScanInfo(HWScanInfo *scan_info) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::GetVideoFormat(uint32_t config_index, uint32_t *video_format) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::GetMaxCEAFormat(uint32_t *max_cea_format) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::SetS3DMode(HWS3DMode s3d_mode) {
return kErrorNotSupported;
}
DisplayError HWDeviceDRM::SetScaleLutConfig(HWScaleLutInfo *lut_info) {
sde_drm::DRMScalerLUTInfo drm_lut_info = {};
drm_lut_info.cir_lut = lut_info->cir_lut;
drm_lut_info.dir_lut = lut_info->dir_lut;
drm_lut_info.sep_lut = lut_info->sep_lut;
drm_lut_info.cir_lut_size = lut_info->cir_lut_size;
drm_lut_info.dir_lut_size = lut_info->dir_lut_size;
drm_lut_info.sep_lut_size = lut_info->sep_lut_size;
drm_mgr_intf_->SetScalerLUT(drm_lut_info);
return kErrorNone;
}
DisplayError HWDeviceDRM::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
if (!hw_resource_.hw_dest_scalar_info.count) {
return kErrorNotSupported;
}
if (mixer_attributes.width > display_attributes_.x_pixels ||
mixer_attributes.height > display_attributes_.y_pixels) {
DLOGW("Input resolution exceeds display resolution! input: res %dx%d display: res %dx%d",
mixer_attributes.width, mixer_attributes.height, display_attributes_.x_pixels,
display_attributes_.y_pixels);
return kErrorNotSupported;
}
uint32_t max_input_width = hw_resource_.hw_dest_scalar_info.max_input_width;
if (display_attributes_.is_device_split) {
max_input_width *= 2;
}
if (mixer_attributes.width > max_input_width) {
DLOGW("Input width exceeds width limit! input_width %d width_limit %d", mixer_attributes.width,
max_input_width);
return kErrorNotSupported;
}
float mixer_aspect_ratio = FLOAT(mixer_attributes.width) / FLOAT(mixer_attributes.height);
float display_aspect_ratio =
FLOAT(display_attributes_.x_pixels) / FLOAT(display_attributes_.y_pixels);
if (display_aspect_ratio != mixer_aspect_ratio) {
DLOGW("Aspect ratio mismatch! input: res %dx%d display: res %dx%d", mixer_attributes.width,
mixer_attributes.height, display_attributes_.x_pixels, display_attributes_.y_pixels);
return kErrorNotSupported;
}
float scale_x = FLOAT(display_attributes_.x_pixels) / FLOAT(mixer_attributes.width);
float scale_y = FLOAT(display_attributes_.y_pixels) / FLOAT(mixer_attributes.height);
float max_scale_up = hw_resource_.hw_dest_scalar_info.max_scale_up;
if (scale_x > max_scale_up || scale_y > max_scale_up) {
DLOGW(
"Up scaling ratio exceeds for destination scalar upscale limit scale_x %f scale_y %f "
"max_scale_up %f",
scale_x, scale_y, max_scale_up);
return kErrorNotSupported;
}
float mixer_split_ratio = FLOAT(mixer_attributes_.split_left) / FLOAT(mixer_attributes_.width);
mixer_attributes_ = mixer_attributes;
mixer_attributes_.split_left = mixer_attributes_.width;
if (display_attributes_.is_device_split) {
mixer_attributes_.split_left = UINT32(FLOAT(mixer_attributes.width) * mixer_split_ratio);
}
return kErrorNone;
}
DisplayError HWDeviceDRM::GetMixerAttributes(HWMixerAttributes *mixer_attributes) {
if (!mixer_attributes) {
return kErrorParameters;
}
mixer_attributes_.width = display_attributes_.x_pixels;
mixer_attributes_.height = display_attributes_.y_pixels;
mixer_attributes_.split_left = display_attributes_.is_device_split
? hw_panel_info_.split_info.left_split
: mixer_attributes_.width;
*mixer_attributes = mixer_attributes_;
return kErrorNone;
}
void HWDeviceDRM::GetDRMDisplayToken(sde_drm::DRMDisplayToken *token) const {
token->conn_id = token_.conn_id;
token->crtc_id = token_.crtc_id;
}
void HWDeviceDRM::UpdateMixerAttributes() {
mixer_attributes_.width = display_attributes_.x_pixels;
mixer_attributes_.height = display_attributes_.y_pixels;
mixer_attributes_.split_left = display_attributes_.is_device_split
? hw_panel_info_.split_info.left_split
: mixer_attributes_.width;
}
void HWDeviceDRM::SetSecureConfig(const LayerBuffer &input_buffer, DRMSecureMode *fb_secure_mode,
DRMSecurityLevel *security_level) {
*fb_secure_mode = DRMSecureMode::NON_SECURE;
*security_level = DRMSecurityLevel::SECURE_NON_SECURE;
if (input_buffer.flags.secure) {
if (input_buffer.flags.secure_camera) {
// IOMMU configuration for this framebuffer mode is secure domain & requires
// only stage II translation, when this buffer is accessed by Display H/W.
// Secure and non-secure planes can be attached to this CRTC.
*fb_secure_mode = DRMSecureMode::SECURE_DIR_TRANSLATION;
} else if (input_buffer.flags.secure_display) {
// IOMMU configuration for this framebuffer mode is non-secure domain & requires
// only stage II translation, when this buffer is accessed by Display H/W.
// Only secure planes can be attached to this CRTC.
*fb_secure_mode = DRMSecureMode::NON_SECURE_DIR_TRANSLATION;
*security_level = DRMSecurityLevel::SECURE_ONLY;
} else {
// IOMMU configuration for this framebuffer mode is secure domain & requires both
// stage I and stage II translations, when this buffer is accessed by Display H/W.
// Secure and non-secure planes can be attached to this CRTC.
*fb_secure_mode = DRMSecureMode::SECURE;
}
}
}
} // namespace sdm