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