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
configure()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
getAttributes(int & width,int & height)72 void ExternalDisplay::getAttributes(int& width, int& height) {
73 int fps = 0;
74 getAttrForMode(width, height, fps);
75 }
76
teardown()77 int ExternalDisplay::teardown() {
78 closeFrameBuffer();
79 resetInfo();
80 // unset system property
81 property_set("hw.hdmiON", "0");
82 return 0;
83 }
84
ExternalDisplay(hwc_context_t * ctx)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 */
setSPDInfo(const char * node,const char * property)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
setHPD(uint32_t startEnd)146 void ExternalDisplay::setHPD(uint32_t startEnd) {
147 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
148 writeHPDOption(startEnd);
149 }
150
setActionSafeDimension(int w,int h)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
getModeCount() const161 int ExternalDisplay::getModeCount() const {
162 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
163 return mModeCount;
164 }
165
getEDIDModes(int * out) const166 void ExternalDisplay::getEDIDModes(int *out) const {
167 for(int i = 0;i < mModeCount;i++) {
168 out[i] = mEDIDModes[i];
169 }
170 }
171
readCEUnderscanInfo()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
~ExternalDisplay()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 */
setDisplayTiming(struct fb_var_screeninfo & info,const msm_hdmi_mode_timing_info * mode)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
parseResolution(char * edidStr,int * edidModes)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
readResolution()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
openFrameBuffer()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
closeFrameBuffer()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
resetInfo()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
getModeOrder(int mode)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
getUserMode()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
getBestMode()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
isValidMode(int ID)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
isInterlacedMode(int ID)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
setResolution(int ID)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
writeHPDOption(int userOption) const548 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
setAttributes()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
getAttrForMode(int & width,int & height,int & fps)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