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