Home | History | Annotate | Download | only in fb
      1 /*
      2 * Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved.
      3 *
      4 * Redistribution and use in source and binary forms, with or without
      5 * modification, are permitted provided that the following conditions are
      6 * met:
      7 *     * Redistributions of source code must retain the above copyright
      8 *       notice, this list of conditions and the following disclaimer.
      9 *     * Redistributions in binary form must reproduce the above
     10 *       copyright notice, this list of conditions and the following
     11 *       disclaimer in the documentation and/or other materials provided
     12 *       with the distribution.
     13 *     * Neither the name of The Linux Foundation nor the names of its
     14 *       contributors may be used to endorse or promote products derived
     15 *       from this software without specific prior written permission.
     16 *
     17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 */
     29 
     30 #include <stdio.h>
     31 #include <unistd.h>
     32 #include <string.h>
     33 #include <sys/ioctl.h>
     34 #include <ctype.h>
     35 #include <fcntl.h>
     36 #include <linux/videodev2.h>
     37 #include <utils/debug.h>
     38 #include <utils/sys.h>
     39 #include <utils/formats.h>
     40 
     41 #include <vector>
     42 #include <map>
     43 #include <utility>
     44 
     45 #include "hw_hdmi.h"
     46 
     47 #define __CLASS__ "HWHDMI"
     48 
     49 namespace sdm {
     50 
     51 #ifdef MDP_HDR_STREAM
     52 static int32_t GetEOTF(const GammaTransfer &transfer) {
     53   int32_t mdp_transfer = -1;
     54 
     55   switch (transfer) {
     56   case Transfer_SMPTE_ST2084:
     57     mdp_transfer = MDP_HDR_EOTF_SMTPE_ST2084;
     58     break;
     59   case Transfer_HLG:
     60     mdp_transfer = MDP_HDR_EOTF_HLG;
     61     break;
     62   default:
     63     DLOGW("Unknown Transfer: %d", transfer);
     64   }
     65 
     66   return mdp_transfer;
     67 }
     68 
     69 static int32_t GetColoriMetry(const LayerBuffer & layer_buffer) {
     70   bool is_yuv = layer_buffer.flags.video;
     71   int32_t colorimetry = -1;
     72 
     73   if (is_yuv) {
     74     switch (layer_buffer.color_metadata.colorPrimaries) {
     75     case ColorPrimaries_BT601_6_525:
     76     case ColorPrimaries_BT601_6_625:
     77       colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_601;
     78       break;
     79     case ColorPrimaries_BT709_5:
     80       colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_709;
     81       break;
     82     case ColorPrimaries_BT2020:
     83       colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_2020_YCBCR;
     84       break;
     85     default:
     86       DLOGW("Unknown color primary = %d for YUV", layer_buffer.color_metadata.colorPrimaries);
     87     }
     88   }
     89 
     90   return colorimetry;
     91 }
     92 
     93 static int32_t GetPixelEncoding(const LayerBuffer &layer_buffer) {
     94   bool is_yuv = layer_buffer.flags.video;
     95   int32_t mdp_pixel_encoding = -1;
     96   mdp_pixel_encoding = MDP_PIXEL_ENCODING_RGB;  // set RGB as default
     97 
     98   if (is_yuv) {
     99     switch (layer_buffer.format) {
    100     case kFormatYCbCr420SemiPlanarVenus:
    101     case kFormatYCbCr420SPVenusUbwc:
    102     case kFormatYCbCr420Planar:
    103     case kFormatYCrCb420Planar:
    104     case kFormatYCrCb420PlanarStride16:
    105     case kFormatYCbCr420SemiPlanar:
    106     case kFormatYCrCb420SemiPlanar:
    107     case kFormatYCbCr420P010:
    108     case kFormatYCbCr420TP10Ubwc:
    109       mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_420;
    110       break;
    111     case kFormatYCbCr422H2V1Packed:
    112     case kFormatYCrCb422H2V1SemiPlanar:
    113     case kFormatYCrCb422H1V2SemiPlanar:
    114     case kFormatYCbCr422H2V1SemiPlanar:
    115     case kFormatYCbCr422H1V2SemiPlanar:
    116       mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_422;
    117       break;
    118     default:  // other yuv formats
    119       DLOGW("New YUV format = %d, need to add support", layer_buffer.format);
    120       break;
    121     }
    122   }
    123 
    124   return mdp_pixel_encoding;
    125 }
    126 static int32_t GetBitsPerComponent(const LayerBuffer &layer_buffer) {
    127   bool is_yuv = layer_buffer.flags.video;
    128   bool is_10_bit = Is10BitFormat(layer_buffer.format);
    129   int32_t mdp_bpc = -1;
    130 
    131   if (is_yuv) {
    132     mdp_bpc = is_10_bit ? MDP_YUV_10_BPC : MDP_YUV_8_BPC;
    133   } else {
    134     mdp_bpc = is_10_bit ? MDP_RGB_10_BPC : MDP_RGB_8_BPC;
    135   }
    136 
    137   return mdp_bpc;
    138 }
    139 
    140 static uint32_t GetRange(const ColorRange &range) {
    141   return ((range == Range_Full) ? MDP_DYNAMIC_RANGE_VESA : MDP_DYNAMIC_RANGE_CEA);
    142 }
    143 
    144 static uint32_t GetContentType(const LayerBuffer &layer_buffer) {
    145   return (layer_buffer.flags.video ? MDP_CONTENT_TYPE_VIDEO : MDP_CONTENT_TYPE_GRAPHICS);
    146 }
    147 #endif
    148 
    149 static bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
    150                                  fb_var_screeninfo *info) {
    151   if (!mode || !info) {
    152     return false;
    153   }
    154 
    155   info->reserved[0] = 0;
    156   info->reserved[1] = 0;
    157   info->reserved[2] = 0;
    158   info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16);
    159   info->xoffset = 0;
    160   info->yoffset = 0;
    161   info->xres = mode->active_h;
    162   info->yres = mode->active_v;
    163   info->pixclock = (mode->pixel_freq) * 1000;
    164   info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
    165   info->right_margin = mode->front_porch_h;
    166   info->hsync_len = mode->pulse_width_h;
    167   info->left_margin = mode->back_porch_h;
    168   info->lower_margin = mode->front_porch_v;
    169   info->vsync_len = mode->pulse_width_v;
    170   info->upper_margin = mode->back_porch_v;
    171 
    172   info->grayscale = V4L2_PIX_FMT_RGB24;
    173   // If the mode supports YUV420 set grayscale to the FOURCC value for YUV420.
    174   std::bitset<32> pixel_formats = mode->pixel_formats;
    175   if (pixel_formats[1]) {
    176     info->grayscale = V4L2_PIX_FMT_NV12;
    177   }
    178 
    179   if (!mode->active_low_h) {
    180     info->sync |= (uint32_t)FB_SYNC_HOR_HIGH_ACT;
    181   } else {
    182     info->sync &= (uint32_t)~FB_SYNC_HOR_HIGH_ACT;
    183   }
    184 
    185   if (!mode->active_low_v) {
    186     info->sync |= (uint32_t)FB_SYNC_VERT_HIGH_ACT;
    187   } else {
    188     info->sync &= (uint32_t)~FB_SYNC_VERT_HIGH_ACT;
    189   }
    190 
    191   return true;
    192 }
    193 
    194 HWHDMI::HWHDMI(BufferSyncHandler *buffer_sync_handler,  HWInfoInterface *hw_info_intf)
    195   : HWDevice(buffer_sync_handler), hw_scan_info_(), active_config_index_(0) {
    196   HWDevice::device_type_ = kDeviceHDMI;
    197   HWDevice::device_name_ = "HDMI Display Device";
    198   HWDevice::hw_info_intf_ = hw_info_intf;
    199 }
    200 
    201 DisplayError HWHDMI::Init() {
    202   DisplayError error = kErrorNone;
    203 
    204   SetSourceProductInformation("vendor_name", "ro.product.manufacturer");
    205   SetSourceProductInformation("product_description", "ro.product.name");
    206 
    207   error = HWDevice::Init();
    208   if (error != kErrorNone) {
    209     return error;
    210   }
    211 
    212   mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
    213 
    214   error = ReadEDIDInfo();
    215   if (error != kErrorNone) {
    216     Deinit();
    217     return error;
    218   }
    219 
    220   if (!IsResolutionFilePresent()) {
    221     Deinit();
    222     return kErrorHardware;
    223   }
    224 
    225   error = ReadTimingInfo();
    226   if (error != kErrorNone) {
    227     Deinit();
    228     return error;
    229   }
    230 
    231   ReadScanInfo();
    232 
    233   GetPanelS3DMode();
    234 
    235   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    236                              (kS3DModeNone, HDMI_S3D_NONE));
    237   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    238                              (kS3DModeLR, HDMI_S3D_SIDE_BY_SIDE));
    239   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    240                              (kS3DModeRL, HDMI_S3D_SIDE_BY_SIDE));
    241   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    242                              (kS3DModeTB, HDMI_S3D_TOP_AND_BOTTOM));
    243   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    244                              (kS3DModeFP, HDMI_S3D_FRAME_PACKING));
    245 
    246   return error;
    247 }
    248 
    249 DisplayError HWHDMI::GetNumDisplayAttributes(uint32_t *count) {
    250   *count = UINT32(hdmi_modes_.size());
    251   if (*count <= 0) {
    252     return kErrorHardware;
    253   }
    254 
    255   return kErrorNone;
    256 }
    257 
    258 DisplayError HWHDMI::GetActiveConfig(uint32_t *active_config_index) {
    259   *active_config_index = active_config_index_;
    260   return kErrorNone;
    261 }
    262 
    263 DisplayError HWHDMI::ReadEDIDInfo() {
    264   ssize_t length = -1;
    265   char edid_str[kPageSize] = {'\0'};
    266   char edid_path[kMaxStringLength] = {'\0'};
    267   snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_);
    268   int edid_file = Sys::open_(edid_path, O_RDONLY);
    269   if (edid_file < 0) {
    270     DLOGE("EDID file open failed.");
    271     return kErrorHardware;
    272   }
    273 
    274   length = Sys::pread_(edid_file, edid_str, sizeof(edid_str)-1, 0);
    275   if (length <= 0) {
    276     DLOGE("%s: edid_modes file empty");
    277     return kErrorHardware;
    278   }
    279   Sys::close_(edid_file);
    280 
    281   DLOGI("EDID mode string: %s", edid_str);
    282   while (length > 1 && isspace(edid_str[length-1])) {
    283     --length;
    284   }
    285   edid_str[length] = '\0';
    286 
    287   if (length > 0) {
    288     // Get EDID modes from the EDID string
    289     char *ptr = edid_str;
    290     const uint32_t edid_count_max = 128;
    291     char *tokens[edid_count_max] = { NULL };
    292     uint32_t hdmi_mode_count = 0;
    293 
    294     ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count);
    295 
    296     supported_video_modes_.resize(hdmi_mode_count);
    297 
    298     hdmi_modes_.resize(hdmi_mode_count);
    299     for (uint32_t i = 0; i < hdmi_mode_count; i++) {
    300       hdmi_modes_[i] = UINT32(atoi(tokens[i]));
    301     }
    302   }
    303 
    304   return kErrorNone;
    305 }
    306 
    307 DisplayError HWHDMI::GetDisplayAttributes(uint32_t index,
    308                                           HWDisplayAttributes *display_attributes) {
    309   DTRACE_SCOPED();
    310 
    311   if (index >= hdmi_modes_.size()) {
    312     return kErrorNotSupported;
    313   }
    314 
    315   // Get the resolution info from the look up table
    316   msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
    317   for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
    318     msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
    319     if (cur->video_format == hdmi_modes_[index]) {
    320       timing_mode = cur;
    321       break;
    322     }
    323   }
    324   display_attributes->x_pixels = timing_mode->active_h;
    325   display_attributes->y_pixels = timing_mode->active_v;
    326   display_attributes->v_front_porch = timing_mode->front_porch_v;
    327   display_attributes->v_back_porch = timing_mode->back_porch_v;
    328   display_attributes->v_pulse_width = timing_mode->pulse_width_v;
    329   uint32_t h_blanking = timing_mode->front_porch_h + timing_mode->back_porch_h +
    330       timing_mode->pulse_width_h;
    331   display_attributes->h_total = timing_mode->active_h + h_blanking;
    332   display_attributes->x_dpi = 0;
    333   display_attributes->y_dpi = 0;
    334   display_attributes->fps = timing_mode->refresh_rate / 1000;
    335   display_attributes->vsync_period_ns = UINT32(1000000000L / display_attributes->fps);
    336   display_attributes->is_device_split = false;
    337   if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
    338     display_attributes->is_device_split = true;
    339     display_attributes->h_total += h_blanking;
    340   }
    341 
    342   GetDisplayS3DSupport(index, display_attributes);
    343   std::bitset<32> pixel_formats = timing_mode->pixel_formats;
    344 
    345   display_attributes->is_yuv = pixel_formats[1];
    346 
    347   return kErrorNone;
    348 }
    349 
    350 DisplayError HWHDMI::SetDisplayAttributes(uint32_t index) {
    351   DTRACE_SCOPED();
    352 
    353   if (index > hdmi_modes_.size()) {
    354     return kErrorNotSupported;
    355   }
    356 
    357   // Variable screen info
    358   fb_var_screeninfo vscreeninfo = {};
    359   if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &vscreeninfo) < 0) {
    360     IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
    361     return kErrorHardware;
    362   }
    363 
    364   DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3],
    365         vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
    366         vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
    367         vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
    368 
    369   msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
    370   for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
    371     msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
    372     if (cur->video_format == hdmi_modes_[index]) {
    373       timing_mode = cur;
    374       break;
    375     }
    376   }
    377 
    378   if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) {
    379     return kErrorParameters;
    380   }
    381 
    382   msmfb_metadata metadata = {};
    383   metadata.op = metadata_op_vic;
    384   metadata.data.video_info_code = timing_mode->video_format;
    385   if (Sys::ioctl_(device_fd_, MSMFB_METADATA_SET, &metadata) < 0) {
    386     IOCTL_LOGE(MSMFB_METADATA_SET, device_type_);
    387     return kErrorHardware;
    388   }
    389 
    390   DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00,
    391         vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
    392         vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
    393         vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
    394 
    395   vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
    396   if (Sys::ioctl_(device_fd_, FBIOPUT_VSCREENINFO, &vscreeninfo) < 0) {
    397     IOCTL_LOGE(FBIOPUT_VSCREENINFO, device_type_);
    398     return kErrorHardware;
    399   }
    400 
    401   active_config_index_ = index;
    402 
    403   frame_rate_ = timing_mode->refresh_rate;
    404 
    405   // Get the display attributes for current active config index
    406   GetDisplayAttributes(active_config_index_, &display_attributes_);
    407   UpdateMixerAttributes();
    408 
    409   supported_s3d_modes_.clear();
    410   supported_s3d_modes_.push_back(kS3DModeNone);
    411   for (uint32_t mode = kS3DModeNone + 1; mode < kS3DModeMax; mode ++) {
    412     if (display_attributes_.s3d_config[(HWS3DMode)mode]) {
    413       supported_s3d_modes_.push_back((HWS3DMode)mode);
    414     }
    415   }
    416 
    417   SetS3DMode(kS3DModeNone);
    418 
    419   return kErrorNone;
    420 }
    421 
    422 DisplayError HWHDMI::GetConfigIndex(uint32_t mode, uint32_t *index) {
    423   // Check if the mode is valid and return corresponding index
    424   for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
    425     if (hdmi_modes_[i] == mode) {
    426       *index = i;
    427       DLOGI("Index = %d for config = %d", *index, mode);
    428       return kErrorNone;
    429     }
    430   }
    431 
    432   DLOGE("Config = %d not supported", mode);
    433   return kErrorNotSupported;
    434 }
    435 
    436 DisplayError HWHDMI::Validate(HWLayers *hw_layers) {
    437   HWDevice::ResetDisplayParams();
    438   return HWDevice::Validate(hw_layers);
    439 }
    440 
    441 DisplayError HWHDMI::Commit(HWLayers *hw_layers) {
    442   DisplayError error = UpdateHDRMetaData(hw_layers);
    443   if (error != kErrorNone) {
    444     return error;
    445   }
    446 
    447   return HWDevice::Commit(hw_layers);
    448 }
    449 
    450 DisplayError HWHDMI::GetHWScanInfo(HWScanInfo *scan_info) {
    451   if (!scan_info) {
    452     return kErrorParameters;
    453   }
    454   *scan_info = hw_scan_info_;
    455   return kErrorNone;
    456 }
    457 
    458 DisplayError HWHDMI::GetVideoFormat(uint32_t config_index, uint32_t *video_format) {
    459   if (config_index > hdmi_modes_.size()) {
    460     return kErrorNotSupported;
    461   }
    462 
    463   *video_format = hdmi_modes_[config_index];
    464 
    465   return kErrorNone;
    466 }
    467 
    468 DisplayError HWHDMI::GetMaxCEAFormat(uint32_t *max_cea_format) {
    469   *max_cea_format = HDMI_VFRMT_END;
    470 
    471   return kErrorNone;
    472 }
    473 
    474 DisplayError HWHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
    475   DisplayError error = kErrorNone;
    476   int fd = -1;
    477   char data[kMaxStringLength] = {'\0'};
    478 
    479   snprintf(data, sizeof(data), "%s%d/hdcp2p2/min_level_change", fb_path_, fb_node_index_);
    480 
    481   fd = Sys::open_(data, O_WRONLY);
    482   if (fd < 0) {
    483     DLOGW("File '%s' could not be opened.", data);
    484     return kErrorHardware;
    485   }
    486 
    487   snprintf(data, sizeof(data), "%d", min_enc_level);
    488 
    489   ssize_t err = Sys::pwrite_(fd, data, strlen(data), 0);
    490   if (err <= 0) {
    491     DLOGE("Write failed, Error = %s", strerror(errno));
    492     error = kErrorHardware;
    493   }
    494 
    495   Sys::close_(fd);
    496 
    497   return error;
    498 }
    499 
    500 HWScanSupport HWHDMI::MapHWScanSupport(uint32_t value) {
    501   switch (value) {
    502   // TODO(user): Read the scan type from driver defined values instead of hardcoding
    503   case 0:
    504     return kScanNotSupported;
    505   case 1:
    506     return kScanAlwaysOverscanned;
    507   case 2:
    508     return kScanAlwaysUnderscanned;
    509   case 3:
    510     return kScanBoth;
    511   default:
    512     return kScanNotSupported;
    513     break;
    514   }
    515 }
    516 
    517 void HWHDMI::ReadScanInfo() {
    518   int scan_info_file = -1;
    519   ssize_t len = -1;
    520   char data[kPageSize] = {'\0'};
    521 
    522   snprintf(data, sizeof(data), "%s%d/scan_info", fb_path_, fb_node_index_);
    523   scan_info_file = Sys::open_(data, O_RDONLY);
    524   if (scan_info_file < 0) {
    525     DLOGW("File '%s' not found.", data);
    526     return;
    527   }
    528 
    529   memset(&data[0], 0, sizeof(data));
    530   len = Sys::pread_(scan_info_file, data, sizeof(data) - 1, 0);
    531   if (len <= 0) {
    532     Sys::close_(scan_info_file);
    533     DLOGW("File %s%d/scan_info is empty.", fb_path_, fb_node_index_);
    534     return;
    535   }
    536   data[len] = '\0';
    537   Sys::close_(scan_info_file);
    538 
    539   const uint32_t scan_info_max_count = 3;
    540   uint32_t scan_info_count = 0;
    541   char *tokens[scan_info_max_count] = { NULL };
    542   ParseLine(data, tokens, scan_info_max_count, &scan_info_count);
    543   if (scan_info_count != scan_info_max_count) {
    544     DLOGW("Failed to parse scan info string %s", data);
    545     return;
    546   }
    547 
    548   hw_scan_info_.pt_scan_support = MapHWScanSupport(UINT32(atoi(tokens[0])));
    549   hw_scan_info_.it_scan_support = MapHWScanSupport(UINT32(atoi(tokens[1])));
    550   hw_scan_info_.cea_scan_support = MapHWScanSupport(UINT32(atoi(tokens[2])));
    551   DLOGI("PT %d IT %d CEA %d", hw_scan_info_.pt_scan_support, hw_scan_info_.it_scan_support,
    552         hw_scan_info_.cea_scan_support);
    553 }
    554 
    555 int HWHDMI::OpenResolutionFile(int file_mode) {
    556   char file_path[kMaxStringLength];
    557   memset(file_path, 0, sizeof(file_path));
    558   snprintf(file_path , sizeof(file_path), "%s%d/res_info", fb_path_, fb_node_index_);
    559 
    560   int fd = Sys::open_(file_path, file_mode);
    561 
    562   if (fd < 0) {
    563     DLOGE("file '%s' not found : ret = %d err str: %s", file_path, fd, strerror(errno));
    564   }
    565 
    566   return fd;
    567 }
    568 
    569 // Method to request HDMI driver to write a new page of timing info into res_info node
    570 void HWHDMI::RequestNewPage(uint32_t page_number) {
    571   char page_string[kPageSize];
    572   int fd = OpenResolutionFile(O_WRONLY);
    573   if (fd < 0) {
    574     return;
    575   }
    576 
    577   snprintf(page_string, sizeof(page_string), "%d", page_number);
    578 
    579   DLOGI_IF(kTagDriverConfig, "page=%s", page_string);
    580 
    581   ssize_t err = Sys::pwrite_(fd, page_string, sizeof(page_string), 0);
    582   if (err <= 0) {
    583     DLOGE("Write to res_info failed (%s)", strerror(errno));
    584   }
    585 
    586   Sys::close_(fd);
    587 }
    588 
    589 // Reads the contents of res_info node into a buffer if the file is not empty
    590 bool HWHDMI::ReadResolutionFile(char *config_buffer) {
    591   ssize_t bytes_read = 0;
    592   int fd = OpenResolutionFile(O_RDONLY);
    593   if (fd >= 0) {
    594     bytes_read = Sys::pread_(fd, config_buffer, kPageSize, 0);
    595     Sys::close_(fd);
    596   }
    597 
    598   DLOGI_IF(kTagDriverConfig, "bytes_read = %d", bytes_read);
    599 
    600   return (bytes_read > 0);
    601 }
    602 
    603 // Populates the internal timing info structure with the timing info obtained
    604 // from the HDMI driver
    605 DisplayError HWHDMI::ReadTimingInfo() {
    606   uint32_t config_index = 0;
    607   uint32_t page_number = MSM_HDMI_INIT_RES_PAGE;
    608   uint32_t size = sizeof(msm_hdmi_mode_timing_info);
    609 
    610   while (true) {
    611     char config_buffer[kPageSize] = {0};
    612     msm_hdmi_mode_timing_info *info = reinterpret_cast<msm_hdmi_mode_timing_info *>(config_buffer);
    613     RequestNewPage(page_number);
    614 
    615     if (!ReadResolutionFile(config_buffer)) {
    616       break;
    617     }
    618 
    619     while (info->video_format && size < kPageSize && config_index < hdmi_modes_.size()) {
    620       supported_video_modes_[config_index] = *info;
    621       size += sizeof(msm_hdmi_mode_timing_info);
    622 
    623       DLOGI_IF(kTagDriverConfig, "Config=%d Mode %d: (%dx%d) @ %d, pixel formats %d",
    624                config_index,
    625                supported_video_modes_[config_index].video_format,
    626                supported_video_modes_[config_index].active_h,
    627                supported_video_modes_[config_index].active_v,
    628                supported_video_modes_[config_index].refresh_rate,
    629                supported_video_modes_[config_index].pixel_formats);
    630 
    631       info++;
    632       config_index++;
    633     }
    634 
    635     size = sizeof(msm_hdmi_mode_timing_info);
    636     // Request HDMI driver to populate res_info with more
    637     // timing information
    638     page_number++;
    639   }
    640 
    641   if (page_number == MSM_HDMI_INIT_RES_PAGE || config_index == 0) {
    642     DLOGE("No timing information found.");
    643     return kErrorHardware;
    644   }
    645 
    646   return kErrorNone;
    647 }
    648 
    649 bool HWHDMI::IsResolutionFilePresent() {
    650   bool is_file_present = false;
    651   int fd = OpenResolutionFile(O_RDONLY);
    652   if (fd >= 0) {
    653     is_file_present = true;
    654     Sys::close_(fd);
    655   }
    656 
    657   return is_file_present;
    658 }
    659 
    660 void HWHDMI::SetSourceProductInformation(const char *node, const char *name) {
    661   char property_value[kMaxStringLength];
    662   char sys_fs_path[kMaxStringLength];
    663   int hdmi_node_index = GetFBNodeIndex(kDeviceHDMI);
    664   if (hdmi_node_index < 0) {
    665     return;
    666   }
    667 
    668   ssize_t length = 0;
    669   bool prop_read_success = Debug::GetProperty(name, property_value);
    670   if (!prop_read_success) {
    671     return;
    672   }
    673 
    674   snprintf(sys_fs_path , sizeof(sys_fs_path), "%s%d/%s", fb_path_, hdmi_node_index, node);
    675   length = HWDevice::SysFsWrite(sys_fs_path, property_value,
    676                                 static_cast<ssize_t>(strlen(property_value)));
    677   if (length <= 0) {
    678     DLOGW("Failed to write %s = %s", node, property_value);
    679   }
    680 }
    681 
    682 DisplayError HWHDMI::GetDisplayS3DSupport(uint32_t index,
    683                                           HWDisplayAttributes *attrib) {
    684   ssize_t length = -1;
    685   char edid_s3d_str[kPageSize] = {'\0'};
    686   char edid_s3d_path[kMaxStringLength] = {'\0'};
    687   snprintf(edid_s3d_path, sizeof(edid_s3d_path), "%s%d/edid_3d_modes", fb_path_, fb_node_index_);
    688 
    689   if (index > hdmi_modes_.size()) {
    690     return kErrorNotSupported;
    691   }
    692 
    693   attrib->s3d_config[kS3DModeNone] = 1;
    694 
    695   // Three level inception!
    696   // The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH
    697   // Initialize all the pointers to NULL to avoid crash in function strtok_r()
    698   char *saveptr_l1 = NULL, *saveptr_l2 = NULL, *saveptr_l3 = NULL;
    699   char *l1 = NULL, *l2 = NULL, *l3 = NULL;
    700 
    701   int edid_s3d_node = Sys::open_(edid_s3d_path, O_RDONLY);
    702   if (edid_s3d_node < 0) {
    703     DLOGW("%s could not be opened : %s", edid_s3d_path, strerror(errno));
    704     return kErrorNotSupported;
    705   }
    706 
    707   length = Sys::pread_(edid_s3d_node, edid_s3d_str, sizeof(edid_s3d_str)-1, 0);
    708   if (length <= 0) {
    709     Sys::close_(edid_s3d_node);
    710     return kErrorNotSupported;
    711   }
    712 
    713   l1 = strtok_r(edid_s3d_str, ",", &saveptr_l1);
    714   while (l1 != NULL) {
    715     l2 = strtok_r(l1, "=", &saveptr_l2);
    716     if (l2 != NULL) {
    717       if (hdmi_modes_[index] == (uint32_t)atoi(l2)) {
    718           l3 = strtok_r(saveptr_l2, ":", &saveptr_l3);
    719           while (l3 != NULL) {
    720             if (strncmp("SSH", l3, strlen("SSH")) == 0) {
    721               attrib->s3d_config[kS3DModeLR] = 1;
    722               attrib->s3d_config[kS3DModeRL] = 1;
    723             } else if (strncmp("TAB", l3, strlen("TAB")) == 0) {
    724               attrib->s3d_config[kS3DModeTB] = 1;
    725             } else if (strncmp("FP", l3, strlen("FP")) == 0) {
    726               attrib->s3d_config[kS3DModeFP] = 1;
    727             }
    728             l3 = strtok_r(NULL, ":", &saveptr_l3);
    729           }
    730       }
    731     }
    732     l1 = strtok_r(NULL, ",", &saveptr_l1);
    733   }
    734 
    735   Sys::close_(edid_s3d_node);
    736   return kErrorNone;
    737 }
    738 
    739 bool HWHDMI::IsSupportedS3DMode(HWS3DMode s3d_mode) {
    740   for (uint32_t i = 0; i < supported_s3d_modes_.size(); i++) {
    741     if (supported_s3d_modes_[i] == s3d_mode) {
    742       return true;
    743     }
    744   }
    745   return false;
    746 }
    747 
    748 DisplayError HWHDMI::SetS3DMode(HWS3DMode s3d_mode) {
    749   if (!IsSupportedS3DMode(s3d_mode)) {
    750     DLOGW("S3D mode is not supported s3d_mode = %d", s3d_mode);
    751     return kErrorNotSupported;
    752   }
    753 
    754   std::map<HWS3DMode, msm_hdmi_s3d_mode>::iterator it = s3d_mode_sdm_to_mdp_.find(s3d_mode);
    755   if (it == s3d_mode_sdm_to_mdp_.end()) {
    756     return kErrorNotSupported;
    757   }
    758   msm_hdmi_s3d_mode s3d_mdp_mode = it->second;
    759 
    760   if (active_mdp_s3d_mode_ == s3d_mdp_mode) {
    761     // HDMI_S3D_SIDE_BY_SIDE is an mdp mapping for kS3DModeLR and kS3DModeRL s3d modes. So no need
    762     // to update the s3d_mode node. hw_panel_info needs to be updated to differentiate these two s3d
    763     // modes in strategy
    764     hw_panel_info_.s3d_mode = s3d_mode;
    765     return kErrorNone;
    766   }
    767 
    768   ssize_t length = -1;
    769   char s3d_mode_path[kMaxStringLength] = {'\0'};
    770   char s3d_mode_string[kMaxStringLength] = {'\0'};
    771   snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_);
    772 
    773   int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR);
    774   if (s3d_mode_node < 0) {
    775     DLOGW("%s could not be opened : %s", s3d_mode_path, strerror(errno));
    776     return kErrorNotSupported;
    777   }
    778 
    779   snprintf(s3d_mode_string, sizeof(s3d_mode_string), "%d", s3d_mdp_mode);
    780   length = Sys::pwrite_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0);
    781   if (length <= 0) {
    782     DLOGW("Failed to write into s3d node: %s", strerror(errno));
    783     Sys::close_(s3d_mode_node);
    784     return kErrorNotSupported;
    785   }
    786 
    787   active_mdp_s3d_mode_ = s3d_mdp_mode;
    788   hw_panel_info_.s3d_mode = s3d_mode;
    789   Sys::close_(s3d_mode_node);
    790 
    791   DLOGI_IF(kTagDriverConfig, "Set s3d mode %d", hw_panel_info_.s3d_mode);
    792   return kErrorNone;
    793 }
    794 
    795 DisplayError HWHDMI::GetPanelS3DMode() {
    796   ssize_t length = -1;
    797   char s3d_mode_path[kMaxStringLength] = {'\0'};
    798   char s3d_mode_string[kMaxStringLength] = {'\0'};
    799   snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_);
    800   int panel_s3d_mode = 0;
    801 
    802   int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR);
    803   if (s3d_mode_node < 0) {
    804     DLOGE("%s could not be opened : %s", s3d_mode_path, strerror(errno));
    805     return kErrorNotSupported;
    806   }
    807 
    808   length = Sys::pread_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0);
    809   if (length <= 0) {
    810     DLOGE("Failed read s3d node: %s", strerror(errno));
    811     Sys::close_(s3d_mode_node);
    812     return kErrorNotSupported;
    813   }
    814 
    815   panel_s3d_mode = atoi(s3d_mode_string);
    816   if (panel_s3d_mode < HDMI_S3D_NONE || panel_s3d_mode >= HDMI_S3D_MAX) {
    817     Sys::close_(s3d_mode_node);
    818     DLOGW("HDMI panel S3D mode is not supported panel_s3d_mode = %d", panel_s3d_mode);
    819     return kErrorUndefined;
    820   }
    821 
    822   active_mdp_s3d_mode_  = static_cast<msm_hdmi_s3d_mode>(panel_s3d_mode);
    823   Sys::close_(s3d_mode_node);
    824 
    825   DLOGI_IF(kTagDriverConfig, "Get HDMI panel s3d mode %d", active_mdp_s3d_mode_);
    826   return kErrorNone;
    827 }
    828 
    829 DisplayError HWHDMI::GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t *mode,
    830                                              DynamicFPSData *data, uint32_t *config_index) {
    831   msm_hdmi_mode_timing_info *cur = NULL;
    832   msm_hdmi_mode_timing_info *dst = NULL;
    833   uint32_t i = 0;
    834   int pre_refresh_rate_diff = 0;
    835   bool pre_unstd_mode = false;
    836 
    837   for (i = 0; i < hdmi_modes_.size(); i++) {
    838     msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i];
    839     if (timing_mode->video_format == hdmi_modes_[active_config_index_]) {
    840       cur = timing_mode;
    841       break;
    842     }
    843   }
    844 
    845   if (cur == NULL) {
    846     DLOGE("can't find timing info for active config index(%d)", active_config_index_);
    847     return kErrorUndefined;
    848   }
    849 
    850   if (cur->refresh_rate != frame_rate_) {
    851     pre_unstd_mode = true;
    852   }
    853 
    854   if (i >= hdmi_modes_.size()) {
    855     return kErrorNotSupported;
    856   }
    857 
    858   dst = cur;
    859   pre_refresh_rate_diff = static_cast<int>(dst->refresh_rate) - static_cast<int>(refresh_rate);
    860 
    861   for (i = 0; i < hdmi_modes_.size(); i++) {
    862     msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i];
    863     if (cur->active_h == timing_mode->active_h &&
    864        cur->active_v == timing_mode->active_v &&
    865        cur->pixel_formats == timing_mode->pixel_formats ) {
    866       int cur_refresh_rate_diff = static_cast<int>(timing_mode->refresh_rate) -
    867                                   static_cast<int>(refresh_rate);
    868       if (abs(pre_refresh_rate_diff) > abs(cur_refresh_rate_diff)) {
    869         pre_refresh_rate_diff = cur_refresh_rate_diff;
    870         dst = timing_mode;
    871       }
    872     }
    873   }
    874 
    875   if (pre_refresh_rate_diff > kThresholdRefreshRate) {
    876     return kErrorNotSupported;
    877   }
    878 
    879   GetConfigIndex(dst->video_format, config_index);
    880 
    881   data->hor_front_porch = dst->front_porch_h;
    882   data->hor_back_porch = dst->back_porch_h;
    883   data->hor_pulse_width = dst->pulse_width_h;
    884   data->clk_rate_hz = dst->pixel_freq;
    885   data->fps = refresh_rate;
    886 
    887   if (dst->front_porch_h != cur->front_porch_h) {
    888     *mode = kModeHFP;
    889   }
    890 
    891   if (dst->refresh_rate != refresh_rate || dst->pixel_freq != cur->pixel_freq) {
    892     if (*mode == kModeHFP) {
    893       if (dst->refresh_rate != refresh_rate) {
    894         *mode = kModeHFPCalcClock;
    895       } else {
    896         *mode = kModeClockHFP;
    897       }
    898     } else {
    899         *mode = kModeClock;
    900     }
    901   }
    902 
    903   if (pre_unstd_mode && (*mode == kModeHFP)) {
    904     *mode = kModeClockHFP;
    905   }
    906 
    907   return kErrorNone;
    908 }
    909 
    910 DisplayError HWHDMI::SetRefreshRate(uint32_t refresh_rate) {
    911   char mode_path[kMaxStringLength] = {0};
    912   char node_path[kMaxStringLength] = {0};
    913   uint32_t mode = kModeClock;
    914   uint32_t config_index = 0;
    915   DynamicFPSData data;
    916   DisplayError error = kErrorNone;
    917 
    918   if (refresh_rate == frame_rate_) {
    919     return error;
    920   }
    921 
    922   error = GetDynamicFrameRateMode(refresh_rate, &mode, &data, &config_index);
    923   if (error != kErrorNone) {
    924     return error;
    925   }
    926 
    927   snprintf(mode_path, sizeof(mode_path), "%s%d/msm_fb_dfps_mode", fb_path_, fb_node_index_);
    928   snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
    929 
    930   int fd_mode = Sys::open_(mode_path, O_WRONLY);
    931   if (fd_mode < 0) {
    932     DLOGE("Failed to open %s with error %s", mode_path, strerror(errno));
    933     return kErrorFileDescriptor;
    934   }
    935 
    936   char dfps_mode[kMaxStringLength];
    937   snprintf(dfps_mode, sizeof(dfps_mode), "%d", mode);
    938   DLOGI_IF(kTagDriverConfig, "Setting dfps_mode  = %d", mode);
    939   ssize_t len = Sys::pwrite_(fd_mode, dfps_mode, strlen(dfps_mode), 0);
    940   if (len < 0) {
    941     DLOGE("Failed to enable dfps mode %d with error %s", mode, strerror(errno));
    942     Sys::close_(fd_mode);
    943     return kErrorUndefined;
    944   }
    945   Sys::close_(fd_mode);
    946 
    947   int fd_node = Sys::open_(node_path, O_WRONLY);
    948   if (fd_node < 0) {
    949     DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
    950     return kErrorFileDescriptor;
    951   }
    952 
    953   char refresh_rate_string[kMaxStringLength];
    954   if (mode == kModeHFP || mode == kModeClock) {
    955     snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", data.fps);
    956     DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", data.fps);
    957   } else {
    958     snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d %d %d %d %d",
    959              data.hor_front_porch, data.hor_back_porch, data.hor_pulse_width,
    960              data.clk_rate_hz, data.fps);
    961   }
    962   len = Sys::pwrite_(fd_node, refresh_rate_string, strlen(refresh_rate_string), 0);
    963   if (len < 0) {
    964     DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
    965     Sys::close_(fd_node);
    966     return kErrorUndefined;
    967   }
    968   Sys::close_(fd_node);
    969 
    970   error = ReadTimingInfo();
    971   if (error != kErrorNone) {
    972     return error;
    973   }
    974 
    975   GetDisplayAttributes(config_index, &display_attributes_);
    976   UpdateMixerAttributes();
    977 
    978   frame_rate_ = refresh_rate;
    979   active_config_index_ = config_index;
    980 
    981   DLOGI_IF(kTagDriverConfig, "config_index(%d) Mode(%d) frame_rate(%d)",
    982            config_index,
    983            mode,
    984            frame_rate_);
    985 
    986   return kErrorNone;
    987 }
    988 
    989 void HWHDMI::UpdateMixerAttributes() {
    990   mixer_attributes_.width = display_attributes_.x_pixels;
    991   mixer_attributes_.height = display_attributes_.y_pixels;
    992   mixer_attributes_.split_left = display_attributes_.is_device_split ?
    993       (display_attributes_.x_pixels / 2) : mixer_attributes_.width;
    994 }
    995 
    996 DisplayError HWHDMI::UpdateHDRMetaData(HWLayers *hw_layers) {
    997   const HWHDRLayerInfo &hdr_layer_info = hw_layers->info.hdr_layer_info;
    998   if (!hw_panel_info_.hdr_enabled || hdr_layer_info.operation == HWHDRLayerInfo::kNoOp) {
    999     return kErrorNone;
   1000   }
   1001 
   1002   DisplayError error = kErrorNone;
   1003 
   1004 #ifdef MDP_HDR_STREAM
   1005   char hdr_stream_path[kMaxStringLength] = {};
   1006   snprintf(hdr_stream_path, sizeof(hdr_stream_path), "%s%d/hdr_stream", fb_path_, fb_node_index_);
   1007 
   1008   int fd = Sys::open_(hdr_stream_path, O_WRONLY);
   1009   if (fd < 0) {
   1010     DLOGE("Failed to open %s with error %s", hdr_stream_path, strerror(errno));
   1011     return kErrorFileDescriptor;
   1012   }
   1013 
   1014   Layer hdr_layer = {};
   1015   if (hdr_layer_info.operation == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) {
   1016     hdr_layer = *(hw_layers->info.stack->layers.at(UINT32(hdr_layer_info.layer_index)));
   1017   }
   1018 
   1019   const LayerBuffer *layer_buffer = &hdr_layer.input_buffer;
   1020   const MasteringDisplay &mastering_display = layer_buffer->color_metadata.masteringDisplayInfo;
   1021   const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel;
   1022   const Primaries &primaries = mastering_display.primaries;
   1023 
   1024   mdp_hdr_stream hdr_stream = {};
   1025   if (hdr_layer_info.operation == HWHDRLayerInfo::kSet) {
   1026     int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer);
   1027     hdr_stream.eotf = (eotf < 0) ? 0 : UINT32(eotf);
   1028     hdr_stream.white_point_x = primaries.whitePoint[0];
   1029     hdr_stream.white_point_y = primaries.whitePoint[1];
   1030     hdr_stream.display_primaries_x[0] = primaries.rgbPrimaries[0][0];
   1031     hdr_stream.display_primaries_y[0] = primaries.rgbPrimaries[0][1];
   1032     hdr_stream.display_primaries_x[1] = primaries.rgbPrimaries[1][0];
   1033     hdr_stream.display_primaries_y[1] = primaries.rgbPrimaries[1][1];
   1034     hdr_stream.display_primaries_x[2] = primaries.rgbPrimaries[2][0];
   1035     hdr_stream.display_primaries_y[2] = primaries.rgbPrimaries[2][1];
   1036     hdr_stream.min_luminance = mastering_display.minDisplayLuminance;
   1037     hdr_stream.max_luminance = mastering_display.maxDisplayLuminance/10000;
   1038     hdr_stream.max_content_light_level = light_level.maxContentLightLevel;
   1039     hdr_stream.max_average_light_level = light_level.minPicAverageLightLevel;
   1040     // DP related
   1041     int32_t pixel_encoding = GetPixelEncoding(hdr_layer.input_buffer);
   1042     hdr_stream.pixel_encoding = (pixel_encoding < 0) ? 0 : UINT32(pixel_encoding);
   1043     int32_t colorimetry = GetColoriMetry(hdr_layer.input_buffer);
   1044     hdr_stream.colorimetry = (colorimetry < 0) ? 0 : UINT32(colorimetry);
   1045     hdr_stream.range = GetRange(hdr_layer.input_buffer.color_metadata.range);
   1046     int32_t bits_per_component = GetBitsPerComponent(hdr_layer.input_buffer);
   1047     hdr_stream.bits_per_component = (bits_per_component  < 0) ? 0 : UINT32(bits_per_component);
   1048     hdr_stream.content_type = GetContentType(hdr_layer.input_buffer);
   1049 
   1050     DLOGV_IF(kTagDriverConfig, "HDR Stream : MaxDisplayLuminance = %d MinDisplayLuminance = %d\n"
   1051       "MaxContentLightLevel = %d MaxAverageLightLevel = %d Red_x = %d Red_y = %d Green_x = %d\n"
   1052       "Green_y = %d Blue_x = %d Blue_y = %d WhitePoint_x = %d WhitePoint_y = %d EOTF = %d\n"
   1053       "PixelEncoding = %d Colorimetry = %d Range = %d BPC = %d ContentType = %d",
   1054       hdr_stream.max_luminance, hdr_stream.min_luminance, hdr_stream.max_content_light_level,
   1055       hdr_stream.max_average_light_level, hdr_stream.display_primaries_x[0],
   1056       hdr_stream.display_primaries_y[0], hdr_stream.display_primaries_x[1],
   1057       hdr_stream.display_primaries_y[1], hdr_stream.display_primaries_x[2],
   1058       hdr_stream.display_primaries_y[2], hdr_stream.white_point_x, hdr_stream.white_point_x,
   1059       hdr_stream.eotf, hdr_stream.pixel_encoding, hdr_stream.colorimetry, hdr_stream.range,
   1060       hdr_stream.bits_per_component, hdr_stream.content_type);
   1061   }
   1062 
   1063   const void *hdr_metadata = reinterpret_cast<const void*>(&hdr_stream);
   1064   ssize_t len = Sys::pwrite_(fd, hdr_metadata, sizeof(hdr_stream), 0);
   1065   if (len <= 0) {
   1066     DLOGE("Failed to write hdr_metadata");
   1067     error = kErrorUndefined;
   1068   }
   1069   Sys::close_(fd);
   1070 #endif
   1071 
   1072   return error;
   1073 }
   1074 
   1075 }  // namespace sdm
   1076 
   1077