Home | History | Annotate | Download | only in fb
      1 /*
      2 * Copyright (c) 2015 - 2016, 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 <vector>
     40 #include <map>
     41 #include <utility>
     42 
     43 #include "hw_hdmi.h"
     44 
     45 #define __CLASS__ "HWHDMI"
     46 
     47 namespace sdm {
     48 
     49 static bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
     50                                  fb_var_screeninfo *info) {
     51   if (!mode || !info) {
     52     return false;
     53   }
     54 
     55   info->reserved[0] = 0;
     56   info->reserved[1] = 0;
     57   info->reserved[2] = 0;
     58   info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16);
     59   info->xoffset = 0;
     60   info->yoffset = 0;
     61   info->xres = mode->active_h;
     62   info->yres = mode->active_v;
     63   info->pixclock = (mode->pixel_freq) * 1000;
     64   info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
     65   info->right_margin = mode->front_porch_h;
     66   info->hsync_len = mode->pulse_width_h;
     67   info->left_margin = mode->back_porch_h;
     68   info->lower_margin = mode->front_porch_v;
     69   info->vsync_len = mode->pulse_width_v;
     70   info->upper_margin = mode->back_porch_v;
     71 
     72   info->grayscale = V4L2_PIX_FMT_RGB24;
     73   // If the mode supports YUV420 set grayscale to the FOURCC value for YUV420.
     74   std::bitset<32> pixel_formats = mode->pixel_formats;
     75   if (pixel_formats[1]) {
     76     info->grayscale = V4L2_PIX_FMT_NV12;
     77   }
     78 
     79   return true;
     80 }
     81 
     82 DisplayError HWHDMI::Create(HWInterface **intf, HWInfoInterface *hw_info_intf,
     83                             BufferSyncHandler *buffer_sync_handler) {
     84   DisplayError error = kErrorNone;
     85   HWHDMI *hw_fb_hdmi = NULL;
     86 
     87   hw_fb_hdmi = new HWHDMI(buffer_sync_handler, hw_info_intf);
     88   error = hw_fb_hdmi->Init();
     89   if (error != kErrorNone) {
     90     delete hw_fb_hdmi;
     91   } else {
     92     *intf = hw_fb_hdmi;
     93   }
     94   return error;
     95 }
     96 
     97 DisplayError HWHDMI::Destroy(HWInterface *intf) {
     98   HWHDMI *hw_fb_hdmi = static_cast<HWHDMI *>(intf);
     99   hw_fb_hdmi->Deinit();
    100   delete hw_fb_hdmi;
    101 
    102   return kErrorNone;
    103 }
    104 
    105 HWHDMI::HWHDMI(BufferSyncHandler *buffer_sync_handler,  HWInfoInterface *hw_info_intf)
    106   : HWDevice(buffer_sync_handler), hw_scan_info_(), active_config_index_(0) {
    107   HWDevice::device_type_ = kDeviceHDMI;
    108   HWDevice::device_name_ = "HDMI Display Device";
    109   HWDevice::hw_info_intf_ = hw_info_intf;
    110 }
    111 
    112 DisplayError HWHDMI::Init() {
    113   DisplayError error = kErrorNone;
    114 
    115   SetSourceProductInformation("vendor_name", "ro.product.manufacturer");
    116   SetSourceProductInformation("product_description", "ro.product.name");
    117 
    118   error = HWDevice::Init();
    119   if (error != kErrorNone) {
    120     return error;
    121   }
    122 
    123   mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
    124 
    125   error = ReadEDIDInfo();
    126   if (error != kErrorNone) {
    127     Deinit();
    128     return error;
    129   }
    130 
    131   if (!IsResolutionFilePresent()) {
    132     Deinit();
    133     return kErrorHardware;
    134   }
    135 
    136   error = ReadTimingInfo();
    137   if (error != kErrorNone) {
    138     Deinit();
    139     return error;
    140   }
    141 
    142   ReadScanInfo();
    143 
    144   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    145                              (kS3DModeNone, HDMI_S3D_NONE));
    146   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    147                              (kS3DModeLR, HDMI_S3D_SIDE_BY_SIDE));
    148   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    149                              (kS3DModeRL, HDMI_S3D_SIDE_BY_SIDE));
    150   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    151                              (kS3DModeTB, HDMI_S3D_TOP_AND_BOTTOM));
    152   s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode>
    153                              (kS3DModeFP, HDMI_S3D_FRAME_PACKING));
    154 
    155   return error;
    156 }
    157 
    158 DisplayError HWHDMI::Deinit() {
    159   return HWDevice::Deinit();
    160 }
    161 
    162 DisplayError HWHDMI::GetNumDisplayAttributes(uint32_t *count) {
    163   *count = UINT32(hdmi_modes_.size());
    164   if (*count <= 0) {
    165     return kErrorHardware;
    166   }
    167 
    168   return kErrorNone;
    169 }
    170 
    171 DisplayError HWHDMI::GetActiveConfig(uint32_t *active_config_index) {
    172   *active_config_index = active_config_index_;
    173   return kErrorNone;
    174 }
    175 
    176 DisplayError HWHDMI::ReadEDIDInfo() {
    177   ssize_t length = -1;
    178   char edid_str[kPageSize] = {'\0'};
    179   char edid_path[kMaxStringLength] = {'\0'};
    180   snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_);
    181   int edid_file = Sys::open_(edid_path, O_RDONLY);
    182   if (edid_file < 0) {
    183     DLOGE("EDID file open failed.");
    184     return kErrorHardware;
    185   }
    186 
    187   length = Sys::pread_(edid_file, edid_str, sizeof(edid_str)-1, 0);
    188   if (length <= 0) {
    189     DLOGE("%s: edid_modes file empty");
    190     return kErrorHardware;
    191   }
    192   Sys::close_(edid_file);
    193 
    194   DLOGI("EDID mode string: %s", edid_str);
    195   while (length > 1 && isspace(edid_str[length-1])) {
    196     --length;
    197   }
    198   edid_str[length] = '\0';
    199 
    200   if (length > 0) {
    201     // Get EDID modes from the EDID string
    202     char *ptr = edid_str;
    203     const uint32_t edid_count_max = 128;
    204     char *tokens[edid_count_max] = { NULL };
    205     uint32_t hdmi_mode_count = 0;
    206 
    207     ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count);
    208 
    209     supported_video_modes_.resize(hdmi_mode_count);
    210 
    211     hdmi_modes_.resize(hdmi_mode_count);
    212     for (uint32_t i = 0; i < hdmi_mode_count; i++) {
    213       hdmi_modes_[i] = UINT32(atoi(tokens[i]));
    214     }
    215   }
    216 
    217   return kErrorNone;
    218 }
    219 
    220 DisplayError HWHDMI::GetDisplayAttributes(uint32_t index,
    221                                           HWDisplayAttributes *display_attributes) {
    222   DTRACE_SCOPED();
    223 
    224   if (index >= hdmi_modes_.size()) {
    225     return kErrorNotSupported;
    226   }
    227 
    228   // Get the resolution info from the look up table
    229   msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
    230   for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
    231     msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
    232     if (cur->video_format == hdmi_modes_[index]) {
    233       timing_mode = cur;
    234       break;
    235     }
    236   }
    237   display_attributes->x_pixels = timing_mode->active_h;
    238   display_attributes->y_pixels = timing_mode->active_v;
    239   display_attributes->v_front_porch = timing_mode->front_porch_v;
    240   display_attributes->v_back_porch = timing_mode->back_porch_v;
    241   display_attributes->v_pulse_width = timing_mode->pulse_width_v;
    242   uint32_t h_blanking = timing_mode->front_porch_h + timing_mode->back_porch_h +
    243       timing_mode->pulse_width_h;
    244   display_attributes->h_total = timing_mode->active_h + h_blanking;
    245   display_attributes->x_dpi = 0;
    246   display_attributes->y_dpi = 0;
    247   display_attributes->fps = timing_mode->refresh_rate / 1000;
    248   display_attributes->vsync_period_ns = UINT32(1000000000L / display_attributes->fps);
    249   display_attributes->is_device_split = false;
    250   if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
    251     display_attributes->is_device_split = true;
    252     display_attributes->h_total += h_blanking;
    253   }
    254 
    255   GetDisplayS3DSupport(index, display_attributes);
    256   std::bitset<32> pixel_formats = timing_mode->pixel_formats;
    257 
    258   display_attributes->is_yuv = pixel_formats[1];
    259 
    260   return kErrorNone;
    261 }
    262 
    263 DisplayError HWHDMI::SetDisplayAttributes(uint32_t index) {
    264   DTRACE_SCOPED();
    265 
    266   if (index > hdmi_modes_.size()) {
    267     return kErrorNotSupported;
    268   }
    269 
    270   // Variable screen info
    271   fb_var_screeninfo vscreeninfo = {};
    272   if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &vscreeninfo) < 0) {
    273     IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
    274     return kErrorHardware;
    275   }
    276 
    277   DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3],
    278         vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
    279         vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
    280         vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
    281 
    282   msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
    283   for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
    284     msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
    285     if (cur->video_format == hdmi_modes_[index]) {
    286       timing_mode = cur;
    287       break;
    288     }
    289   }
    290 
    291   if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) {
    292     return kErrorParameters;
    293   }
    294 
    295   msmfb_metadata metadata = {};
    296   metadata.op = metadata_op_vic;
    297   metadata.data.video_info_code = timing_mode->video_format;
    298   if (Sys::ioctl_(device_fd_, MSMFB_METADATA_SET, &metadata) < 0) {
    299     IOCTL_LOGE(MSMFB_METADATA_SET, device_type_);
    300     return kErrorHardware;
    301   }
    302 
    303   DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00,
    304         vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
    305         vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
    306         vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
    307 
    308   vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
    309   if (Sys::ioctl_(device_fd_, FBIOPUT_VSCREENINFO, &vscreeninfo) < 0) {
    310     IOCTL_LOGE(FBIOPUT_VSCREENINFO, device_type_);
    311     return kErrorHardware;
    312   }
    313 
    314   active_config_index_ = index;
    315 
    316   frame_rate_ = timing_mode->refresh_rate;
    317 
    318   // Get the display attributes for current active config index
    319   GetDisplayAttributes(active_config_index_, &display_attributes_);
    320   UpdateMixerAttributes();
    321 
    322   supported_s3d_modes_.clear();
    323   supported_s3d_modes_.push_back(kS3DModeNone);
    324   for (uint32_t mode = kS3DModeNone + 1; mode < kS3DModeMax; mode ++) {
    325     if (display_attributes_.s3d_config[(HWS3DMode)mode]) {
    326       supported_s3d_modes_.push_back((HWS3DMode)mode);
    327     }
    328   }
    329 
    330   SetS3DMode(kS3DModeNone);
    331 
    332   return kErrorNone;
    333 }
    334 
    335 DisplayError HWHDMI::GetConfigIndex(uint32_t mode, uint32_t *index) {
    336   // Check if the mode is valid and return corresponding index
    337   for (uint32_t i = 0; i < hdmi_modes_.size(); i++) {
    338     if (hdmi_modes_[i] == mode) {
    339       *index = i;
    340       DLOGI("Index = %d for config = %d", *index, mode);
    341       return kErrorNone;
    342     }
    343   }
    344 
    345   DLOGE("Config = %d not supported", mode);
    346   return kErrorNotSupported;
    347 }
    348 
    349 DisplayError HWHDMI::Validate(HWLayers *hw_layers) {
    350   HWDevice::ResetDisplayParams();
    351   return HWDevice::Validate(hw_layers);
    352 }
    353 
    354 DisplayError HWHDMI::GetHWScanInfo(HWScanInfo *scan_info) {
    355   if (!scan_info) {
    356     return kErrorParameters;
    357   }
    358   *scan_info = hw_scan_info_;
    359   return kErrorNone;
    360 }
    361 
    362 DisplayError HWHDMI::GetVideoFormat(uint32_t config_index, uint32_t *video_format) {
    363   if (config_index > hdmi_modes_.size()) {
    364     return kErrorNotSupported;
    365   }
    366 
    367   *video_format = hdmi_modes_[config_index];
    368 
    369   return kErrorNone;
    370 }
    371 
    372 DisplayError HWHDMI::GetMaxCEAFormat(uint32_t *max_cea_format) {
    373   *max_cea_format = HDMI_VFRMT_END;
    374 
    375   return kErrorNone;
    376 }
    377 
    378 DisplayError HWHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
    379   DisplayError error = kErrorNone;
    380   int fd = -1;
    381   char data[kMaxStringLength] = {'\0'};
    382 
    383   snprintf(data, sizeof(data), "%s%d/hdcp2p2/min_level_change", fb_path_, fb_node_index_);
    384 
    385   fd = Sys::open_(data, O_WRONLY);
    386   if (fd < 0) {
    387     DLOGW("File '%s' could not be opened.", data);
    388     return kErrorHardware;
    389   }
    390 
    391   snprintf(data, sizeof(data), "%d", min_enc_level);
    392 
    393   ssize_t err = Sys::pwrite_(fd, data, strlen(data), 0);
    394   if (err <= 0) {
    395     DLOGE("Write failed, Error = %s", strerror(errno));
    396     error = kErrorHardware;
    397   }
    398 
    399   Sys::close_(fd);
    400 
    401   return error;
    402 }
    403 
    404 HWScanSupport HWHDMI::MapHWScanSupport(uint32_t value) {
    405   switch (value) {
    406   // TODO(user): Read the scan type from driver defined values instead of hardcoding
    407   case 0:
    408     return kScanNotSupported;
    409   case 1:
    410     return kScanAlwaysOverscanned;
    411   case 2:
    412     return kScanAlwaysUnderscanned;
    413   case 3:
    414     return kScanBoth;
    415   default:
    416     return kScanNotSupported;
    417     break;
    418   }
    419 }
    420 
    421 void HWHDMI::ReadScanInfo() {
    422   int scan_info_file = -1;
    423   ssize_t len = -1;
    424   char data[kPageSize] = {'\0'};
    425 
    426   snprintf(data, sizeof(data), "%s%d/scan_info", fb_path_, fb_node_index_);
    427   scan_info_file = Sys::open_(data, O_RDONLY);
    428   if (scan_info_file < 0) {
    429     DLOGW("File '%s' not found.", data);
    430     return;
    431   }
    432 
    433   memset(&data[0], 0, sizeof(data));
    434   len = Sys::pread_(scan_info_file, data, sizeof(data) - 1, 0);
    435   if (len <= 0) {
    436     Sys::close_(scan_info_file);
    437     DLOGW("File %s%d/scan_info is empty.", fb_path_, fb_node_index_);
    438     return;
    439   }
    440   data[len] = '\0';
    441   Sys::close_(scan_info_file);
    442 
    443   const uint32_t scan_info_max_count = 3;
    444   uint32_t scan_info_count = 0;
    445   char *tokens[scan_info_max_count] = { NULL };
    446   ParseLine(data, tokens, scan_info_max_count, &scan_info_count);
    447   if (scan_info_count != scan_info_max_count) {
    448     DLOGW("Failed to parse scan info string %s", data);
    449     return;
    450   }
    451 
    452   hw_scan_info_.pt_scan_support = MapHWScanSupport(UINT32(atoi(tokens[0])));
    453   hw_scan_info_.it_scan_support = MapHWScanSupport(UINT32(atoi(tokens[1])));
    454   hw_scan_info_.cea_scan_support = MapHWScanSupport(UINT32(atoi(tokens[2])));
    455   DLOGI("PT %d IT %d CEA %d", hw_scan_info_.pt_scan_support, hw_scan_info_.it_scan_support,
    456         hw_scan_info_.cea_scan_support);
    457 }
    458 
    459 int HWHDMI::OpenResolutionFile(int file_mode) {
    460   char file_path[kMaxStringLength];
    461   memset(file_path, 0, sizeof(file_path));
    462   snprintf(file_path , sizeof(file_path), "%s%d/res_info", fb_path_, fb_node_index_);
    463 
    464   int fd = Sys::open_(file_path, file_mode);
    465 
    466   if (fd < 0) {
    467     DLOGE("file '%s' not found : ret = %d err str: %s", file_path, fd, strerror(errno));
    468   }
    469 
    470   return fd;
    471 }
    472 
    473 // Method to request HDMI driver to write a new page of timing info into res_info node
    474 void HWHDMI::RequestNewPage(uint32_t page_number) {
    475   char page_string[kPageSize];
    476   int fd = OpenResolutionFile(O_WRONLY);
    477   if (fd < 0) {
    478     return;
    479   }
    480 
    481   snprintf(page_string, sizeof(page_string), "%d", page_number);
    482 
    483   DLOGI_IF(kTagDriverConfig, "page=%s", page_string);
    484 
    485   ssize_t err = Sys::pwrite_(fd, page_string, sizeof(page_string), 0);
    486   if (err <= 0) {
    487     DLOGE("Write to res_info failed (%s)", strerror(errno));
    488   }
    489 
    490   Sys::close_(fd);
    491 }
    492 
    493 // Reads the contents of res_info node into a buffer if the file is not empty
    494 bool HWHDMI::ReadResolutionFile(char *config_buffer) {
    495   ssize_t bytes_read = 0;
    496   int fd = OpenResolutionFile(O_RDONLY);
    497   if (fd >= 0) {
    498     bytes_read = Sys::pread_(fd, config_buffer, kPageSize, 0);
    499     Sys::close_(fd);
    500   }
    501 
    502   DLOGI_IF(kTagDriverConfig, "bytes_read = %d", bytes_read);
    503 
    504   return (bytes_read > 0);
    505 }
    506 
    507 // Populates the internal timing info structure with the timing info obtained
    508 // from the HDMI driver
    509 DisplayError HWHDMI::ReadTimingInfo() {
    510   uint32_t config_index = 0;
    511   uint32_t page_number = MSM_HDMI_INIT_RES_PAGE;
    512   uint32_t size = sizeof(msm_hdmi_mode_timing_info);
    513 
    514   while (true) {
    515     char config_buffer[kPageSize] = {0};
    516     msm_hdmi_mode_timing_info *info = reinterpret_cast<msm_hdmi_mode_timing_info *>(config_buffer);
    517     RequestNewPage(page_number);
    518 
    519     if (!ReadResolutionFile(config_buffer)) {
    520       break;
    521     }
    522 
    523     while (info->video_format && size < kPageSize && config_index < hdmi_modes_.size()) {
    524       supported_video_modes_[config_index] = *info;
    525       size += sizeof(msm_hdmi_mode_timing_info);
    526 
    527       DLOGI_IF(kTagDriverConfig, "Config=%d Mode %d: (%dx%d) @ %d, pixel formats %d",
    528                config_index,
    529                supported_video_modes_[config_index].video_format,
    530                supported_video_modes_[config_index].active_h,
    531                supported_video_modes_[config_index].active_v,
    532                supported_video_modes_[config_index].refresh_rate,
    533                supported_video_modes_[config_index].pixel_formats);
    534 
    535       info++;
    536       config_index++;
    537     }
    538 
    539     size = sizeof(msm_hdmi_mode_timing_info);
    540     // Request HDMI driver to populate res_info with more
    541     // timing information
    542     page_number++;
    543   }
    544 
    545   if (page_number == MSM_HDMI_INIT_RES_PAGE || config_index == 0) {
    546     DLOGE("No timing information found.");
    547     return kErrorHardware;
    548   }
    549 
    550   return kErrorNone;
    551 }
    552 
    553 bool HWHDMI::IsResolutionFilePresent() {
    554   bool is_file_present = false;
    555   int fd = OpenResolutionFile(O_RDONLY);
    556   if (fd >= 0) {
    557     is_file_present = true;
    558     Sys::close_(fd);
    559   }
    560 
    561   return is_file_present;
    562 }
    563 
    564 void HWHDMI::SetSourceProductInformation(const char *node, const char *name) {
    565   char property_value[kMaxStringLength];
    566   char sys_fs_path[kMaxStringLength];
    567   int hdmi_node_index = GetFBNodeIndex(kDeviceHDMI);
    568   if (hdmi_node_index < 0) {
    569     return;
    570   }
    571 
    572   ssize_t length = 0;
    573   bool prop_read_success = Debug::GetProperty(name, property_value);
    574   if (!prop_read_success) {
    575     return;
    576   }
    577 
    578   snprintf(sys_fs_path , sizeof(sys_fs_path), "%s%d/%s", fb_path_, hdmi_node_index, node);
    579   length = HWDevice::SysFsWrite(sys_fs_path, property_value,
    580                                 static_cast<ssize_t>(strlen(property_value)));
    581   if (length <= 0) {
    582     DLOGW("Failed to write %s = %s", node, property_value);
    583   }
    584 }
    585 
    586 DisplayError HWHDMI::GetDisplayS3DSupport(uint32_t index,
    587                                           HWDisplayAttributes *attrib) {
    588   ssize_t length = -1;
    589   char edid_s3d_str[kPageSize] = {'\0'};
    590   char edid_s3d_path[kMaxStringLength] = {'\0'};
    591   snprintf(edid_s3d_path, sizeof(edid_s3d_path), "%s%d/edid_3d_modes", fb_path_, fb_node_index_);
    592 
    593   if (index > hdmi_modes_.size()) {
    594     return kErrorNotSupported;
    595   }
    596 
    597   attrib->s3d_config[kS3DModeNone] = 1;
    598 
    599   // Three level inception!
    600   // The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH
    601   char *saveptr_l1, *saveptr_l2, *saveptr_l3;
    602   char *l1, *l2, *l3;
    603 
    604   int edid_s3d_node = Sys::open_(edid_s3d_path, O_RDONLY);
    605   if (edid_s3d_node < 0) {
    606     DLOGW("%s could not be opened : %s", edid_s3d_path, strerror(errno));
    607     return kErrorNotSupported;
    608   }
    609 
    610   length = Sys::pread_(edid_s3d_node, edid_s3d_str, sizeof(edid_s3d_str)-1, 0);
    611   if (length <= 0) {
    612     Sys::close_(edid_s3d_node);
    613     return kErrorNotSupported;
    614   }
    615 
    616   l1 = strtok_r(edid_s3d_str, ",", &saveptr_l1);
    617   while (l1 != NULL) {
    618     l2 = strtok_r(l1, "=", &saveptr_l2);
    619     if (l2 != NULL) {
    620       if (hdmi_modes_[index] == (uint32_t)atoi(l2)) {
    621           l3 = strtok_r(saveptr_l2, ":", &saveptr_l3);
    622           while (l3 != NULL) {
    623             if (strncmp("SSH", l3, strlen("SSH")) == 0) {
    624               attrib->s3d_config[kS3DModeLR] = 1;
    625               attrib->s3d_config[kS3DModeRL] = 1;
    626             } else if (strncmp("TAB", l3, strlen("TAB")) == 0) {
    627               attrib->s3d_config[kS3DModeTB] = 1;
    628             } else if (strncmp("FP", l3, strlen("FP")) == 0) {
    629               attrib->s3d_config[kS3DModeFP] = 1;
    630             }
    631             l3 = strtok_r(NULL, ":", &saveptr_l3);
    632           }
    633       }
    634     }
    635     l1 = strtok_r(NULL, ",", &saveptr_l1);
    636   }
    637 
    638   Sys::close_(edid_s3d_node);
    639   return kErrorNone;
    640 }
    641 
    642 bool HWHDMI::IsSupportedS3DMode(HWS3DMode s3d_mode) {
    643   for (uint32_t i = 0; i < supported_s3d_modes_.size(); i++) {
    644     if (supported_s3d_modes_[i] == s3d_mode) {
    645       return true;
    646     }
    647   }
    648   return false;
    649 }
    650 
    651 DisplayError HWHDMI::SetS3DMode(HWS3DMode s3d_mode) {
    652   if (!IsSupportedS3DMode(s3d_mode)) {
    653     DLOGW("S3D mode is not supported s3d_mode = %d", s3d_mode);
    654     return kErrorNotSupported;
    655   }
    656 
    657   std::map<HWS3DMode, msm_hdmi_s3d_mode>::iterator it = s3d_mode_sdm_to_mdp_.find(s3d_mode);
    658   if (it == s3d_mode_sdm_to_mdp_.end()) {
    659     return kErrorNotSupported;
    660   }
    661   msm_hdmi_s3d_mode s3d_mdp_mode = it->second;
    662 
    663   if (active_mdp_s3d_mode_ == s3d_mdp_mode) {
    664     // HDMI_S3D_SIDE_BY_SIDE is an mdp mapping for kS3DModeLR and kS3DModeRL s3d modes. So no need
    665     // to update the s3d_mode node. hw_panel_info needs to be updated to differentiate these two s3d
    666     // modes in strategy
    667     hw_panel_info_.s3d_mode = s3d_mode;
    668     return kErrorNone;
    669   }
    670 
    671   ssize_t length = -1;
    672   char s3d_mode_path[kMaxStringLength] = {'\0'};
    673   char s3d_mode_string[kMaxStringLength] = {'\0'};
    674   snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_);
    675 
    676   int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR);
    677   if (s3d_mode_node < 0) {
    678     DLOGW("%s could not be opened : %s", s3d_mode_path, strerror(errno));
    679     return kErrorNotSupported;
    680   }
    681 
    682   snprintf(s3d_mode_string, sizeof(s3d_mode_string), "%d", s3d_mdp_mode);
    683   length = Sys::pwrite_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0);
    684   if (length <= 0) {
    685     DLOGW("Failed to write into s3d node: %s", strerror(errno));
    686     Sys::close_(s3d_mode_node);
    687     return kErrorNotSupported;
    688   }
    689 
    690   active_mdp_s3d_mode_ = s3d_mdp_mode;
    691   hw_panel_info_.s3d_mode = s3d_mode;
    692   Sys::close_(s3d_mode_node);
    693 
    694   DLOGI_IF(kTagDriverConfig, "s3d mode %d", hw_panel_info_.s3d_mode);
    695   return kErrorNone;
    696 }
    697 
    698 DisplayError HWHDMI::SetRefreshRate(uint32_t refresh_rate) {
    699   char mode_path[kMaxStringLength] = {0};
    700   char node_path[kMaxStringLength] = {0};
    701   uint32_t mode = kModeHFP;
    702 
    703   if (refresh_rate == frame_rate_) {
    704     return kErrorNone;
    705   }
    706 
    707   snprintf(mode_path, sizeof(mode_path), "%s%d/msm_fb_dfps_mode", fb_path_, fb_node_index_);
    708   snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
    709 
    710   int fd_mode = Sys::open_(mode_path, O_WRONLY);
    711   if (fd_mode < 0) {
    712     DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
    713     return kErrorFileDescriptor;
    714   }
    715 
    716   char dfps_mode[kMaxStringLength];
    717   snprintf(dfps_mode, sizeof(dfps_mode), "%d", mode);
    718   DLOGI_IF(kTagDriverConfig, "Setting dfps_mode  = %d", mode);
    719   ssize_t len = Sys::pwrite_(fd_mode, dfps_mode, strlen(dfps_mode), 0);
    720   if (len < 0) {
    721     DLOGE("Failed to enable dfps mode %d with error %s", mode, strerror(errno));
    722     Sys::close_(fd_mode);
    723     return kErrorUndefined;
    724   }
    725   Sys::close_(fd_mode);
    726 
    727   int fd_node = Sys::open_(node_path, O_WRONLY);
    728   if (fd_node < 0) {
    729     DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
    730     return kErrorFileDescriptor;
    731   }
    732 
    733   char refresh_rate_string[kMaxStringLength];
    734   snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
    735   DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate);
    736   len = Sys::pwrite_(fd_node, refresh_rate_string, strlen(refresh_rate_string), 0);
    737   if (len < 0) {
    738     DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
    739     Sys::close_(fd_node);
    740     return kErrorUndefined;
    741   }
    742   Sys::close_(fd_node);
    743 
    744   DisplayError error = ReadTimingInfo();
    745   if (error != kErrorNone) {
    746     return error;
    747   }
    748 
    749   GetDisplayAttributes(active_config_index_, &display_attributes_);
    750   UpdateMixerAttributes();
    751 
    752   frame_rate_ = refresh_rate;
    753 
    754   return kErrorNone;
    755 }
    756 
    757 void HWHDMI::UpdateMixerAttributes() {
    758   mixer_attributes_.width = display_attributes_.x_pixels;
    759   mixer_attributes_.height = display_attributes_.y_pixels;
    760   mixer_attributes_.split_left = display_attributes_.is_device_split ?
    761       (display_attributes_.x_pixels / 2) : mixer_attributes_.width;
    762 }
    763 
    764 }  // namespace sdm
    765 
    766