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