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