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 <utils/threads.h> 25 #include <utils/Errors.h> 26 #include <utils/Log.h> 27 28 #include <linux/msm_mdp.h> 29 #include <video/msm_hdmi_modes.h> 30 #include <linux/fb.h> 31 #include <sys/ioctl.h> 32 #include <cutils/properties.h> 33 #include "hwc_utils.h" 34 #include "external.h" 35 #include "overlayUtils.h" 36 #include "overlay.h" 37 #include "mdp_version.h" 38 #include "qd_utils.h" 39 40 using namespace android; 41 42 namespace qhwc { 43 #define MAX_SYSFS_FILE_PATH 255 44 #define UNKNOWN_STRING "unknown" 45 #define SPD_NAME_LENGTH 16 46 /* Max. resolution assignable to when downscale */ 47 #define SUPPORTED_DOWNSCALE_EXT_AREA (1920*1080) 48 49 50 int ExternalDisplay::configure() { 51 if(!openFrameBuffer()) { 52 ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum); 53 return -1; 54 } 55 readCEUnderscanInfo(); 56 readResolution(); 57 // TODO: Move this to activate 58 /* Used for changing the resolution 59 * getUserMode will get the preferred 60 * mode set thru adb shell */ 61 int mode = getUserMode(); 62 if (mode == -1) { 63 //Get the best mode and set 64 mode = getBestMode(); 65 } 66 setResolution(mode); 67 setAttributes(); 68 // set system property 69 property_set("hw.hdmiON", "1"); 70 return 0; 71 } 72 73 void ExternalDisplay::getAttributes(int& width, int& height) { 74 int fps = 0; 75 getAttrForMode(width, height, fps); 76 } 77 78 int ExternalDisplay::teardown() { 79 closeFrameBuffer(); 80 resetInfo(); 81 // unset system property 82 property_set("hw.hdmiON", "0"); 83 return 0; 84 } 85 86 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), 87 mCurrentMode(-1), mModeCount(0), 88 mUnderscanSupported(false), mHwcContext(ctx) 89 { 90 memset(&mVInfo, 0, sizeof(mVInfo)); 91 mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL); 92 // disable HPD at start, it will be enabled later 93 // when the display powers on 94 // This helps for framework reboot or adb shell stop/start 95 writeHPDOption(0); 96 97 // for HDMI - retreive all the modes supported by the driver 98 if(mFbNum != -1) { 99 supported_video_mode_lut = 100 new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX]; 101 // Populate the mode table for supported modes 102 MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut); 103 MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut, 104 MSM_HDMI_MODES_ALL); 105 // Update the Source Product Information 106 // Vendor Name 107 setSPDInfo("vendor_name", "ro.product.manufacturer"); 108 // Product Description 109 setSPDInfo("product_description", "ro.product.name"); 110 } 111 } 112 /* gets the product manufacturer and product name and writes it 113 * to the sysfs node, so that the driver can get that information 114 * Used to show QCOM 8974 instead of Input 1 for example 115 */ 116 void ExternalDisplay::setSPDInfo(const char* node, const char* property) { 117 ssize_t err = -1; 118 char info[PROPERTY_VALUE_MAX]; 119 char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH]; 120 memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath)); 121 snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath), 122 "/sys/devices/virtual/graphics/fb%d/%s", 123 mFbNum, node); 124 int spdFile = open(sysFsSPDFilePath, O_RDWR, 0); 125 if (spdFile < 0) { 126 ALOGE("%s: file '%s' not found : ret = %d" 127 "err str: %s", __FUNCTION__, sysFsSPDFilePath, 128 spdFile, strerror(errno)); 129 } else { 130 memset(info, 0, sizeof(info)); 131 property_get(property, info, UNKNOWN_STRING); 132 ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info); 133 if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) { 134 err = write(spdFile, info, strlen(info)); 135 if (err <= 0) { 136 ALOGE("%s: file write failed for '%s'" 137 "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno); 138 } 139 } else { 140 ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s", 141 __FUNCTION__, node); 142 } 143 close(spdFile); 144 } 145 } 146 147 void ExternalDisplay::setHPD(uint32_t startEnd) { 148 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd); 149 writeHPDOption(startEnd); 150 } 151 152 void ExternalDisplay::setActionSafeDimension(int w, int h) { 153 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h); 154 char actionsafeWidth[PROPERTY_VALUE_MAX]; 155 char actionsafeHeight[PROPERTY_VALUE_MAX]; 156 snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w); 157 property_set("persist.sys.actionsafe.width", actionsafeWidth); 158 snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h); 159 property_set("persist.sys.actionsafe.height", actionsafeHeight); 160 } 161 162 int ExternalDisplay::getModeCount() const { 163 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount); 164 return mModeCount; 165 } 166 167 void ExternalDisplay::getEDIDModes(int *out) const { 168 for(int i = 0;i < mModeCount;i++) { 169 out[i] = mEDIDModes[i]; 170 } 171 } 172 173 void ExternalDisplay::readCEUnderscanInfo() 174 { 175 int hdmiScanInfoFile = -1; 176 ssize_t len = -1; 177 char scanInfo[17]; 178 char *ce_info_str = NULL; 179 char *save_ptr; 180 const char token[] = ", \n"; 181 int ce_info = -1; 182 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH]; 183 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath), 184 "/sys/devices/virtual/graphics/fb%d/" 185 "scan_info", mFbNum); 186 187 memset(scanInfo, 0, sizeof(scanInfo)); 188 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0); 189 if (hdmiScanInfoFile < 0) { 190 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found", 191 __FUNCTION__, sysFsScanInfoFilePath); 192 return; 193 } else { 194 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1); 195 ALOGD("%s: Scan Info string: %s length = %zu", 196 __FUNCTION__, scanInfo, len); 197 if (len <= 0) { 198 close(hdmiScanInfoFile); 199 ALOGE("%s: Scan Info file empty '%s'", 200 __FUNCTION__, sysFsScanInfoFilePath); 201 return; 202 } 203 scanInfo[len] = '\0'; /* null terminate the string */ 204 close(hdmiScanInfoFile); 205 } 206 207 /* 208 * The scan_info contains the three fields 209 * PT - preferred video format 210 * IT - video format 211 * CE video format - containing the underscan support information 212 */ 213 214 /* PT */ 215 ce_info_str = strtok_r(scanInfo, token, &save_ptr); 216 if (ce_info_str) { 217 /* IT */ 218 ce_info_str = strtok_r(NULL, token, &save_ptr); 219 if (ce_info_str) { 220 /* CE */ 221 ce_info_str = strtok_r(NULL, token, &save_ptr); 222 if (ce_info_str) 223 ce_info = atoi(ce_info_str); 224 } 225 } 226 227 if (ce_info_str) { 228 // ce_info contains the underscan information 229 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED || 230 ce_info == EXT_SCAN_BOTH_SUPPORTED) 231 // if TV supported underscan, then driver will always underscan 232 // hence no need to apply action safe rectangle 233 mUnderscanSupported = true; 234 } else { 235 ALOGE("%s: scan_info string error", __FUNCTION__); 236 } 237 238 // Store underscan support info in a system property 239 const char* prop = (mUnderscanSupported) ? "1" : "0"; 240 property_set("hw.underscan_supported", prop); 241 return; 242 } 243 244 ExternalDisplay::~ExternalDisplay() 245 { 246 delete [] supported_video_mode_lut; 247 closeFrameBuffer(); 248 } 249 250 /* 251 * sets the fb_var_screeninfo from the hdmi_mode_timing_info 252 */ 253 void setDisplayTiming(struct fb_var_screeninfo &info, 254 const msm_hdmi_mode_timing_info* mode) 255 { 256 info.reserved[0] = 0; 257 info.reserved[1] = 0; 258 info.reserved[2] = 0; 259 #ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT 260 info.reserved[3] = (info.reserved[3] & 0xFFFF) | 261 (mode->video_format << 16); 262 #endif 263 info.xoffset = 0; 264 info.yoffset = 0; 265 info.xres = mode->active_h; 266 info.yres = mode->active_v; 267 268 info.pixclock = (mode->pixel_freq)*1000; 269 info.vmode = mode->interlaced ? 270 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; 271 272 info.right_margin = mode->front_porch_h; 273 info.hsync_len = mode->pulse_width_h; 274 info.left_margin = mode->back_porch_h; 275 info.lower_margin = mode->front_porch_v; 276 info.vsync_len = mode->pulse_width_v; 277 info.upper_margin = mode->back_porch_v; 278 } 279 280 int ExternalDisplay::parseResolution(char* edidStr, int* edidModes) 281 { 282 char delim = ','; 283 int count = 0; 284 char *start, *end; 285 // EDIDs are string delimited by ',' 286 // Ex: 16,4,5,3,32,34,1 287 // Parse this string to get mode(int) 288 start = (char*) edidStr; 289 end = &delim; 290 while(*end == delim) { 291 edidModes[count] = (int) strtol(start, &end, 10); 292 start = end+1; 293 count++; 294 } 295 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count); 296 for (int i = 0; i < count; i++) 297 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]); 298 return count; 299 } 300 301 bool ExternalDisplay::readResolution() 302 { 303 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH]; 304 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath), 305 "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum); 306 307 int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0); 308 ssize_t len = -1; 309 char edidStr[128] = {'\0'}; 310 311 if (hdmiEDIDFile < 0) { 312 ALOGE("%s: edid_modes file '%s' not found", 313 __FUNCTION__, sysFsEDIDFilePath); 314 return false; 315 } else { 316 len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1); 317 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zu", 318 __FUNCTION__, edidStr, len); 319 if ( len <= 0) { 320 ALOGE("%s: edid_modes file empty '%s'", 321 __FUNCTION__, sysFsEDIDFilePath); 322 edidStr[0] = '\0'; 323 } 324 else { 325 while (len > 1 && isspace(edidStr[len-1])) { 326 --len; 327 } 328 edidStr[len] = '\0'; 329 } 330 close(hdmiEDIDFile); 331 } 332 if(len > 0) { 333 // Get EDID modes from the EDID strings 334 mModeCount = parseResolution(edidStr, mEDIDModes); 335 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__, 336 mModeCount); 337 } 338 339 return (len > 0); 340 } 341 342 bool ExternalDisplay::openFrameBuffer() 343 { 344 if (mFd == -1) { 345 char strDevPath[MAX_SYSFS_FILE_PATH]; 346 snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum); 347 mFd = open(strDevPath, O_RDWR); 348 if (mFd < 0) 349 ALOGE("%s: %s is not available", __FUNCTION__, strDevPath); 350 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd; 351 } 352 return (mFd > 0); 353 } 354 355 bool ExternalDisplay::closeFrameBuffer() 356 { 357 int ret = 0; 358 if(mFd >= 0) { 359 ret = close(mFd); 360 mFd = -1; 361 } 362 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd; 363 return (ret == 0); 364 } 365 366 // clears the vinfo, edid, best modes 367 void ExternalDisplay::resetInfo() 368 { 369 memset(&mVInfo, 0, sizeof(mVInfo)); 370 memset(mEDIDModes, 0, sizeof(mEDIDModes)); 371 mModeCount = 0; 372 mCurrentMode = -1; 373 mUnderscanSupported = false; 374 // Reset the underscan supported system property 375 const char* prop = "0"; 376 property_set("hw.underscan_supported", prop); 377 } 378 379 int ExternalDisplay::getModeOrder(int mode) 380 { 381 // XXX: We dont support interlaced modes but having 382 // it here for future 383 switch (mode) { 384 default: 385 case HDMI_VFRMT_1440x480i60_4_3: 386 return 1; // 480i 4:3 387 case HDMI_VFRMT_1440x480i60_16_9: 388 return 2; // 480i 16:9 389 case HDMI_VFRMT_1440x576i50_4_3: 390 return 3; // i576i 4:3 391 case HDMI_VFRMT_1440x576i50_16_9: 392 return 4; // 576i 16:9 393 case HDMI_VFRMT_1920x1080i60_16_9: 394 return 5; // 1080i 16:9 395 case HDMI_VFRMT_640x480p60_4_3: 396 return 6; // 640x480 4:3 397 case HDMI_VFRMT_720x480p60_4_3: 398 return 7; // 480p 4:3 399 case HDMI_VFRMT_720x480p60_16_9: 400 return 8; // 480p 16:9 401 case HDMI_VFRMT_720x576p50_4_3: 402 return 9; // 576p 4:3 403 case HDMI_VFRMT_720x576p50_16_9: 404 return 10; // 576p 16:9 405 case HDMI_VFRMT_1024x768p60_4_3: 406 return 11; // 768p 4:3 Vesa format 407 case HDMI_VFRMT_1280x1024p60_5_4: 408 return 12; // 1024p Vesa format 409 case HDMI_VFRMT_1280x720p50_16_9: 410 return 13; // 720p@50Hz 411 case HDMI_VFRMT_1280x720p60_16_9: 412 return 14; // 720p@60Hz 413 case HDMI_VFRMT_1920x1080p24_16_9: 414 return 15; //1080p@24Hz 415 case HDMI_VFRMT_1920x1080p25_16_9: 416 return 16; //108-p@25Hz 417 case HDMI_VFRMT_1920x1080p30_16_9: 418 return 17; //1080p@30Hz 419 case HDMI_VFRMT_1920x1080p50_16_9: 420 return 18; //1080p@50Hz 421 case HDMI_VFRMT_1920x1080p60_16_9: 422 return 19; //1080p@60Hz 423 case HDMI_VFRMT_2560x1600p60_16_9: 424 return 20; //WQXGA@60Hz541 425 case HDMI_VFRMT_3840x2160p24_16_9: 426 return 21;//2160@24Hz 427 case HDMI_VFRMT_3840x2160p25_16_9: 428 return 22;//2160@25Hz 429 case HDMI_VFRMT_3840x2160p30_16_9: 430 return 23; //2160@30Hz 431 case HDMI_VFRMT_4096x2160p24_16_9: 432 return 24; //4kx2k@24Hz 433 } 434 } 435 436 /// Returns the user mode set(if any) using adb shell 437 int ExternalDisplay::getUserMode() { 438 /* Based on the property set the resolution */ 439 char property_value[PROPERTY_VALUE_MAX]; 440 property_get("hw.hdmi.resolution", property_value, "-1"); 441 int mode = atoi(property_value); 442 // We dont support interlaced modes 443 if(isValidMode(mode) && !isInterlacedMode(mode)) { 444 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode); 445 return mode; 446 } 447 return -1; 448 } 449 450 // Get the best mode for the current HD TV 451 int ExternalDisplay::getBestMode() { 452 int bestOrder = 0; 453 int bestMode = HDMI_VFRMT_640x480p60_4_3; 454 // for all the edid read, get the best mode 455 for(int i = 0; i < mModeCount; i++) { 456 int mode = mEDIDModes[i]; 457 int order = getModeOrder(mode); 458 if (order > bestOrder) { 459 bestOrder = order; 460 bestMode = mode; 461 } 462 } 463 return bestMode; 464 } 465 466 inline bool ExternalDisplay::isValidMode(int ID) 467 { 468 bool valid = false; 469 for (int i = 0; i < mModeCount; i++) { 470 if(ID == mEDIDModes[i]) { 471 valid = true; 472 break; 473 } 474 } 475 return valid; 476 } 477 478 // returns true if the mode(ID) is interlaced mode format 479 bool ExternalDisplay::isInterlacedMode(int ID) { 480 bool interlaced = false; 481 switch(ID) { 482 case HDMI_VFRMT_1440x480i60_4_3: 483 case HDMI_VFRMT_1440x480i60_16_9: 484 case HDMI_VFRMT_1440x576i50_4_3: 485 case HDMI_VFRMT_1440x576i50_16_9: 486 case HDMI_VFRMT_1920x1080i60_16_9: 487 interlaced = true; 488 break; 489 default: 490 interlaced = false; 491 break; 492 } 493 return interlaced; 494 } 495 496 void ExternalDisplay::setResolution(int ID) 497 { 498 int ret = 0; 499 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 500 if(ret < 0) { 501 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 502 strerror(errno)); 503 } 504 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d)," 505 "(%d,%d,%d) %dMHz>", __FUNCTION__, 506 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, 507 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 508 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 509 mVInfo.pixclock/1000/1000); 510 //If its a new ID - update var_screeninfo 511 if ((isValidMode(ID)) && mCurrentMode != ID) { 512 const struct msm_hdmi_mode_timing_info *mode = 513 &supported_video_mode_lut[0]; 514 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) { 515 const struct msm_hdmi_mode_timing_info *cur = 516 &supported_video_mode_lut[i]; 517 if (cur->video_format == (uint32_t)ID) { 518 mode = cur; 519 break; 520 } 521 } 522 setDisplayTiming(mVInfo, mode); 523 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d" 524 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID, 525 mode->video_format, mVInfo.xres, mVInfo.yres, 526 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 527 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 528 mVInfo.pixclock/1000/1000); 529 #ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT 530 struct msmfb_metadata metadata; 531 memset(&metadata, 0 , sizeof(metadata)); 532 metadata.op = metadata_op_vic; 533 metadata.data.video_info_code = mode->video_format; 534 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) { 535 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s", 536 __FUNCTION__, strerror(errno)); 537 } 538 #endif 539 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; 540 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo); 541 if(ret < 0) { 542 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s", 543 __FUNCTION__, strerror(errno)); 544 } 545 mCurrentMode = ID; 546 } 547 } 548 549 bool ExternalDisplay::writeHPDOption(int userOption) const 550 { 551 bool ret = true; 552 if(mFbNum != -1) { 553 char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH]; 554 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath), 555 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum); 556 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0); 557 if (hdmiHPDFile < 0) { 558 ALOGE("%s: state file '%s' not found : ret%d err str: %s", 559 __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno)); 560 ret = false; 561 } else { 562 ssize_t err = -1; 563 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption); 564 if(userOption) 565 err = write(hdmiHPDFile, "1", 2); 566 else 567 err = write(hdmiHPDFile, "0" , 2); 568 if (err <= 0) { 569 ALOGE("%s: file write failed '%s'", __FUNCTION__, 570 sysFsHPDFilePath); 571 ret = false; 572 } 573 close(hdmiHPDFile); 574 } 575 } 576 return ret; 577 } 578 579 580 void ExternalDisplay::setAttributes() { 581 int width = 0, height = 0, fps = 0; 582 getAttrForMode(width, height, fps); 583 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height); 584 if(mHwcContext) { 585 // Always set dpyAttr res to mVInfo res 586 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width; 587 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height; 588 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false; 589 if(!qdutils::MDPVersion::getInstance().is8x26() 590 && mHwcContext->mMDPDownscaleEnabled) { 591 int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres; 592 int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres; 593 // if primary resolution is more than the hdmi resolution 594 // configure dpy attr to primary resolution and set 595 // downscale mode 596 // Restrict this upto 1080p resolution max 597 if(((priW * priH) > (width * height)) && 598 ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) { 599 // tmpW and tmpH will hold the primary dimensions before we 600 // update the aspect ratio if necessary. 601 int tmpW = priW; 602 int tmpH = priH; 603 // HDMI is always in landscape, so always assign the higher 604 // dimension to hdmi's xres 605 if(priH > priW) { 606 tmpW = priH; 607 tmpH = priW; 608 } 609 // The aspect ratios of the external and primary displays 610 // can be different. As a result, directly assigning primary 611 // resolution could lead to an incorrect final image. 612 // We get around this by calculating a new resolution by 613 // keeping aspect ratio intact. 614 hwc_rect r = {0, 0, 0, 0}; 615 getAspectRatioPosition(tmpW, tmpH, width, height, r); 616 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = 617 r.right - r.left; 618 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = 619 r.bottom - r.top; 620 // Set External Display MDP Downscale mode indicator 621 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true; 622 } 623 } 624 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period = 625 (int) 1000000000l / fps; 626 } 627 } 628 629 void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) { 630 switch (mCurrentMode) { 631 case HDMI_VFRMT_640x480p60_4_3: 632 width = 640; 633 height = 480; 634 fps = 60; 635 break; 636 case HDMI_VFRMT_720x480p60_4_3: 637 case HDMI_VFRMT_720x480p60_16_9: 638 width = 720; 639 height = 480; 640 fps = 60; 641 break; 642 case HDMI_VFRMT_720x576p50_4_3: 643 case HDMI_VFRMT_720x576p50_16_9: 644 width = 720; 645 height = 576; 646 fps = 50; 647 break; 648 case HDMI_VFRMT_1280x720p50_16_9: 649 width = 1280; 650 height = 720; 651 fps = 50; 652 break; 653 case HDMI_VFRMT_1280x720p60_16_9: 654 width = 1280; 655 height = 720; 656 fps = 60; 657 break; 658 case HDMI_VFRMT_1280x1024p60_5_4: 659 width = 1280; 660 height = 1024; 661 fps = 60; 662 break; 663 case HDMI_VFRMT_1024x768p60_4_3: 664 width = 1024; 665 height = 768; 666 fps = 60; 667 break; 668 case HDMI_VFRMT_1920x1080p24_16_9: 669 width = 1920; 670 height = 1080; 671 fps = 24; 672 break; 673 case HDMI_VFRMT_1920x1080p25_16_9: 674 width = 1920; 675 height = 1080; 676 fps = 25; 677 break; 678 case HDMI_VFRMT_1920x1080p30_16_9: 679 width = 1920; 680 height = 1080; 681 fps = 30; 682 break; 683 case HDMI_VFRMT_1920x1080p50_16_9: 684 width = 1920; 685 height = 1080; 686 fps = 50; 687 break; 688 case HDMI_VFRMT_1920x1080p60_16_9: 689 width = 1920; 690 height = 1080; 691 fps = 60; 692 break; 693 case HDMI_VFRMT_2560x1600p60_16_9: 694 width = 2560; 695 height = 1600; 696 fps = 60; 697 break; 698 case HDMI_VFRMT_3840x2160p24_16_9: 699 width = 3840; 700 height = 2160; 701 fps = 24; 702 break; 703 case HDMI_VFRMT_3840x2160p25_16_9: 704 width = 3840; 705 height = 2160; 706 fps = 25; 707 break; 708 case HDMI_VFRMT_3840x2160p30_16_9: 709 width = 3840; 710 height = 2160; 711 fps = 30; 712 break; 713 case HDMI_VFRMT_4096x2160p24_16_9: 714 width = 4096; 715 height = 2160; 716 fps = 24; 717 break; 718 719 } 720 } 721 722 }; 723