blob: 89d63e93f54e965771c4a7561bff6340ee9e7446 [file] [log] [blame]
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
Arun Kumar K.R25187572013-02-28 18:47:36 -08003 * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -07004 *
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
Naseer Ahmed72cf9762012-07-21 12:17:13 -070021#define DEBUG 0
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070022#include <ctype.h>
Naseer Ahmed72cf9762012-07-21 12:17:13 -070023#include <fcntl.h>
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070024#include <utils/threads.h>
25#include <utils/Errors.h>
26#include <utils/Log.h>
27
28#include <linux/msm_mdp.h>
Arun Kumar K.R25187572013-02-28 18:47:36 -080029#include <video/msm_hdmi_modes.h>
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070030#include <linux/fb.h>
31#include <sys/ioctl.h>
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070032#include <cutils/properties.h>
33#include "hwc_utils.h"
Saurabh Shah56f610d2012-08-07 15:27:06 -070034#include "external.h"
35#include "overlayUtils.h"
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080036#include "overlay.h"
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -070037#include "mdp_version.h"
Saurabh Shah56f610d2012-08-07 15:27:06 -070038
39using namespace android;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070040
41namespace qhwc {
Arun Kumar K.R26808f32013-02-11 19:17:05 -080042#define MAX_SYSFS_FILE_PATH 255
43#define UNKNOWN_STRING "unknown"
44#define SPD_NAME_LENGTH 16
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070045
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070046int ExternalDisplay::configure() {
47 if(!openFrameBuffer()) {
48 ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080049 return -1;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070050 }
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -080051 readCEUnderscanInfo();
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080052 readResolution();
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080053 // TODO: Move this to activate
Arun Kumar K.R37552c52012-12-10 12:47:18 -080054 /* Used for changing the resolution
55 * getUserMode will get the preferred
56 * mode set thru adb shell */
57 int mode = getUserMode();
58 if (mode == -1) {
59 //Get the best mode and set
60 mode = getBestMode();
61 }
62 setResolution(mode);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070063 setAttributes();
Amara Venkata Mastan Manoj Kumarb156a2f2013-02-07 16:42:50 -080064 // set system property
65 property_set("hw.hdmiON", "1");
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080066 return 0;
67}
68
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -070069void ExternalDisplay::getAttributes(int& width, int& height) {
70 int fps = 0;
71 getAttrForMode(width, height, fps);
72}
73
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070074int ExternalDisplay::teardown() {
75 closeFrameBuffer();
76 resetInfo();
77 // unset system property
78 property_set("hw.hdmiON", "0");
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080079 return 0;
80}
81
Naseer Ahmedf8ec1622012-07-31 18:56:23 -070082ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070083 mCurrentMode(-1), mModeCount(0),
84 mUnderscanSupported(false), mHwcContext(ctx)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070085{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -070086 memset(&mVInfo, 0, sizeof(mVInfo));
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070087 mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL);
Arun Kumar K.Re746ac52013-03-20 15:56:15 -070088 // disable HPD at start, it will be enabled later
89 // when the display powers on
90 // This helps for framework reboot or adb shell stop/start
91 writeHPDOption(0);
Amara Venkata Mastan Manoj Kumar11a380d2013-01-17 09:30:56 -080092
Arun Kumar K.R25187572013-02-28 18:47:36 -080093 // for HDMI - retreive all the modes supported by the driver
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070094 if(mFbNum != -1) {
Arun Kumar K.R25187572013-02-28 18:47:36 -080095 supported_video_mode_lut =
96 new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
97 // Populate the mode table for supported modes
98 MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut);
99 MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut,
100 MSM_HDMI_MODES_ALL);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800101 // Update the Source Product Information
102 // Vendor Name
103 setSPDInfo("vendor_name", "ro.product.manufacturer");
104 // Product Description
105 setSPDInfo("product_description", "ro.product.name");
106 }
107}
108/* gets the product manufacturer and product name and writes it
109 * to the sysfs node, so that the driver can get that information
110 * Used to show QCOM 8974 instead of Input 1 for example
111 */
112void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
113 int err = -1;
114 char info[PROPERTY_VALUE_MAX];
115 char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH];
116 memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
117 snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath),
118 "/sys/devices/virtual/graphics/fb%d/%s",
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700119 mFbNum, node);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800120 int spdFile = open(sysFsSPDFilePath, O_RDWR, 0);
121 if (spdFile < 0) {
122 ALOGE("%s: file '%s' not found : ret = %d"
123 "err str: %s", __FUNCTION__, sysFsSPDFilePath,
124 spdFile, strerror(errno));
125 } else {
126 memset(info, 0, sizeof(info));
127 property_get(property, info, UNKNOWN_STRING);
128 ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info);
129 if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) {
130 err = write(spdFile, info, strlen(info));
131 if (err <= 0) {
132 ALOGE("%s: file write failed for '%s'"
133 "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno);
134 }
135 } else {
136 ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s",
137 __FUNCTION__, node);
138 }
139 close(spdFile);
Arun Kumar K.R25187572013-02-28 18:47:36 -0800140 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700141}
142
Saurabh Shah56f610d2012-08-07 15:27:06 -0700143void ExternalDisplay::setHPD(uint32_t startEnd) {
144 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
145 writeHPDOption(startEnd);
146}
147
148void ExternalDisplay::setActionSafeDimension(int w, int h) {
149 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800150 char actionsafeWidth[PROPERTY_VALUE_MAX];
151 char actionsafeHeight[PROPERTY_VALUE_MAX];
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800152 snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
Arun Kumar K.R4d73d642013-04-10 17:06:39 -0700153 property_set("persist.sys.actionsafe.width", actionsafeWidth);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800154 snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
Arun Kumar K.R4d73d642013-04-10 17:06:39 -0700155 property_set("persist.sys.actionsafe.height", actionsafeHeight);
Saurabh Shah56f610d2012-08-07 15:27:06 -0700156}
157
158int ExternalDisplay::getModeCount() const {
159 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
Saurabh Shah56f610d2012-08-07 15:27:06 -0700160 return mModeCount;
161}
162
163void ExternalDisplay::getEDIDModes(int *out) const {
Saurabh Shah56f610d2012-08-07 15:27:06 -0700164 for(int i = 0;i < mModeCount;i++) {
165 out[i] = mEDIDModes[i];
166 }
167}
168
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800169void ExternalDisplay::readCEUnderscanInfo()
170{
171 int hdmiScanInfoFile = -1;
172 int len = -1;
173 char scanInfo[17];
174 char *ce_info_str = NULL;
175 const char token[] = ", \n";
176 int ce_info = -1;
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800177 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
178 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
179 "/sys/devices/virtual/graphics/fb%d/"
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700180 "scan_info", mFbNum);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800181
182 memset(scanInfo, 0, sizeof(scanInfo));
183 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
184 if (hdmiScanInfoFile < 0) {
185 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
186 __FUNCTION__, sysFsScanInfoFilePath);
187 return;
188 } else {
189 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
190 ALOGD("%s: Scan Info string: %s length = %d",
191 __FUNCTION__, scanInfo, len);
192 if (len <= 0) {
193 close(hdmiScanInfoFile);
194 ALOGE("%s: Scan Info file empty '%s'",
195 __FUNCTION__, sysFsScanInfoFilePath);
196 return;
197 }
198 scanInfo[len] = '\0'; /* null terminate the string */
199 }
200 close(hdmiScanInfoFile);
201
202 /*
203 * The scan_info contains the three fields
204 * PT - preferred video format
205 * IT - video format
206 * CE video format - containing the underscan support information
207 */
208
209 /* PT */
210 ce_info_str = strtok(scanInfo, token);
211 if (ce_info_str) {
212 /* IT */
213 ce_info_str = strtok(NULL, token);
214 if (ce_info_str) {
215 /* CE */
216 ce_info_str = strtok(NULL, token);
217 if (ce_info_str)
218 ce_info = atoi(ce_info_str);
219 }
220 }
221
222 if (ce_info_str) {
223 // ce_info contains the underscan information
224 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
225 ce_info == EXT_SCAN_BOTH_SUPPORTED)
226 // if TV supported underscan, then driver will always underscan
227 // hence no need to apply action safe rectangle
228 mUnderscanSupported = true;
229 } else {
230 ALOGE("%s: scan_info string error", __FUNCTION__);
231 }
232
233 // Store underscan support info in a system property
234 const char* prop = (mUnderscanSupported) ? "1" : "0";
235 property_set("hw.underscan_supported", prop);
236 return;
237}
238
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700239ExternalDisplay::~ExternalDisplay()
240{
Arun Kumar K.R25187572013-02-28 18:47:36 -0800241 delete [] supported_video_mode_lut;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700242 closeFrameBuffer();
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700243}
244
Arun Kumar K.R25187572013-02-28 18:47:36 -0800245/*
246 * sets the fb_var_screeninfo from the hdmi_mode_timing_info
247 */
248void setDisplayTiming(struct fb_var_screeninfo &info,
249 const msm_hdmi_mode_timing_info* mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700250{
251 info.reserved[0] = 0;
252 info.reserved[1] = 0;
253 info.reserved[2] = 0;
Ken Zhang7b03a952013-01-16 13:23:48 -0500254#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
Arun Kumar K.R25187572013-02-28 18:47:36 -0800255 info.reserved[3] = (info.reserved[3] & 0xFFFF) |
256 (mode->video_format << 16);
Ken Zhang7b03a952013-01-16 13:23:48 -0500257#endif
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700258 info.xoffset = 0;
259 info.yoffset = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800260 info.xres = mode->active_h;
261 info.yres = mode->active_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700262
Arun Kumar K.R25187572013-02-28 18:47:36 -0800263 info.pixclock = (mode->pixel_freq)*1000;
264 info.vmode = mode->interlaced ?
265 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700266
Arun Kumar K.R25187572013-02-28 18:47:36 -0800267 info.right_margin = mode->front_porch_h;
268 info.hsync_len = mode->pulse_width_h;
269 info.left_margin = mode->back_porch_h;
270 info.lower_margin = mode->front_porch_v;
271 info.vsync_len = mode->pulse_width_v;
272 info.upper_margin = mode->back_porch_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700273}
274
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700275int ExternalDisplay::parseResolution(char* edidStr, int* edidModes)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700276{
277 char delim = ',';
278 int count = 0;
279 char *start, *end;
280 // EDIDs are string delimited by ','
281 // Ex: 16,4,5,3,32,34,1
282 // Parse this string to get mode(int)
283 start = (char*) edidStr;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700284 end = &delim;
285 while(*end == delim) {
286 edidModes[count] = (int) strtol(start, &end, 10);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700287 start = end+1;
288 count++;
289 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700290 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
291 for (int i = 0; i < count; i++)
292 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700293 return count;
294}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700295
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700296bool ExternalDisplay::readResolution()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700297{
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800298 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
299 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700300 "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800301
302 int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700303 int len = -1;
304
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700305 if (hdmiEDIDFile < 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700306 ALOGE("%s: edid_modes file '%s' not found",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800307 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700308 return false;
309 } else {
310 len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700311 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
312 __FUNCTION__, mEDIDs, len);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700313 if ( len <= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700314 ALOGE("%s: edid_modes file empty '%s'",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800315 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700316 }
317 else {
318 while (len > 1 && isspace(mEDIDs[len-1]))
319 --len;
320 mEDIDs[len] = 0;
321 }
322 }
323 close(hdmiEDIDFile);
324 if(len > 0) {
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800325 // Get EDID modes from the EDID strings
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700326 mModeCount = parseResolution(mEDIDs, mEDIDModes);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700327 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
328 mModeCount);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700329 }
330
331 return (strlen(mEDIDs) > 0);
332}
333
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700334bool ExternalDisplay::openFrameBuffer()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700335{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700336 if (mFd == -1) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700337 char strDevPath[MAX_SYSFS_FILE_PATH];
338 snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
339 mFd = open(strDevPath, O_RDWR);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700340 if (mFd < 0)
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700341 ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
342 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700343 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700344 return (mFd > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700345}
346
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700347bool ExternalDisplay::closeFrameBuffer()
348{
349 int ret = 0;
Naseer Ahmedf53b3772013-02-15 19:13:50 -0500350 if(mFd >= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700351 ret = close(mFd);
352 mFd = -1;
353 }
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700354 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700355 return (ret == 0);
356}
357
358// clears the vinfo, edid, best modes
359void ExternalDisplay::resetInfo()
360{
361 memset(&mVInfo, 0, sizeof(mVInfo));
362 memset(mEDIDs, 0, sizeof(mEDIDs));
363 memset(mEDIDModes, 0, sizeof(mEDIDModes));
364 mModeCount = 0;
365 mCurrentMode = -1;
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800366 mUnderscanSupported = false;
367 // Reset the underscan supported system property
368 const char* prop = "0";
369 property_set("hw.underscan_supported", prop);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700370}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700371
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700372int ExternalDisplay::getModeOrder(int mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700373{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800374 // XXX: We dont support interlaced modes but having
Arun Kumar K.R25187572013-02-28 18:47:36 -0800375 // it here for future
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700376 switch (mode) {
377 default:
Arun Kumar K.R25187572013-02-28 18:47:36 -0800378 case HDMI_VFRMT_1440x480i60_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700379 return 1; // 480i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800380 case HDMI_VFRMT_1440x480i60_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700381 return 2; // 480i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800382 case HDMI_VFRMT_1440x576i50_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700383 return 3; // i576i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800384 case HDMI_VFRMT_1440x576i50_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700385 return 4; // 576i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800386 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800387 return 5; // 1080i 16:9
388 case HDMI_VFRMT_640x480p60_4_3:
389 return 6; // 640x480 4:3
390 case HDMI_VFRMT_720x480p60_4_3:
391 return 7; // 480p 4:3
392 case HDMI_VFRMT_720x480p60_16_9:
393 return 8; // 480p 16:9
394 case HDMI_VFRMT_720x576p50_4_3:
395 return 9; // 576p 4:3
396 case HDMI_VFRMT_720x576p50_16_9:
397 return 10; // 576p 16:9
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700398 case HDMI_VFRMT_1024x768p60_4_3:
399 return 11; // 768p 4:3 Vesa format
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800400 case HDMI_VFRMT_1280x1024p60_5_4:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700401 return 12; // 1024p Vesa format
Arun Kumar K.R25187572013-02-28 18:47:36 -0800402 case HDMI_VFRMT_1280x720p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700403 return 13; // 720p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800404 case HDMI_VFRMT_1280x720p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700405 return 14; // 720p@60Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800406 case HDMI_VFRMT_1920x1080p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700407 return 15; //1080p@24Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800408 case HDMI_VFRMT_1920x1080p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700409 return 16; //108-p@25Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800410 case HDMI_VFRMT_1920x1080p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700411 return 17; //1080p@30Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800412 case HDMI_VFRMT_1920x1080p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700413 return 18; //1080p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800414 case HDMI_VFRMT_1920x1080p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700415 return 19; //1080p@60Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800416 case HDMI_VFRMT_2560x1600p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700417 return 20; //WQXGA@60Hz541
Ujwal Patelb9430d22012-11-15 18:10:19 -0800418 case HDMI_VFRMT_3840x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700419 return 21;//2160@24Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800420 case HDMI_VFRMT_3840x2160p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700421 return 22;//2160@25Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800422 case HDMI_VFRMT_3840x2160p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700423 return 23; //2160@30Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800424 case HDMI_VFRMT_4096x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700425 return 24; //4kx2k@24Hz
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700426 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700427}
428
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800429/// Returns the user mode set(if any) using adb shell
430int ExternalDisplay::getUserMode() {
431 /* Based on the property set the resolution */
432 char property_value[PROPERTY_VALUE_MAX];
Arun Kumar K.Rc31bdcb2013-02-25 17:47:42 -0800433 property_get("hw.hdmi.resolution", property_value, "-1");
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800434 int mode = atoi(property_value);
435 // We dont support interlaced modes
436 if(isValidMode(mode) && !isInterlacedMode(mode)) {
Naseer Ahmed74214722013-02-09 08:11:36 -0500437 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800438 return mode;
439 }
440 return -1;
441}
442
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700443// Get the best mode for the current HD TV
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700444int ExternalDisplay::getBestMode() {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700445 int bestOrder = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800446 int bestMode = HDMI_VFRMT_640x480p60_4_3;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700447 // for all the edid read, get the best mode
448 for(int i = 0; i < mModeCount; i++) {
449 int mode = mEDIDModes[i];
450 int order = getModeOrder(mode);
451 if (order > bestOrder) {
452 bestOrder = order;
453 bestMode = mode;
454 }
455 }
456 return bestMode;
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700457}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700458
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700459inline bool ExternalDisplay::isValidMode(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700460{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800461 bool valid = false;
462 for (int i = 0; i < mModeCount; i++) {
463 if(ID == mEDIDModes[i]) {
464 valid = true;
465 break;
466 }
467 }
468 return valid;
469}
470
471// returns true if the mode(ID) is interlaced mode format
472bool ExternalDisplay::isInterlacedMode(int ID) {
473 bool interlaced = false;
474 switch(ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800475 case HDMI_VFRMT_1440x480i60_4_3:
476 case HDMI_VFRMT_1440x480i60_16_9:
477 case HDMI_VFRMT_1440x576i50_4_3:
478 case HDMI_VFRMT_1440x576i50_16_9:
479 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800480 interlaced = true;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700481 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800482 default:
483 interlaced = false;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700484 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800485 }
486 return interlaced;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700487}
488
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700489void ExternalDisplay::setResolution(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700490{
491 struct fb_var_screeninfo info;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700492 int ret = 0;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700493 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
494 if(ret < 0) {
495 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
496 strerror(errno));
497 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700498 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
499 "(%d,%d,%d) %dMHz>", __FUNCTION__,
500 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
501 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
502 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
503 mVInfo.pixclock/1000/1000);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800504 //If its a new ID - update var_screeninfo
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700505 if ((isValidMode(ID)) && mCurrentMode != ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800506 const struct msm_hdmi_mode_timing_info *mode =
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700507 &supported_video_mode_lut[0];
Arun Kumar K.R25187572013-02-28 18:47:36 -0800508 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
509 const struct msm_hdmi_mode_timing_info *cur =
510 &supported_video_mode_lut[i];
511 if (cur->video_format == (uint32_t)ID) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700512 mode = cur;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800513 break;
514 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700515 }
Arun Kumar K.R25187572013-02-28 18:47:36 -0800516 setDisplayTiming(mVInfo, mode);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700517 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700518 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800519 mode->video_format, mVInfo.xres, mVInfo.yres,
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700520 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
521 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
522 mVInfo.pixclock/1000/1000);
Ken Zhang7b03a952013-01-16 13:23:48 -0500523#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
524 struct msmfb_metadata metadata;
525 memset(&metadata, 0 , sizeof(metadata));
526 metadata.op = metadata_op_vic;
527 metadata.data.video_info_code = mode->video_format;
528 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
529 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
530 __FUNCTION__, strerror(errno));
531 }
532#endif
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800533 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
534 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
535 if(ret < 0) {
536 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
537 __FUNCTION__, strerror(errno));
538 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700539 mCurrentMode = ID;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700540 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700541}
542
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700543bool ExternalDisplay::writeHPDOption(int userOption) const
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700544{
545 bool ret = true;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700546 if(mFbNum != -1) {
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700547 char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
548 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700549 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700550 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
551 if (hdmiHPDFile < 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700552 ALOGE("%s: state file '%s' not found : ret%d err str: %s",
553 __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700554 ret = false;
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700555 } else {
556 int err = -1;
557 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
558 if(userOption)
559 err = write(hdmiHPDFile, "1", 2);
560 else
561 err = write(hdmiHPDFile, "0" , 2);
562 if (err <= 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700563 ALOGE("%s: file write failed '%s'", __FUNCTION__,
564 sysFsHPDFilePath);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700565 ret = false;
566 }
567 close(hdmiHPDFile);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700568 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700569 }
570 return ret;
571}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700572
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700573
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700574void ExternalDisplay::setAttributes() {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700575 int width = 0, height = 0, fps = 0;
576 getAttrForMode(width, height, fps);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700577 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700578 if(mHwcContext) {
579 // Always set dpyAttr res to mVInfo res
580 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
581 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
582 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
583 if(!qdutils::MDPVersion::getInstance().is8x26()) {
584 int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
585 int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
586 // if primary resolution is more than the hdmi resolution
587 // configure dpy attr to primary resolution and set
588 // downscale mode
589 if((priW * priH) > (width * height)) {
590 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
591 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
592 // HDMI is always in landscape, so always assign the higher
593 // dimension to hdmi's xres
594 if(priH > priW) {
595 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priH;
596 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priW;
597 }
598 // Set External Display MDP Downscale mode indicator
599 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
600 }
601 }
602 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
603 1000000000l / fps;
604 }
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700605}
606
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800607void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700608 switch (mCurrentMode) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800609 case HDMI_VFRMT_640x480p60_4_3:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700610 width = 640;
611 height = 480;
612 fps = 60;
613 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800614 case HDMI_VFRMT_720x480p60_4_3:
615 case HDMI_VFRMT_720x480p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700616 width = 720;
617 height = 480;
618 fps = 60;
619 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800620 case HDMI_VFRMT_720x576p50_4_3:
621 case HDMI_VFRMT_720x576p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700622 width = 720;
623 height = 576;
624 fps = 50;
625 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800626 case HDMI_VFRMT_1280x720p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700627 width = 1280;
628 height = 720;
629 fps = 50;
630 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800631 case HDMI_VFRMT_1280x720p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700632 width = 1280;
633 height = 720;
634 fps = 60;
635 break;
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800636 case HDMI_VFRMT_1280x1024p60_5_4:
637 width = 1280;
638 height = 1024;
639 fps = 60;
640 break;
Manoj Rao564ee922013-05-07 21:32:57 -0700641 case HDMI_VFRMT_1024x768p60_4_3:
642 width = 1024;
643 height = 768;
644 fps = 60;
645 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800646 case HDMI_VFRMT_1920x1080p24_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700647 width = 1920;
648 height = 1080;
649 fps = 24;
650 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800651 case HDMI_VFRMT_1920x1080p25_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700652 width = 1920;
653 height = 1080;
654 fps = 25;
655 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800656 case HDMI_VFRMT_1920x1080p30_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700657 width = 1920;
658 height = 1080;
659 fps = 30;
660 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800661 case HDMI_VFRMT_1920x1080p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700662 width = 1920;
663 height = 1080;
664 fps = 50;
665 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800666 case HDMI_VFRMT_1920x1080p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700667 width = 1920;
668 height = 1080;
669 fps = 60;
670 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800671 case HDMI_VFRMT_2560x1600p60_16_9:
672 width = 2560;
673 height = 1600;
674 fps = 60;
675 break;
676 case HDMI_VFRMT_3840x2160p24_16_9:
677 width = 3840;
678 height = 2160;
679 fps = 24;
680 break;
Arun Kumar K.R92ebf9d2013-04-09 19:23:14 -0700681 case HDMI_VFRMT_3840x2160p25_16_9:
682 width = 3840;
683 height = 2160;
684 fps = 25;
685 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800686 case HDMI_VFRMT_3840x2160p30_16_9:
687 width = 3840;
688 height = 2160;
689 fps = 30;
690 break;
691 case HDMI_VFRMT_4096x2160p24_16_9:
692 width = 4096;
693 height = 2160;
694 fps = 24;
695 break;
696
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700697 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700698}
699
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700700};