• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info * mode,fb_var_screeninfo * info)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 
Create(HWInterface ** intf,HWInfoInterface * hw_info_intf,BufferSyncHandler * buffer_sync_handler)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 
Destroy(HWInterface * intf)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 
HWHDMI(BufferSyncHandler * buffer_sync_handler,HWInfoInterface * hw_info_intf)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 
Init()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 
Deinit()158 DisplayError HWHDMI::Deinit() {
159   return HWDevice::Deinit();
160 }
161 
GetNumDisplayAttributes(uint32_t * count)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 
GetActiveConfig(uint32_t * active_config_index)171 DisplayError HWHDMI::GetActiveConfig(uint32_t *active_config_index) {
172   *active_config_index = active_config_index_;
173   return kErrorNone;
174 }
175 
ReadEDIDInfo()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 
GetDisplayAttributes(uint32_t index,HWDisplayAttributes * display_attributes)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 
SetDisplayAttributes(uint32_t index)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 
GetConfigIndex(uint32_t mode,uint32_t * index)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 
Validate(HWLayers * hw_layers)349 DisplayError HWHDMI::Validate(HWLayers *hw_layers) {
350   HWDevice::ResetDisplayParams();
351   return HWDevice::Validate(hw_layers);
352 }
353 
GetHWScanInfo(HWScanInfo * scan_info)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 
GetVideoFormat(uint32_t config_index,uint32_t * video_format)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 
GetMaxCEAFormat(uint32_t * max_cea_format)372 DisplayError HWHDMI::GetMaxCEAFormat(uint32_t *max_cea_format) {
373   *max_cea_format = HDMI_VFRMT_END;
374 
375   return kErrorNone;
376 }
377 
OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level)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 
MapHWScanSupport(uint32_t value)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 
ReadScanInfo()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 
OpenResolutionFile(int file_mode)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
RequestNewPage(uint32_t page_number)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
ReadResolutionFile(char * config_buffer)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
ReadTimingInfo()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 
IsResolutionFilePresent()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 
SetSourceProductInformation(const char * node,const char * name)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 
GetDisplayS3DSupport(uint32_t index,HWDisplayAttributes * attrib)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 
IsSupportedS3DMode(HWS3DMode s3d_mode)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 
SetS3DMode(HWS3DMode s3d_mode)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 
SetRefreshRate(uint32_t refresh_rate)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 
UpdateMixerAttributes()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