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