1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved. 4 * 5 * Not a Contribution, Apache license notifications and license are 6 * retained for attribution purposes only. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 #define DEBUG 0 22 #include <ctype.h> 23 #include <fcntl.h> 24 #include <media/IAudioPolicyService.h> 25 #include <media/AudioSystem.h> 26 #include <utils/threads.h> 27 #include <utils/Errors.h> 28 #include <utils/Log.h> 29 30 #include <linux/msm_mdp.h> 31 #include <video/msm_hdmi_modes.h> 32 #include <linux/fb.h> 33 #include <sys/ioctl.h> 34 #include <sys/poll.h> 35 #include <sys/resource.h> 36 #include <cutils/properties.h> 37 #include "hwc_utils.h" 38 #include "external.h" 39 40 using namespace android; 41 42 namespace qhwc { 43 44 #define MAX_FRAME_BUFFER_NAME_SIZE (80) 45 #define MAX_DISPLAY_DEVICES (3) 46 #define MAX_SYSFS_FILE_PATH 255 47 #define UNKNOWN_STRING "unknown" 48 #define SPD_NAME_LENGTH 16 49 50 const char* msmFbDevicePath[] = { "/dev/graphics/fb1", 51 "/dev/graphics/fb2"}; 52 53 /* 54 * Updates extDeviceFbIndex Array with the correct frame buffer indices 55 * of avaiable external devices 56 * 57 */ 58 void ExternalDisplay::updateExtDispDevFbIndex() 59 { 60 FILE *displayDeviceFP = NULL; 61 char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; 62 char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE]; 63 64 for(int j = 1; j < MAX_DISPLAY_DEVICES; j++) { 65 snprintf (msmFbTypePath, sizeof(msmFbTypePath), 66 "/sys/class/graphics/fb%d/msm_fb_type", j); 67 displayDeviceFP = fopen(msmFbTypePath, "r"); 68 if(displayDeviceFP){ 69 fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, 70 displayDeviceFP); 71 if(strncmp(fbType, "dtv panel", strlen("dtv panel")) == 0){ 72 ALOGD_IF(DEBUG,"hdmi framebuffer index is %d",j); 73 mHdmiFbNum = j; 74 } else if(strncmp(fbType, "writeback panel", 75 strlen("writeback panel")) == 0){ 76 ALOGD_IF(DEBUG,"wfd framebuffer index is %d",j); 77 mWfdFbNum = j; 78 } 79 fclose(displayDeviceFP); 80 } 81 } 82 ALOGD_IF(DEBUG,"%s: mHdmiFbNum: %d mWfdFbNum: %d ",__FUNCTION__, 83 mHdmiFbNum, mWfdFbNum); 84 } 85 86 int ExternalDisplay::configureHDMIDisplay() { 87 openFrameBuffer(mHdmiFbNum); 88 if(mFd == -1) 89 return -1; 90 readCEUnderscanInfo(); 91 readResolution(); 92 // TODO: Move this to activate 93 /* Used for changing the resolution 94 * getUserMode will get the preferred 95 * mode set thru adb shell */ 96 int mode = getUserMode(); 97 if (mode == -1) { 98 //Get the best mode and set 99 mode = getBestMode(); 100 } 101 setResolution(mode); 102 setDpyHdmiAttr(); 103 setExternalDisplay(true, mHdmiFbNum); 104 return 0; 105 } 106 107 int ExternalDisplay::configureWFDDisplay() { 108 int ret = 0; 109 if(mConnectedFbNum == mHdmiFbNum) { 110 ALOGE("%s: Cannot process WFD connection while HDMI is active", 111 __FUNCTION__); 112 return -1; 113 } 114 openFrameBuffer(mWfdFbNum); 115 if(mFd == -1) 116 return -1; 117 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 118 if(ret < 0) { 119 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 120 strerror(errno)); 121 } 122 setDpyWfdAttr(); 123 setExternalDisplay(true, mWfdFbNum); 124 return 0; 125 } 126 127 int ExternalDisplay::teardownHDMIDisplay() { 128 if(mConnectedFbNum == mHdmiFbNum) { 129 // hdmi offline event..! 130 closeFrameBuffer(); 131 resetInfo(); 132 setExternalDisplay(false); 133 } 134 return 0; 135 } 136 137 int ExternalDisplay::teardownWFDDisplay() { 138 if(mConnectedFbNum == mWfdFbNum) { 139 // wfd offline event..! 140 closeFrameBuffer(); 141 memset(&mVInfo, 0, sizeof(mVInfo)); 142 setExternalDisplay(false); 143 } 144 return 0; 145 } 146 147 void ExternalDisplay::processUEventOnline(const char *str) { 148 const char *s1 = str + strlen("change@/devices/virtual/switch/"); 149 if(!strncmp(s1,"hdmi",strlen(s1))) { 150 // hdmi online event..! 151 configureHDMIDisplay(); 152 // set system property 153 property_set("hw.hdmiON", "1"); 154 }else if(!strncmp(s1,"wfd",strlen(s1))) { 155 // wfd online event..! 156 configureWFDDisplay(); 157 } 158 } 159 160 void ExternalDisplay::processUEventOffline(const char *str) { 161 const char *s1 = str + strlen("change@/devices/virtual/switch/"); 162 if(!strncmp(s1,"hdmi",strlen(s1))) { 163 teardownHDMIDisplay(); 164 // unset system property 165 property_set("hw.hdmiON", "0"); 166 }else if(!strncmp(s1,"wfd",strlen(s1))) { 167 teardownWFDDisplay(); 168 } 169 } 170 171 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), 172 mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0), 173 mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1), 174 mWfdFbNum(-1), mExtDpyNum(HWC_DISPLAY_EXTERNAL) 175 { 176 memset(&mVInfo, 0, sizeof(mVInfo)); 177 //Determine the fb index for external display devices. 178 updateExtDispDevFbIndex(); 179 // disable HPD at start, it will be enabled later 180 // when the display powers on 181 // This helps for framework reboot or adb shell stop/start 182 writeHPDOption(0); 183 184 // for HDMI - retreive all the modes supported by the driver 185 if(mHdmiFbNum != -1) { 186 supported_video_mode_lut = 187 new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX]; 188 // Populate the mode table for supported modes 189 MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut); 190 MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut, 191 MSM_HDMI_MODES_ALL); 192 // Update the Source Product Information 193 // Vendor Name 194 setSPDInfo("vendor_name", "ro.product.manufacturer"); 195 // Product Description 196 setSPDInfo("product_description", "ro.product.name"); 197 } 198 } 199 /* gets the product manufacturer and product name and writes it 200 * to the sysfs node, so that the driver can get that information 201 * Used to show QCOM 8974 instead of Input 1 for example 202 */ 203 void ExternalDisplay::setSPDInfo(const char* node, const char* property) { 204 int err = -1; 205 char info[PROPERTY_VALUE_MAX]; 206 char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH]; 207 memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath)); 208 snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath), 209 "/sys/devices/virtual/graphics/fb%d/%s", 210 mHdmiFbNum, node); 211 int spdFile = open(sysFsSPDFilePath, O_RDWR, 0); 212 if (spdFile < 0) { 213 ALOGE("%s: file '%s' not found : ret = %d" 214 "err str: %s", __FUNCTION__, sysFsSPDFilePath, 215 spdFile, strerror(errno)); 216 } else { 217 memset(info, 0, sizeof(info)); 218 property_get(property, info, UNKNOWN_STRING); 219 ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info); 220 if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) { 221 err = write(spdFile, info, strlen(info)); 222 if (err <= 0) { 223 ALOGE("%s: file write failed for '%s'" 224 "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno); 225 } 226 } else { 227 ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s", 228 __FUNCTION__, node); 229 } 230 close(spdFile); 231 } 232 } 233 234 void ExternalDisplay::setEDIDMode(int resMode) { 235 ALOGD_IF(DEBUG,"resMode=%d ", resMode); 236 { 237 Mutex::Autolock lock(mExtDispLock); 238 setExternalDisplay(false); 239 openFrameBuffer(mHdmiFbNum); 240 setResolution(resMode); 241 } 242 setExternalDisplay(true, mHdmiFbNum); 243 } 244 245 void ExternalDisplay::setHPD(uint32_t startEnd) { 246 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd); 247 writeHPDOption(startEnd); 248 } 249 250 void ExternalDisplay::setActionSafeDimension(int w, int h) { 251 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h); 252 Mutex::Autolock lock(mExtDispLock); 253 char actionsafeWidth[PROPERTY_VALUE_MAX]; 254 char actionsafeHeight[PROPERTY_VALUE_MAX]; 255 snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w); 256 property_set("persist.sys.actionsafe.width", actionsafeWidth); 257 snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h); 258 property_set("persist.sys.actionsafe.height", actionsafeHeight); 259 setExternalDisplay(true, mHdmiFbNum); 260 } 261 262 int ExternalDisplay::getModeCount() const { 263 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount); 264 Mutex::Autolock lock(mExtDispLock); 265 return mModeCount; 266 } 267 268 void ExternalDisplay::getEDIDModes(int *out) const { 269 Mutex::Autolock lock(mExtDispLock); 270 for(int i = 0;i < mModeCount;i++) { 271 out[i] = mEDIDModes[i]; 272 } 273 } 274 275 void ExternalDisplay::readCEUnderscanInfo() 276 { 277 int hdmiScanInfoFile = -1; 278 int len = -1; 279 char scanInfo[17]; 280 char *ce_info_str = NULL; 281 const char token[] = ", \n"; 282 int ce_info = -1; 283 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH]; 284 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath), 285 "/sys/devices/virtual/graphics/fb%d/" 286 "scan_info", mHdmiFbNum); 287 288 memset(scanInfo, 0, sizeof(scanInfo)); 289 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0); 290 if (hdmiScanInfoFile < 0) { 291 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found", 292 __FUNCTION__, sysFsScanInfoFilePath); 293 return; 294 } else { 295 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1); 296 ALOGD("%s: Scan Info string: %s length = %d", 297 __FUNCTION__, scanInfo, len); 298 if (len <= 0) { 299 close(hdmiScanInfoFile); 300 ALOGE("%s: Scan Info file empty '%s'", 301 __FUNCTION__, sysFsScanInfoFilePath); 302 return; 303 } 304 scanInfo[len] = '\0'; /* null terminate the string */ 305 } 306 close(hdmiScanInfoFile); 307 308 /* 309 * The scan_info contains the three fields 310 * PT - preferred video format 311 * IT - video format 312 * CE video format - containing the underscan support information 313 */ 314 315 /* PT */ 316 ce_info_str = strtok(scanInfo, token); 317 if (ce_info_str) { 318 /* IT */ 319 ce_info_str = strtok(NULL, token); 320 if (ce_info_str) { 321 /* CE */ 322 ce_info_str = strtok(NULL, token); 323 if (ce_info_str) 324 ce_info = atoi(ce_info_str); 325 } 326 } 327 328 if (ce_info_str) { 329 // ce_info contains the underscan information 330 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED || 331 ce_info == EXT_SCAN_BOTH_SUPPORTED) 332 // if TV supported underscan, then driver will always underscan 333 // hence no need to apply action safe rectangle 334 mUnderscanSupported = true; 335 } else { 336 ALOGE("%s: scan_info string error", __FUNCTION__); 337 } 338 339 // Store underscan support info in a system property 340 const char* prop = (mUnderscanSupported) ? "1" : "0"; 341 property_set("hw.underscan_supported", prop); 342 return; 343 } 344 345 ExternalDisplay::~ExternalDisplay() 346 { 347 delete [] supported_video_mode_lut; 348 closeFrameBuffer(); 349 } 350 351 /* 352 * sets the fb_var_screeninfo from the hdmi_mode_timing_info 353 */ 354 void setDisplayTiming(struct fb_var_screeninfo &info, 355 const msm_hdmi_mode_timing_info* mode) 356 { 357 info.reserved[0] = 0; 358 info.reserved[1] = 0; 359 info.reserved[2] = 0; 360 #ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT 361 info.reserved[3] = (info.reserved[3] & 0xFFFF) | 362 (mode->video_format << 16); 363 #endif 364 info.xoffset = 0; 365 info.yoffset = 0; 366 info.xres = mode->active_h; 367 info.yres = mode->active_v; 368 369 info.pixclock = (mode->pixel_freq)*1000; 370 info.vmode = mode->interlaced ? 371 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; 372 373 info.right_margin = mode->front_porch_h; 374 info.hsync_len = mode->pulse_width_h; 375 info.left_margin = mode->back_porch_h; 376 info.lower_margin = mode->front_porch_v; 377 info.vsync_len = mode->pulse_width_v; 378 info.upper_margin = mode->back_porch_v; 379 } 380 381 int ExternalDisplay::parseResolution(char* edidStr, int* edidModes) 382 { 383 char delim = ','; 384 int count = 0; 385 char *start, *end; 386 // EDIDs are string delimited by ',' 387 // Ex: 16,4,5,3,32,34,1 388 // Parse this string to get mode(int) 389 start = (char*) edidStr; 390 end = &delim; 391 while(*end == delim) { 392 edidModes[count] = (int) strtol(start, &end, 10); 393 start = end+1; 394 count++; 395 } 396 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count); 397 for (int i = 0; i < count; i++) 398 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]); 399 return count; 400 } 401 402 bool ExternalDisplay::readResolution() 403 { 404 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH]; 405 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath), 406 "/sys/devices/virtual/graphics/fb%d/edid_modes", mHdmiFbNum); 407 408 int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0); 409 int len = -1; 410 411 if (hdmiEDIDFile < 0) { 412 ALOGE("%s: edid_modes file '%s' not found", 413 __FUNCTION__, sysFsEDIDFilePath); 414 return false; 415 } else { 416 len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1); 417 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d", 418 __FUNCTION__, mEDIDs, len); 419 if ( len <= 0) { 420 ALOGE("%s: edid_modes file empty '%s'", 421 __FUNCTION__, sysFsEDIDFilePath); 422 } 423 else { 424 while (len > 1 && isspace(mEDIDs[len-1])) 425 --len; 426 mEDIDs[len] = 0; 427 } 428 } 429 close(hdmiEDIDFile); 430 if(len > 0) { 431 // Get EDID modes from the EDID strings 432 mModeCount = parseResolution(mEDIDs, mEDIDModes); 433 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__, 434 mModeCount); 435 } 436 437 return (strlen(mEDIDs) > 0); 438 } 439 440 bool ExternalDisplay::openFrameBuffer(int fbNum) 441 { 442 if (mFd == -1) { 443 mFd = open(msmFbDevicePath[fbNum-1], O_RDWR); 444 if (mFd < 0) 445 ALOGE("%s: %s is not available", __FUNCTION__, 446 msmFbDevicePath[fbNum-1]); 447 if(mHwcContext) { 448 mHwcContext->dpyAttr[mExtDpyNum].fd = mFd; 449 } 450 } 451 return (mFd > 0); 452 } 453 454 bool ExternalDisplay::closeFrameBuffer() 455 { 456 int ret = 0; 457 if(mFd >= 0) { 458 ret = close(mFd); 459 mFd = -1; 460 } 461 if(mHwcContext) { 462 mHwcContext->dpyAttr[mExtDpyNum].fd = mFd; 463 } 464 return (ret == 0); 465 } 466 467 // clears the vinfo, edid, best modes 468 void ExternalDisplay::resetInfo() 469 { 470 memset(&mVInfo, 0, sizeof(mVInfo)); 471 memset(mEDIDs, 0, sizeof(mEDIDs)); 472 memset(mEDIDModes, 0, sizeof(mEDIDModes)); 473 mModeCount = 0; 474 mCurrentMode = -1; 475 mUnderscanSupported = false; 476 // Reset the underscan supported system property 477 const char* prop = "0"; 478 property_set("hw.underscan_supported", prop); 479 } 480 481 int ExternalDisplay::getModeOrder(int mode) 482 { 483 // XXX: We dont support interlaced modes but having 484 // it here for future 485 switch (mode) { 486 default: 487 case HDMI_VFRMT_1440x480i60_4_3: 488 return 1; // 480i 4:3 489 case HDMI_VFRMT_1440x480i60_16_9: 490 return 2; // 480i 16:9 491 case HDMI_VFRMT_1440x576i50_4_3: 492 return 3; // i576i 4:3 493 case HDMI_VFRMT_1440x576i50_16_9: 494 return 4; // 576i 16:9 495 case HDMI_VFRMT_1920x1080i60_16_9: 496 return 5; // 1080i 16:9 497 case HDMI_VFRMT_640x480p60_4_3: 498 return 6; // 640x480 4:3 499 case HDMI_VFRMT_720x480p60_4_3: 500 return 7; // 480p 4:3 501 case HDMI_VFRMT_720x480p60_16_9: 502 return 8; // 480p 16:9 503 case HDMI_VFRMT_720x576p50_4_3: 504 return 9; // 576p 4:3 505 case HDMI_VFRMT_720x576p50_16_9: 506 return 10; // 576p 16:9 507 case HDMI_VFRMT_1024x768p60_4_3: 508 return 11; // 768p 4:3 Vesa format 509 case HDMI_VFRMT_1280x1024p60_5_4: 510 return 12; // 1024p Vesa format 511 case HDMI_VFRMT_1280x720p50_16_9: 512 return 13; // 720p@50Hz 513 case HDMI_VFRMT_1280x720p60_16_9: 514 return 14; // 720p@60Hz 515 case HDMI_VFRMT_1920x1080p24_16_9: 516 return 15; //1080p@24Hz 517 case HDMI_VFRMT_1920x1080p25_16_9: 518 return 16; //108-p@25Hz 519 case HDMI_VFRMT_1920x1080p30_16_9: 520 return 17; //1080p@30Hz 521 case HDMI_VFRMT_1920x1080p50_16_9: 522 return 18; //1080p@50Hz 523 case HDMI_VFRMT_1920x1080p60_16_9: 524 return 19; //1080p@60Hz 525 case HDMI_VFRMT_2560x1600p60_16_9: 526 return 20; //WQXGA@60Hz541 527 case HDMI_VFRMT_3840x2160p24_16_9: 528 return 21;//2160@24Hz 529 case HDMI_VFRMT_3840x2160p25_16_9: 530 return 22;//2160@25Hz 531 case HDMI_VFRMT_3840x2160p30_16_9: 532 return 23; //2160@30Hz 533 case HDMI_VFRMT_4096x2160p24_16_9: 534 return 24; //4kx2k@24Hz 535 } 536 } 537 538 /// Returns the user mode set(if any) using adb shell 539 int ExternalDisplay::getUserMode() { 540 /* Based on the property set the resolution */ 541 char property_value[PROPERTY_VALUE_MAX]; 542 property_get("hw.hdmi.resolution", property_value, "-1"); 543 int mode = atoi(property_value); 544 // We dont support interlaced modes 545 if(isValidMode(mode) && !isInterlacedMode(mode)) { 546 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode); 547 return mode; 548 } 549 return -1; 550 } 551 552 // Get the best mode for the current HD TV 553 int ExternalDisplay::getBestMode() { 554 int bestOrder = 0; 555 int bestMode = HDMI_VFRMT_640x480p60_4_3; 556 Mutex::Autolock lock(mExtDispLock); 557 // for all the edid read, get the best mode 558 for(int i = 0; i < mModeCount; i++) { 559 int mode = mEDIDModes[i]; 560 int order = getModeOrder(mode); 561 if (order > bestOrder) { 562 bestOrder = order; 563 bestMode = mode; 564 } 565 } 566 return bestMode; 567 } 568 569 inline bool ExternalDisplay::isValidMode(int ID) 570 { 571 bool valid = false; 572 for (int i = 0; i < mModeCount; i++) { 573 if(ID == mEDIDModes[i]) { 574 valid = true; 575 break; 576 } 577 } 578 return valid; 579 } 580 581 // returns true if the mode(ID) is interlaced mode format 582 bool ExternalDisplay::isInterlacedMode(int ID) { 583 bool interlaced = false; 584 switch(ID) { 585 case HDMI_VFRMT_1440x480i60_4_3: 586 case HDMI_VFRMT_1440x480i60_16_9: 587 case HDMI_VFRMT_1440x576i50_4_3: 588 case HDMI_VFRMT_1440x576i50_16_9: 589 case HDMI_VFRMT_1920x1080i60_16_9: 590 interlaced = true; 591 break; 592 default: 593 interlaced = false; 594 break; 595 } 596 return interlaced; 597 } 598 599 void ExternalDisplay::setResolution(int ID) 600 { 601 struct fb_var_screeninfo info; 602 int ret = 0; 603 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 604 if(ret < 0) { 605 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 606 strerror(errno)); 607 } 608 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d)," 609 "(%d,%d,%d) %dMHz>", __FUNCTION__, 610 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, 611 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 612 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 613 mVInfo.pixclock/1000/1000); 614 //If its a new ID - update var_screeninfo 615 if ((isValidMode(ID)) && mCurrentMode != ID) { 616 const struct msm_hdmi_mode_timing_info *mode = 617 &supported_video_mode_lut[0]; 618 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) { 619 const struct msm_hdmi_mode_timing_info *cur = 620 &supported_video_mode_lut[i]; 621 if (cur->video_format == (uint32_t)ID) { 622 mode = cur; 623 break; 624 } 625 } 626 setDisplayTiming(mVInfo, mode); 627 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d" 628 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID, 629 mode->video_format, mVInfo.xres, mVInfo.yres, 630 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 631 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 632 mVInfo.pixclock/1000/1000); 633 #ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT 634 struct msmfb_metadata metadata; 635 memset(&metadata, 0 , sizeof(metadata)); 636 metadata.op = metadata_op_vic; 637 metadata.data.video_info_code = mode->video_format; 638 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) { 639 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s", 640 __FUNCTION__, strerror(errno)); 641 } 642 #endif 643 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; 644 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo); 645 if(ret < 0) { 646 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s", 647 __FUNCTION__, strerror(errno)); 648 } 649 mCurrentMode = ID; 650 } 651 } 652 653 void ExternalDisplay::setExternalDisplay(bool connected, int extFbNum) 654 { 655 hwc_context_t* ctx = mHwcContext; 656 if(ctx) { 657 ALOGD_IF(DEBUG, "%s: connected = %d", __FUNCTION__, connected); 658 // Store the external display 659 mConnected = connected; 660 mConnectedFbNum = extFbNum; 661 mHwcContext->dpyAttr[mExtDpyNum].connected = connected; 662 } 663 } 664 665 int ExternalDisplay::getExtFbNum(int &fbNum) { 666 int ret = -1; 667 if(mConnected) { 668 fbNum = mConnectedFbNum; 669 ret = 0; 670 } 671 return ret; 672 } 673 674 bool ExternalDisplay::writeHPDOption(int userOption) const 675 { 676 bool ret = true; 677 if(mHdmiFbNum != -1) { 678 char sysFsHPDFilePath[255]; 679 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath), 680 "/sys/devices/virtual/graphics/fb%d/hpd", mHdmiFbNum); 681 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0); 682 if (hdmiHPDFile < 0) { 683 ALOGE("%s: state file '%s' not found : ret%d err str: %s", __FUNCTION__, 684 sysFsHPDFilePath, hdmiHPDFile, strerror(errno)); 685 ret = false; 686 } else { 687 int err = -1; 688 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption); 689 if(userOption) 690 err = write(hdmiHPDFile, "1", 2); 691 else 692 err = write(hdmiHPDFile, "0" , 2); 693 if (err <= 0) { 694 ALOGE("%s: file write failed '%s'", __FUNCTION__, sysFsHPDFilePath); 695 ret = false; 696 } 697 close(hdmiHPDFile); 698 } 699 } 700 return ret; 701 } 702 703 void ExternalDisplay::setDpyWfdAttr() { 704 if(mHwcContext) { 705 mHwcContext->dpyAttr[mExtDpyNum].xres = mVInfo.xres; 706 mHwcContext->dpyAttr[mExtDpyNum].yres = mVInfo.yres; 707 mHwcContext->dpyAttr[mExtDpyNum].vsync_period = 708 1000000000l /60; 709 ALOGD_IF(DEBUG,"%s: wfd...connected..!",__FUNCTION__); 710 } 711 } 712 713 void ExternalDisplay::setDpyHdmiAttr() { 714 int width = 0, height = 0, fps = 0; 715 getAttrForMode(width, height, fps); 716 if(mHwcContext) { 717 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height); 718 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width; 719 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height; 720 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period = 721 1000000000l / fps; 722 } 723 } 724 725 void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) { 726 switch (mCurrentMode) { 727 case HDMI_VFRMT_640x480p60_4_3: 728 width = 640; 729 height = 480; 730 fps = 60; 731 break; 732 case HDMI_VFRMT_720x480p60_4_3: 733 case HDMI_VFRMT_720x480p60_16_9: 734 width = 720; 735 height = 480; 736 fps = 60; 737 break; 738 case HDMI_VFRMT_720x576p50_4_3: 739 case HDMI_VFRMT_720x576p50_16_9: 740 width = 720; 741 height = 576; 742 fps = 50; 743 break; 744 case HDMI_VFRMT_1280x720p50_16_9: 745 width = 1280; 746 height = 720; 747 fps = 50; 748 break; 749 case HDMI_VFRMT_1280x720p60_16_9: 750 width = 1280; 751 height = 720; 752 fps = 60; 753 break; 754 case HDMI_VFRMT_1280x1024p60_5_4: 755 width = 1280; 756 height = 1024; 757 fps = 60; 758 break; 759 case HDMI_VFRMT_1024x768p60_4_3: 760 width = 1024; 761 height = 768; 762 fps = 60; 763 break; 764 case HDMI_VFRMT_1920x1080p24_16_9: 765 width = 1920; 766 height = 1080; 767 fps = 24; 768 break; 769 case HDMI_VFRMT_1920x1080p25_16_9: 770 width = 1920; 771 height = 1080; 772 fps = 25; 773 break; 774 case HDMI_VFRMT_1920x1080p30_16_9: 775 width = 1920; 776 height = 1080; 777 fps = 30; 778 break; 779 case HDMI_VFRMT_1920x1080p50_16_9: 780 width = 1920; 781 height = 1080; 782 fps = 50; 783 break; 784 case HDMI_VFRMT_1920x1080p60_16_9: 785 width = 1920; 786 height = 1080; 787 fps = 60; 788 break; 789 case HDMI_VFRMT_2560x1600p60_16_9: 790 width = 2560; 791 height = 1600; 792 fps = 60; 793 break; 794 case HDMI_VFRMT_3840x2160p24_16_9: 795 width = 3840; 796 height = 2160; 797 fps = 24; 798 break; 799 case HDMI_VFRMT_3840x2160p25_16_9: 800 width = 3840; 801 height = 2160; 802 fps = 25; 803 break; 804 case HDMI_VFRMT_3840x2160p30_16_9: 805 width = 3840; 806 height = 2160; 807 fps = 30; 808 break; 809 case HDMI_VFRMT_4096x2160p24_16_9: 810 width = 4096; 811 height = 2160; 812 fps = 24; 813 break; 814 815 } 816 } 817 818 }; 819