summaryrefslogtreecommitdiff
path: root/msm8909/sdm/libs/core/fb/hw_hdmi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'msm8909/sdm/libs/core/fb/hw_hdmi.cpp')
-rw-r--r--msm8909/sdm/libs/core/fb/hw_hdmi.cpp1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/msm8909/sdm/libs/core/fb/hw_hdmi.cpp b/msm8909/sdm/libs/core/fb/hw_hdmi.cpp
new file mode 100644
index 00000000..15b47da0
--- /dev/null
+++ b/msm8909/sdm/libs/core/fb/hw_hdmi.cpp
@@ -0,0 +1,1129 @@
+/*
+* Copyright (c) 2015 - 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.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <utils/debug.h>
+#include <utils/sys.h>
+#include <utils/formats.h>
+
+#include <vector>
+#include <map>
+#include <utility>
+
+#include "hw_hdmi.h"
+
+#define __CLASS__ "HWHDMI"
+
+#define MIN_HDR_RESET_WAITTIME_SEC 2
+
+namespace sdm {
+
+#ifdef MDP_HDR_STREAM
+static int32_t GetEOTF(const GammaTransfer &transfer) {
+ int32_t mdp_transfer = -1;
+
+ switch (transfer) {
+ case Transfer_SMPTE_ST2084:
+ mdp_transfer = MDP_HDR_EOTF_SMTPE_ST2084;
+ break;
+ case Transfer_HLG:
+ mdp_transfer = MDP_HDR_EOTF_HLG;
+ break;
+ default:
+ DLOGW("Unknown Transfer: %d", transfer);
+ }
+
+ return mdp_transfer;
+}
+
+static int32_t GetColoriMetry(const LayerBuffer & layer_buffer) {
+ bool is_yuv = layer_buffer.flags.video;
+ int32_t colorimetry = -1;
+
+ if (is_yuv) {
+ switch (layer_buffer.color_metadata.colorPrimaries) {
+ case ColorPrimaries_BT601_6_525:
+ case ColorPrimaries_BT601_6_625:
+ colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_601;
+ break;
+ case ColorPrimaries_BT709_5:
+ colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_709;
+ break;
+ case ColorPrimaries_BT2020:
+ colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_2020_YCBCR;
+ break;
+ default:
+ DLOGW("Unknown color primary = %d for YUV", layer_buffer.color_metadata.colorPrimaries);
+ }
+ }
+
+ return colorimetry;
+}
+
+static int32_t GetPixelEncoding(const LayerBuffer &layer_buffer) {
+ bool is_yuv = layer_buffer.flags.video;
+ int32_t mdp_pixel_encoding = -1;
+ mdp_pixel_encoding = MDP_PIXEL_ENCODING_RGB; // set RGB as default
+
+ if (is_yuv) {
+ switch (layer_buffer.format) {
+ case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
+ case kFormatYCbCr420Planar:
+ case kFormatYCrCb420Planar:
+ case kFormatYCrCb420PlanarStride16:
+ case kFormatYCbCr420SemiPlanar:
+ case kFormatYCrCb420SemiPlanar:
+ case kFormatYCbCr420P010:
+ case kFormatYCbCr420TP10Ubwc:
+ mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_420;
+ break;
+ case kFormatYCbCr422H2V1Packed:
+ case kFormatYCrCb422H2V1SemiPlanar:
+ case kFormatYCrCb422H1V2SemiPlanar:
+ case kFormatYCbCr422H2V1SemiPlanar:
+ case kFormatYCbCr422H1V2SemiPlanar:
+ mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_422;
+ break;
+ default: // other yuv formats
+ DLOGW("New YUV format = %d, need to add support", layer_buffer.format);
+ break;
+ }
+ }
+
+ return mdp_pixel_encoding;
+}
+static int32_t GetBitsPerComponent(const LayerBuffer &layer_buffer) {
+ bool is_yuv = layer_buffer.flags.video;
+ bool is_10_bit = Is10BitFormat(layer_buffer.format);
+ int32_t mdp_bpc = -1;
+
+ if (is_yuv) {
+ mdp_bpc = is_10_bit ? MDP_YUV_10_BPC : MDP_YUV_8_BPC;
+ } else {
+ mdp_bpc = is_10_bit ? MDP_RGB_10_BPC : MDP_RGB_8_BPC;
+ }
+
+ return mdp_bpc;
+}
+
+static uint32_t GetRange(const ColorRange &range) {
+ return ((range == Range_Full) ? MDP_DYNAMIC_RANGE_VESA : MDP_DYNAMIC_RANGE_CEA);
+}
+
+static uint32_t GetContentType(const LayerBuffer &layer_buffer) {
+ return (layer_buffer.flags.video ? MDP_CONTENT_TYPE_VIDEO : MDP_CONTENT_TYPE_GRAPHICS);
+}
+#endif
+
+static bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
+ fb_var_screeninfo *info) {
+ if (!mode || !info) {
+ return false;
+ }
+
+ info->reserved[0] = 0;
+ info->reserved[1] = 0;
+ info->reserved[2] = 0;
+ info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16);
+ info->xoffset = 0;
+ info->yoffset = 0;
+ info->xres = mode->active_h;
+ info->yres = mode->active_v;
+ info->pixclock = (mode->pixel_freq) * 1000;
+ info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
+ info->right_margin = mode->front_porch_h;
+ info->hsync_len = mode->pulse_width_h;
+ info->left_margin = mode->back_porch_h;
+ info->lower_margin = mode->front_porch_v;
+ info->vsync_len = mode->pulse_width_v;
+ info->upper_margin = mode->back_porch_v;
+
+ info->grayscale = V4L2_PIX_FMT_RGB24;
+ // If the mode supports YUV420 set grayscale to the FOURCC value for YUV420.
+ std::bitset<32> pixel_formats = mode->pixel_formats;
+ if (pixel_formats[1]) {
+ info->grayscale = V4L2_PIX_FMT_NV12;
+ }
+
+ if (!mode->active_low_h) {
+ info->sync |= (uint32_t)FB_SYNC_HOR_HIGH_ACT;
+ } else {
+ info->sync &= (uint32_t)~FB_SYNC_HOR_HIGH_ACT;
+ }
+
+ if (!mode->active_low_v) {
+ info->sync |= (uint32_t)FB_SYNC_VERT_HIGH_ACT;
+ } else {
+ info->sync &= (uint32_t)~FB_SYNC_VERT_HIGH_ACT;
+ }
+
+ return true;
+}
+
+HWHDMI::HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
+ : HWDevice(buffer_sync_handler), hw_scan_info_(), active_config_index_(0) {
+ HWDevice::device_type_ = kDeviceHDMI;
+ HWDevice::device_name_ = "HDMI Display Device";
+ HWDevice::hw_info_intf_ = hw_info_intf;
+ (void)hdr_reset_start_;
+ (void)hdr_reset_end_;
+ (void)reset_hdr_flag_;
+ (void)cdm_color_space_;
+}
+
+DisplayError HWHDMI::Init() {
+ DisplayError error = kErrorNone;
+
+ SetSourceProductInformation("vendor_name", "ro.product.manufacturer");
+ SetSourceProductInformation("product_description", "ro.product.name");
+
+ error = HWDevice::Init();
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
+
+ error = ReadEDIDInfo();
+ if (error != kErrorNone) {
+ Deinit();
+ return error;
+ }
+
+ if (!IsResolutionFilePresent()) {
+ Deinit();
+ return kErrorHardware;
+ }
+
+ error = ReadTimingInfo();
+ if (error != kErrorNone) {
+ Deinit();
+ return error;
+ }
+
+ ReadScanInfo();
+
+ GetPanelS3DMode();
+
+ s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
+ (kS3DModeNone, HDMI_S3D_NONE));
+ s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
+ (kS3DModeLR, HDMI_S3D_SIDE_BY_SIDE));
+ s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
+ (kS3DModeRL, HDMI_S3D_SIDE_BY_SIDE));
+ s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
+ (kS3DModeTB, HDMI_S3D_TOP_AND_BOTTOM));
+ s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
+ (kS3DModeFP, HDMI_S3D_FRAME_PACKING));
+
+ return error;
+}
+
+DisplayError HWHDMI::GetNumDisplayAttributes(uint32_t *count) {
+ *count = UINT32(hdmi_modes_.size());
+ if (*count <= 0) {
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetActiveConfig(uint32_t *active_config_index) {
+ *active_config_index = active_config_index_;
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::ReadEDIDInfo() {
+ ssize_t length = -1;
+ char edid_str[kPageSize] = {'\0'};
+ char edid_path[kMaxStringLength] = {'\0'};
+ snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_);
+ int edid_file = Sys::open_(edid_path, O_RDONLY);
+ if (edid_file < 0) {
+ DLOGE("EDID file open failed.");
+ return kErrorHardware;
+ }
+
+ length = Sys::pread_(edid_file, edid_str, sizeof(edid_str)-1, 0);
+ if (length <= 0) {
+ DLOGE("%s: edid_modes file empty");
+ return kErrorHardware;
+ }
+ Sys::close_(edid_file);
+
+ DLOGI("EDID mode string: %s", edid_str);
+ while (length > 1 && isspace(edid_str[length-1])) {
+ --length;
+ }
+ edid_str[length] = '\0';
+
+ if (length > 0) {
+ // Get EDID modes from the EDID string
+ char *ptr = edid_str;
+ const uint32_t edid_count_max = 128;
+ char *tokens[edid_count_max] = { NULL };
+ uint32_t hdmi_mode_count = 0;
+
+ ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count);
+
+ supported_video_modes_.resize(hdmi_mode_count);
+
+ hdmi_modes_.resize(hdmi_mode_count);
+ for (uint32_t i = 0; i < hdmi_mode_count; i++) {
+ hdmi_modes_[i] = UINT32(atoi(tokens[i]));
+ }
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetDisplayAttributes(uint32_t index,
+ HWDisplayAttributes *display_attributes) {
+ DTRACE_SCOPED();
+
+ if (index >= hdmi_modes_.size()) {
+ return kErrorNotSupported;
+ }
+
+ // Get the resolution info from the look up table
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+ for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
+ msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+ if (cur->video_format == hdmi_modes_[index]) {
+ timing_mode = cur;
+ break;
+ }
+ }
+ display_attributes->x_pixels = timing_mode->active_h;
+ display_attributes->y_pixels = timing_mode->active_v;
+ display_attributes->v_front_porch = timing_mode->front_porch_v;
+ display_attributes->v_back_porch = timing_mode->back_porch_v;
+ display_attributes->v_pulse_width = timing_mode->pulse_width_v;
+ uint32_t h_blanking = timing_mode->front_porch_h + timing_mode->back_porch_h +
+ timing_mode->pulse_width_h;
+ display_attributes->h_total = timing_mode->active_h + h_blanking;
+ display_attributes->x_dpi = 0;
+ display_attributes->y_dpi = 0;
+ display_attributes->fps = timing_mode->refresh_rate / 1000;
+ display_attributes->vsync_period_ns = UINT32(1000000000L / display_attributes->fps);
+ display_attributes->is_device_split = false;
+ if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
+ display_attributes->is_device_split = true;
+ display_attributes->h_total += h_blanking;
+ }
+
+ GetDisplayS3DSupport(index, display_attributes);
+ std::bitset<32> pixel_formats = timing_mode->pixel_formats;
+
+ display_attributes->is_yuv = pixel_formats[1];
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::SetDisplayAttributes(uint32_t index) {
+ DTRACE_SCOPED();
+
+ if (index > hdmi_modes_.size()) {
+ return kErrorNotSupported;
+ }
+
+ // Variable screen info
+ fb_var_screeninfo vscreeninfo = {};
+ if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &vscreeninfo) < 0) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
+ return kErrorHardware;
+ }
+
+ DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3],
+ vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+ vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+ vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+ for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
+ msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+ if (cur->video_format == hdmi_modes_[index]) {
+ timing_mode = cur;
+ break;
+ }
+ }
+
+ if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) {
+ return kErrorParameters;
+ }
+
+ msmfb_metadata metadata = {};
+ metadata.op = metadata_op_vic;
+ metadata.data.video_info_code = timing_mode->video_format;
+ if (Sys::ioctl_(device_fd_, MSMFB_METADATA_SET, &metadata) < 0) {
+ IOCTL_LOGE(MSMFB_METADATA_SET, device_type_);
+ return kErrorHardware;
+ }
+
+ DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00,
+ vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+ vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+ vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+ vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
+ if (Sys::ioctl_(device_fd_, FBIOPUT_VSCREENINFO, &vscreeninfo) < 0) {
+ IOCTL_LOGE(FBIOPUT_VSCREENINFO, device_type_);
+ return kErrorHardware;
+ }
+
+ active_config_index_ = index;
+
+ frame_rate_ = timing_mode->refresh_rate;
+
+ // Get the display attributes for current active config index
+ GetDisplayAttributes(active_config_index_, &display_attributes_);
+ UpdateMixerAttributes();
+
+ supported_s3d_modes_.clear();
+ supported_s3d_modes_.push_back(kS3DModeNone);
+ for (uint32_t mode = kS3DModeNone + 1; mode < kS3DModeMax; mode ++) {
+ if (display_attributes_.s3d_config[(HWS3DMode)mode]) {
+ supported_s3d_modes_.push_back((HWS3DMode)mode);
+ }
+ }
+
+ SetS3DMode(kS3DModeNone);
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetConfigIndex(uint32_t mode, uint32_t *index) {
+ // Check if the mode is valid and return corresponding index
+ for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
+ if (hdmi_modes_[i] == mode) {
+ *index = i;
+ DLOGI("Index = %d for config = %d", *index, mode);
+ return kErrorNone;
+ }
+ }
+
+ DLOGE("Config = %d not supported", mode);
+ return kErrorNotSupported;
+}
+
+DisplayError HWHDMI::Validate(HWLayers *hw_layers) {
+ HWDevice::ResetDisplayParams();
+ return HWDevice::Validate(hw_layers);
+}
+
+DisplayError HWHDMI::Commit(HWLayers *hw_layers) {
+ DisplayError error = UpdateHDRMetaData(hw_layers);
+ if (error != kErrorNone) {
+ return error;
+ }
+ if (cdm_color_space_commit_) {
+#ifdef MDP_COMMIT_UPDATE_CDM_COLOR_SPACE
+ mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
+ mdp_commit.cdm_color_space = cdm_color_space_;
+ mdp_commit.flags |= MDP_COMMIT_UPDATE_CDM_COLOR_SPACE;
+#endif
+ }
+
+ error = HWDevice::Commit(hw_layers);
+ if (cdm_color_space_commit_)
+ cdm_color_space_commit_ = false;
+
+ return error;
+}
+
+DisplayError HWHDMI::GetHWScanInfo(HWScanInfo *scan_info) {
+ if (!scan_info) {
+ return kErrorParameters;
+ }
+ *scan_info = hw_scan_info_;
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetVideoFormat(uint32_t config_index, uint32_t *video_format) {
+ if (config_index > hdmi_modes_.size()) {
+ return kErrorNotSupported;
+ }
+
+ *video_format = hdmi_modes_[config_index];
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetMaxCEAFormat(uint32_t *max_cea_format) {
+ *max_cea_format = HDMI_VFRMT_END;
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
+ DisplayError error = kErrorNone;
+ int fd = -1;
+ char data[kMaxStringLength] = {'\0'};
+
+ snprintf(data, sizeof(data), "%s%d/hdcp2p2/min_level_change", fb_path_, fb_node_index_);
+
+ fd = Sys::open_(data, O_WRONLY);
+ if (fd < 0) {
+ DLOGW("File '%s' could not be opened.", data);
+ return kErrorHardware;
+ }
+
+ snprintf(data, sizeof(data), "%d", min_enc_level);
+
+ ssize_t err = Sys::pwrite_(fd, data, strlen(data), 0);
+ if (err <= 0) {
+ DLOGE("Write failed, Error = %s", strerror(errno));
+ error = kErrorHardware;
+ }
+
+ Sys::close_(fd);
+
+ return error;
+}
+
+HWScanSupport HWHDMI::MapHWScanSupport(uint32_t value) {
+ switch (value) {
+ // TODO(user): Read the scan type from driver defined values instead of hardcoding
+ case 0:
+ return kScanNotSupported;
+ case 1:
+ return kScanAlwaysOverscanned;
+ case 2:
+ return kScanAlwaysUnderscanned;
+ case 3:
+ return kScanBoth;
+ default:
+ return kScanNotSupported;
+ break;
+ }
+}
+
+void HWHDMI::ReadScanInfo() {
+ int scan_info_file = -1;
+ ssize_t len = -1;
+ char data[kPageSize] = {'\0'};
+
+ snprintf(data, sizeof(data), "%s%d/scan_info", fb_path_, fb_node_index_);
+ scan_info_file = Sys::open_(data, O_RDONLY);
+ if (scan_info_file < 0) {
+ DLOGW("File '%s' not found.", data);
+ return;
+ }
+
+ memset(&data[0], 0, sizeof(data));
+ len = Sys::pread_(scan_info_file, data, sizeof(data) - 1, 0);
+ if (len <= 0) {
+ Sys::close_(scan_info_file);
+ DLOGW("File %s%d/scan_info is empty.", fb_path_, fb_node_index_);
+ return;
+ }
+ data[len] = '\0';
+ Sys::close_(scan_info_file);
+
+ const uint32_t scan_info_max_count = 3;
+ uint32_t scan_info_count = 0;
+ char *tokens[scan_info_max_count] = { NULL };
+ ParseLine(data, tokens, scan_info_max_count, &scan_info_count);
+ if (scan_info_count != scan_info_max_count) {
+ DLOGW("Failed to parse scan info string %s", data);
+ return;
+ }
+
+ hw_scan_info_.pt_scan_support = MapHWScanSupport(UINT32(atoi(tokens[0])));
+ hw_scan_info_.it_scan_support = MapHWScanSupport(UINT32(atoi(tokens[1])));
+ hw_scan_info_.cea_scan_support = MapHWScanSupport(UINT32(atoi(tokens[2])));
+ DLOGI("PT %d IT %d CEA %d", hw_scan_info_.pt_scan_support, hw_scan_info_.it_scan_support,
+ hw_scan_info_.cea_scan_support);
+}
+
+int HWHDMI::OpenResolutionFile(int file_mode) {
+ char file_path[kMaxStringLength];
+ memset(file_path, 0, sizeof(file_path));
+ snprintf(file_path , sizeof(file_path), "%s%d/res_info", fb_path_, fb_node_index_);
+
+ int fd = Sys::open_(file_path, file_mode);
+
+ if (fd < 0) {
+ DLOGE("file '%s' not found : ret = %d err str: %s", file_path, fd, strerror(errno));
+ }
+
+ return fd;
+}
+
+// Method to request HDMI driver to write a new page of timing info into res_info node
+void HWHDMI::RequestNewPage(uint32_t page_number) {
+ char page_string[kPageSize];
+ int fd = OpenResolutionFile(O_WRONLY);
+ if (fd < 0) {
+ return;
+ }
+
+ snprintf(page_string, sizeof(page_string), "%d", page_number);
+
+ DLOGI_IF(kTagDriverConfig, "page=%s", page_string);
+
+ ssize_t err = Sys::pwrite_(fd, page_string, sizeof(page_string), 0);
+ if (err <= 0) {
+ DLOGE("Write to res_info failed (%s)", strerror(errno));
+ }
+
+ Sys::close_(fd);
+}
+
+// Reads the contents of res_info node into a buffer if the file is not empty
+bool HWHDMI::ReadResolutionFile(char *config_buffer) {
+ ssize_t bytes_read = 0;
+ int fd = OpenResolutionFile(O_RDONLY);
+ if (fd >= 0) {
+ bytes_read = Sys::pread_(fd, config_buffer, kPageSize, 0);
+ Sys::close_(fd);
+ }
+
+ DLOGI_IF(kTagDriverConfig, "bytes_read = %d", bytes_read);
+
+ return (bytes_read > 0);
+}
+
+// Populates the internal timing info structure with the timing info obtained
+// from the HDMI driver
+DisplayError HWHDMI::ReadTimingInfo() {
+ uint32_t config_index = 0;
+ uint32_t page_number = MSM_HDMI_INIT_RES_PAGE;
+ uint32_t size = sizeof(msm_hdmi_mode_timing_info);
+
+ while (true) {
+ char config_buffer[kPageSize] = {0};
+ msm_hdmi_mode_timing_info *info = reinterpret_cast<msm_hdmi_mode_timing_info *>(config_buffer);
+ RequestNewPage(page_number);
+
+ if (!ReadResolutionFile(config_buffer)) {
+ break;
+ }
+
+ while (info->video_format && size < kPageSize && config_index < hdmi_modes_.size()) {
+ supported_video_modes_[config_index] = *info;
+ size += sizeof(msm_hdmi_mode_timing_info);
+
+ DLOGI_IF(kTagDriverConfig, "Config=%d Mode %d: (%dx%d) @ %d, pixel formats %d",
+ config_index,
+ supported_video_modes_[config_index].video_format,
+ supported_video_modes_[config_index].active_h,
+ supported_video_modes_[config_index].active_v,
+ supported_video_modes_[config_index].refresh_rate,
+ supported_video_modes_[config_index].pixel_formats);
+
+ info++;
+ config_index++;
+ }
+
+ size = sizeof(msm_hdmi_mode_timing_info);
+ // Request HDMI driver to populate res_info with more
+ // timing information
+ page_number++;
+ }
+
+ if (page_number == MSM_HDMI_INIT_RES_PAGE || config_index == 0) {
+ DLOGE("No timing information found.");
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+bool HWHDMI::IsResolutionFilePresent() {
+ bool is_file_present = false;
+ int fd = OpenResolutionFile(O_RDONLY);
+ if (fd >= 0) {
+ is_file_present = true;
+ Sys::close_(fd);
+ }
+
+ return is_file_present;
+}
+
+void HWHDMI::SetSourceProductInformation(const char *node, const char *name) {
+ char property_value[kMaxStringLength];
+ char sys_fs_path[kMaxStringLength];
+ int hdmi_node_index = GetFBNodeIndex(kDeviceHDMI);
+ if (hdmi_node_index < 0) {
+ return;
+ }
+
+ ssize_t length = 0;
+ bool prop_read_success = Debug::GetProperty(name, property_value);
+ if (!prop_read_success) {
+ return;
+ }
+
+ snprintf(sys_fs_path , sizeof(sys_fs_path), "%s%d/%s", fb_path_, hdmi_node_index, node);
+ length = HWDevice::SysFsWrite(sys_fs_path, property_value,
+ static_cast<ssize_t>(strlen(property_value)));
+ if (length <= 0) {
+ DLOGW("Failed to write %s = %s", node, property_value);
+ }
+}
+
+DisplayError HWHDMI::GetDisplayS3DSupport(uint32_t index,
+ HWDisplayAttributes *attrib) {
+ ssize_t length = -1;
+ char edid_s3d_str[kPageSize] = {'\0'};
+ char edid_s3d_path[kMaxStringLength] = {'\0'};
+ snprintf(edid_s3d_path, sizeof(edid_s3d_path), "%s%d/edid_3d_modes", fb_path_, fb_node_index_);
+
+ if (index > hdmi_modes_.size()) {
+ return kErrorNotSupported;
+ }
+
+ attrib->s3d_config[kS3DModeNone] = 1;
+
+ // Three level inception!
+ // The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH
+ // Initialize all the pointers to NULL to avoid crash in function strtok_r()
+ char *saveptr_l1 = NULL, *saveptr_l2 = NULL, *saveptr_l3 = NULL;
+ char *l1 = NULL, *l2 = NULL, *l3 = NULL;
+
+ int edid_s3d_node = Sys::open_(edid_s3d_path, O_RDONLY);
+ if (edid_s3d_node < 0) {
+ DLOGW("%s could not be opened : %s", edid_s3d_path, strerror(errno));
+ return kErrorNotSupported;
+ }
+
+ length = Sys::pread_(edid_s3d_node, edid_s3d_str, sizeof(edid_s3d_str)-1, 0);
+ if (length <= 0) {
+ Sys::close_(edid_s3d_node);
+ return kErrorNotSupported;
+ }
+
+ l1 = strtok_r(edid_s3d_str, ",", &saveptr_l1);
+ while (l1 != NULL) {
+ l2 = strtok_r(l1, "=", &saveptr_l2);
+ if (l2 != NULL) {
+ if (hdmi_modes_[index] == (uint32_t)atoi(l2)) {
+ l3 = strtok_r(saveptr_l2, ":", &saveptr_l3);
+ while (l3 != NULL) {
+ if (strncmp("SSH", l3, strlen("SSH")) == 0) {
+ attrib->s3d_config[kS3DModeLR] = 1;
+ attrib->s3d_config[kS3DModeRL] = 1;
+ } else if (strncmp("TAB", l3, strlen("TAB")) == 0) {
+ attrib->s3d_config[kS3DModeTB] = 1;
+ } else if (strncmp("FP", l3, strlen("FP")) == 0) {
+ attrib->s3d_config[kS3DModeFP] = 1;
+ }
+ l3 = strtok_r(NULL, ":", &saveptr_l3);
+ }
+ }
+ }
+ l1 = strtok_r(NULL, ",", &saveptr_l1);
+ }
+
+ Sys::close_(edid_s3d_node);
+ return kErrorNone;
+}
+
+bool HWHDMI::IsSupportedS3DMode(HWS3DMode s3d_mode) {
+ for (uint32_t i = 0; i < supported_s3d_modes_.size(); i++) {
+ if (supported_s3d_modes_[i] == s3d_mode) {
+ return true;
+ }
+ }
+ return false;
+}
+
+DisplayError HWHDMI::SetS3DMode(HWS3DMode s3d_mode) {
+ if (!IsSupportedS3DMode(s3d_mode)) {
+ DLOGW("S3D mode is not supported s3d_mode = %d", s3d_mode);
+ return kErrorNotSupported;
+ }
+
+ std::map<HWS3DMode, msm_hdmi_s3d_mode>::iterator it = s3d_mode_sdm_to_mdp_.find(s3d_mode);
+ if (it == s3d_mode_sdm_to_mdp_.end()) {
+ return kErrorNotSupported;
+ }
+ msm_hdmi_s3d_mode s3d_mdp_mode = it->second;
+
+ if (active_mdp_s3d_mode_ == s3d_mdp_mode) {
+ // HDMI_S3D_SIDE_BY_SIDE is an mdp mapping for kS3DModeLR and kS3DModeRL s3d modes. So no need
+ // to update the s3d_mode node. hw_panel_info needs to be updated to differentiate these two s3d
+ // modes in strategy
+ hw_panel_info_.s3d_mode = s3d_mode;
+ return kErrorNone;
+ }
+
+ ssize_t length = -1;
+ char s3d_mode_path[kMaxStringLength] = {'\0'};
+ char s3d_mode_string[kMaxStringLength] = {'\0'};
+ snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_);
+
+ int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR);
+ if (s3d_mode_node < 0) {
+ DLOGW("%s could not be opened : %s", s3d_mode_path, strerror(errno));
+ return kErrorNotSupported;
+ }
+
+ snprintf(s3d_mode_string, sizeof(s3d_mode_string), "%d", s3d_mdp_mode);
+ length = Sys::pwrite_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0);
+ if (length <= 0) {
+ DLOGW("Failed to write into s3d node: %s", strerror(errno));
+ Sys::close_(s3d_mode_node);
+ return kErrorNotSupported;
+ }
+
+ active_mdp_s3d_mode_ = s3d_mdp_mode;
+ hw_panel_info_.s3d_mode = s3d_mode;
+ Sys::close_(s3d_mode_node);
+
+ DLOGI_IF(kTagDriverConfig, "Set s3d mode %d", hw_panel_info_.s3d_mode);
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetPanelS3DMode() {
+ ssize_t length = -1;
+ char s3d_mode_path[kMaxStringLength] = {'\0'};
+ char s3d_mode_string[kMaxStringLength] = {'\0'};
+ snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_);
+ int panel_s3d_mode = 0;
+
+ int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR);
+ if (s3d_mode_node < 0) {
+ DLOGE("%s could not be opened : %s", s3d_mode_path, strerror(errno));
+ return kErrorNotSupported;
+ }
+
+ length = Sys::pread_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0);
+ if (length <= 0) {
+ DLOGE("Failed read s3d node: %s", strerror(errno));
+ Sys::close_(s3d_mode_node);
+ return kErrorNotSupported;
+ }
+
+ panel_s3d_mode = atoi(s3d_mode_string);
+ if (panel_s3d_mode < HDMI_S3D_NONE || panel_s3d_mode >= HDMI_S3D_MAX) {
+ Sys::close_(s3d_mode_node);
+ DLOGW("HDMI panel S3D mode is not supported panel_s3d_mode = %d", panel_s3d_mode);
+ return kErrorUndefined;
+ }
+
+ active_mdp_s3d_mode_ = static_cast<msm_hdmi_s3d_mode>(panel_s3d_mode);
+ Sys::close_(s3d_mode_node);
+
+ DLOGI_IF(kTagDriverConfig, "Get HDMI panel s3d mode %d", active_mdp_s3d_mode_);
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t *mode,
+ DynamicFPSData *data, uint32_t *config_index) {
+ msm_hdmi_mode_timing_info *cur = NULL;
+ msm_hdmi_mode_timing_info *dst = NULL;
+ uint32_t i = 0;
+ int pre_refresh_rate_diff = 0;
+ bool pre_unstd_mode = false;
+
+ for (i = 0; i < hdmi_modes_.size(); i++) {
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i];
+ if (timing_mode->video_format == hdmi_modes_[active_config_index_]) {
+ cur = timing_mode;
+ break;
+ }
+ }
+
+ if (cur == NULL) {
+ DLOGE("can't find timing info for active config index(%d)", active_config_index_);
+ return kErrorUndefined;
+ }
+
+ if (cur->refresh_rate != frame_rate_) {
+ pre_unstd_mode = true;
+ }
+
+ if (i >= hdmi_modes_.size()) {
+ return kErrorNotSupported;
+ }
+
+ dst = cur;
+ pre_refresh_rate_diff = static_cast<int>(dst->refresh_rate) - static_cast<int>(refresh_rate);
+
+ for (i = 0; i < hdmi_modes_.size(); i++) {
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i];
+ if (cur->active_h == timing_mode->active_h &&
+ cur->active_v == timing_mode->active_v &&
+ cur->pixel_formats == timing_mode->pixel_formats ) {
+ int cur_refresh_rate_diff = static_cast<int>(timing_mode->refresh_rate) -
+ static_cast<int>(refresh_rate);
+ if (abs(pre_refresh_rate_diff) > abs(cur_refresh_rate_diff)) {
+ pre_refresh_rate_diff = cur_refresh_rate_diff;
+ dst = timing_mode;
+ }
+ }
+ }
+
+ if (pre_refresh_rate_diff > kThresholdRefreshRate) {
+ return kErrorNotSupported;
+ }
+
+ GetConfigIndex(dst->video_format, config_index);
+
+ data->hor_front_porch = dst->front_porch_h;
+ data->hor_back_porch = dst->back_porch_h;
+ data->hor_pulse_width = dst->pulse_width_h;
+ data->clk_rate_hz = dst->pixel_freq;
+ data->fps = refresh_rate;
+
+ if (dst->front_porch_h != cur->front_porch_h) {
+ *mode = kModeHFP;
+ }
+
+ if (dst->refresh_rate != refresh_rate || dst->pixel_freq != cur->pixel_freq) {
+ if (*mode == kModeHFP) {
+ if (dst->refresh_rate != refresh_rate) {
+ *mode = kModeHFPCalcClock;
+ } else {
+ *mode = kModeClockHFP;
+ }
+ } else {
+ *mode = kModeClock;
+ }
+ }
+
+ if (pre_unstd_mode && (*mode == kModeHFP)) {
+ *mode = kModeClockHFP;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::SetRefreshRate(uint32_t refresh_rate) {
+ char mode_path[kMaxStringLength] = {0};
+ char node_path[kMaxStringLength] = {0};
+ uint32_t mode = kModeClock;
+ uint32_t config_index = 0;
+ DynamicFPSData data;
+ DisplayError error = kErrorNone;
+
+ if (refresh_rate == frame_rate_) {
+ return error;
+ }
+
+ error = GetDynamicFrameRateMode(refresh_rate, &mode, &data, &config_index);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ snprintf(mode_path, sizeof(mode_path), "%s%d/msm_fb_dfps_mode", fb_path_, fb_node_index_);
+ snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
+
+ int fd_mode = Sys::open_(mode_path, O_WRONLY);
+ if (fd_mode < 0) {
+ DLOGE("Failed to open %s with error %s", mode_path, strerror(errno));
+ return kErrorFileDescriptor;
+ }
+
+ char dfps_mode[kMaxStringLength];
+ snprintf(dfps_mode, sizeof(dfps_mode), "%d", mode);
+ DLOGI_IF(kTagDriverConfig, "Setting dfps_mode = %d", mode);
+ ssize_t len = Sys::pwrite_(fd_mode, dfps_mode, strlen(dfps_mode), 0);
+ if (len < 0) {
+ DLOGE("Failed to enable dfps mode %d with error %s", mode, strerror(errno));
+ Sys::close_(fd_mode);
+ return kErrorUndefined;
+ }
+ Sys::close_(fd_mode);
+
+ int fd_node = Sys::open_(node_path, O_WRONLY);
+ if (fd_node < 0) {
+ DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
+ return kErrorFileDescriptor;
+ }
+
+ char refresh_rate_string[kMaxStringLength];
+ if (mode == kModeHFP || mode == kModeClock) {
+ snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", data.fps);
+ DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", data.fps);
+ } else {
+ snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d %d %d %d %d",
+ data.hor_front_porch, data.hor_back_porch, data.hor_pulse_width,
+ data.clk_rate_hz, data.fps);
+ }
+ len = Sys::pwrite_(fd_node, refresh_rate_string, strlen(refresh_rate_string), 0);
+ if (len < 0) {
+ DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
+ Sys::close_(fd_node);
+ return kErrorUndefined;
+ }
+ Sys::close_(fd_node);
+
+ error = ReadTimingInfo();
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ GetDisplayAttributes(config_index, &display_attributes_);
+ UpdateMixerAttributes();
+
+ frame_rate_ = refresh_rate;
+ active_config_index_ = config_index;
+
+ DLOGI_IF(kTagDriverConfig, "config_index(%d) Mode(%d) frame_rate(%d)",
+ config_index,
+ mode,
+ frame_rate_);
+
+ return kErrorNone;
+}
+
+void HWHDMI::UpdateMixerAttributes() {
+ mixer_attributes_.width = display_attributes_.x_pixels;
+ mixer_attributes_.height = display_attributes_.y_pixels;
+ mixer_attributes_.split_left = display_attributes_.is_device_split ?
+ (display_attributes_.x_pixels / 2) : mixer_attributes_.width;
+}
+
+DisplayError HWHDMI::UpdateHDRMetaData(HWLayers *hw_layers) {
+ if (!hw_panel_info_.hdr_enabled) {
+ return kErrorNone;
+ }
+
+ DisplayError error = kErrorNone;
+
+#ifdef MDP_HDR_STREAM
+ const HWHDRLayerInfo &hdr_layer_info = hw_layers->info.hdr_layer_info;
+ char hdr_stream_path[kMaxStringLength] = {};
+ snprintf(hdr_stream_path, sizeof(hdr_stream_path), "%s%d/hdr_stream", fb_path_, fb_node_index_);
+
+ Layer hdr_layer = {};
+ if (hdr_layer_info.operation == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) {
+ hdr_layer = *(hw_layers->info.stack->layers.at(UINT32(hdr_layer_info.layer_index)));
+ }
+
+ const LayerBuffer *layer_buffer = &hdr_layer.input_buffer;
+ const MasteringDisplay &mastering_display = layer_buffer->color_metadata.masteringDisplayInfo;
+ const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel;
+ const Primaries &primaries = mastering_display.primaries;
+
+ mdp_hdr_stream_ctrl hdr_ctrl = {};
+ if (hdr_layer_info.operation == HWHDRLayerInfo::kSet) {
+ int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer);
+ hdr_ctrl.hdr_stream.eotf = (eotf < 0) ? 0 : UINT32(eotf);
+ hdr_ctrl.hdr_stream.white_point_x = primaries.whitePoint[0];
+ hdr_ctrl.hdr_stream.white_point_y = primaries.whitePoint[1];
+ hdr_ctrl.hdr_stream.display_primaries_x[0] = primaries.rgbPrimaries[0][0];
+ hdr_ctrl.hdr_stream.display_primaries_y[0] = primaries.rgbPrimaries[0][1];
+ hdr_ctrl.hdr_stream.display_primaries_x[1] = primaries.rgbPrimaries[1][0];
+ hdr_ctrl.hdr_stream.display_primaries_y[1] = primaries.rgbPrimaries[1][1];
+ hdr_ctrl.hdr_stream.display_primaries_x[2] = primaries.rgbPrimaries[2][0];
+ hdr_ctrl.hdr_stream.display_primaries_y[2] = primaries.rgbPrimaries[2][1];
+ hdr_ctrl.hdr_stream.min_luminance = mastering_display.minDisplayLuminance;
+ hdr_ctrl.hdr_stream.max_luminance = mastering_display.maxDisplayLuminance/10000;
+ hdr_ctrl.hdr_stream.max_content_light_level = light_level.maxContentLightLevel;
+ hdr_ctrl.hdr_stream.max_average_light_level = light_level.minPicAverageLightLevel;
+ hdr_ctrl.hdr_state = HDR_ENABLE;
+ reset_hdr_flag_ = false;
+#ifdef MDP_COMMIT_UPDATE_CDM_COLOR_SPACE
+ HWDevice::SetCSC(layer_buffer->color_metadata, &cdm_color_space_);
+ cdm_color_space_commit_ = true;
+#endif
+ // DP related
+ int32_t pixel_encoding = GetPixelEncoding(hdr_layer.input_buffer);
+ hdr_ctrl.hdr_stream.pixel_encoding = (pixel_encoding < 0) ? 0 : UINT32(pixel_encoding);
+ int32_t colorimetry = GetColoriMetry(hdr_layer.input_buffer);
+ hdr_ctrl.hdr_stream.colorimetry = (colorimetry < 0) ? 0 : UINT32(colorimetry);
+ hdr_ctrl.hdr_stream.range = GetRange(hdr_layer.input_buffer.color_metadata.range);
+ int32_t bits_per_component = GetBitsPerComponent(hdr_layer.input_buffer);
+ hdr_ctrl.hdr_stream.bits_per_component =
+ (bits_per_component < 0) ? 0 : UINT32(bits_per_component);
+ hdr_ctrl.hdr_stream.content_type = GetContentType(hdr_layer.input_buffer);
+
+ DLOGD_IF(kTagDriverConfig, "kSet: HDR Stream : MaxDisplayLuminance = %d\n"
+ "MinDisplayLuminance = %d MaxContentLightLevel = %d MaxAverageLightLevel = %d\n"
+ "Red_x = %d Red_y = %d Green_x = %d Green_y = %d Blue_x = %d Blue_y = %d\n"
+ "WhitePoint_x = %d WhitePoint_y = %d EOTF = %d PixelEncoding = %d Colorimetry = %d\n"
+ "Range = %d BPC = %d ContentType = %d hdr_state = %d",
+ hdr_ctrl.hdr_stream.max_luminance, hdr_ctrl.hdr_stream.min_luminance,
+ hdr_ctrl.hdr_stream.max_content_light_level, hdr_ctrl.hdr_stream.max_average_light_level,
+ hdr_ctrl.hdr_stream.display_primaries_x[0], hdr_ctrl.hdr_stream.display_primaries_y[0],
+ hdr_ctrl.hdr_stream.display_primaries_x[1], hdr_ctrl.hdr_stream.display_primaries_y[1],
+ hdr_ctrl.hdr_stream.display_primaries_x[2], hdr_ctrl.hdr_stream.display_primaries_y[2],
+ hdr_ctrl.hdr_stream.white_point_x, hdr_ctrl.hdr_stream.white_point_x,
+ hdr_ctrl.hdr_stream.eotf, hdr_ctrl.hdr_stream.pixel_encoding,
+ hdr_ctrl.hdr_stream.colorimetry, hdr_ctrl.hdr_stream.range,
+ hdr_ctrl.hdr_stream.bits_per_component, hdr_ctrl.hdr_stream.content_type,
+ hdr_ctrl.hdr_state);
+ } else if (hdr_layer_info.operation == HWHDRLayerInfo::kReset) {
+ memset(&hdr_ctrl.hdr_stream, 0, sizeof(hdr_ctrl.hdr_stream));
+ hdr_ctrl.hdr_state = HDR_RESET;
+ reset_hdr_flag_ = true;
+ hdr_reset_start_ = time(NULL);
+#ifdef MDP_COMMIT_UPDATE_CDM_COLOR_SPACE
+ cdm_color_space_ = (mdp_color_space) MDP_CSC_DEFAULT;
+ cdm_color_space_commit_ = true;
+#endif
+ DLOGD_IF(kTagDriverConfig, "kReset: HDR Stream: HDR_RESET");
+ } else if (hdr_layer_info.operation == HWHDRLayerInfo::kNoOp) {
+ if (reset_hdr_flag_) {
+ hdr_reset_end_ = time(NULL);
+
+ if ((hdr_reset_end_ - hdr_reset_start_) >= MIN_HDR_RESET_WAITTIME_SEC) {
+ reset_hdr_flag_ = false;
+ memset(&hdr_ctrl.hdr_stream, 0, sizeof(hdr_ctrl.hdr_stream));
+ hdr_ctrl.hdr_state = HDR_DISABLE;
+ DLOGD_IF(kTagDriverConfig, "kNoOp: HDR Stream: HDR_DISABLE");
+ } else {
+ return kErrorNone;
+ }
+ } else {
+ return kErrorNone;
+ }
+ }
+
+ int fd = Sys::open_(hdr_stream_path, O_WRONLY);
+ if (fd < 0) {
+ DLOGE("Failed to open %s with error %s", hdr_stream_path, strerror(errno));
+ return kErrorFileDescriptor;
+ }
+
+ const void *hdr_metadata = reinterpret_cast<const void*>(&hdr_ctrl);
+ ssize_t len = Sys::pwrite_(fd, hdr_metadata, sizeof(hdr_ctrl), 0);
+ if (len <= 0) {
+ DLOGE("Failed to write hdr_metadata");
+ error = kErrorUndefined;
+ }
+ Sys::close_(fd);
+#endif
+
+ return error;
+}
+
+} // namespace sdm
+