blob: b247dfbeeac7fbfe2a2a4864257080c47c6aacd9 [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"
Saurabh Shah56f610d2012-08-07 15:27:06 -070037
38using namespace android;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070039
40namespace qhwc {
Arun Kumar K.R26808f32013-02-11 19:17:05 -080041#define MAX_SYSFS_FILE_PATH 255
42#define UNKNOWN_STRING "unknown"
43#define SPD_NAME_LENGTH 16
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070044
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070045int ExternalDisplay::configure() {
46 if(!openFrameBuffer()) {
47 ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080048 return -1;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070049 }
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -080050 readCEUnderscanInfo();
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080051 readResolution();
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080052 // TODO: Move this to activate
Arun Kumar K.R37552c52012-12-10 12:47:18 -080053 /* Used for changing the resolution
54 * getUserMode will get the preferred
55 * mode set thru adb shell */
56 int mode = getUserMode();
57 if (mode == -1) {
58 //Get the best mode and set
59 mode = getBestMode();
60 }
61 setResolution(mode);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070062 setAttributes();
Amara Venkata Mastan Manoj Kumarb156a2f2013-02-07 16:42:50 -080063 // set system property
64 property_set("hw.hdmiON", "1");
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080065 return 0;
66}
67
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070068int ExternalDisplay::teardown() {
69 closeFrameBuffer();
70 resetInfo();
71 // unset system property
72 property_set("hw.hdmiON", "0");
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080073 return 0;
74}
75
Naseer Ahmedf8ec1622012-07-31 18:56:23 -070076ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070077 mCurrentMode(-1), mModeCount(0),
78 mUnderscanSupported(false), mHwcContext(ctx)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070079{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -070080 memset(&mVInfo, 0, sizeof(mVInfo));
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070081 mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL);
Arun Kumar K.Re746ac52013-03-20 15:56:15 -070082 // disable HPD at start, it will be enabled later
83 // when the display powers on
84 // This helps for framework reboot or adb shell stop/start
85 writeHPDOption(0);
Amara Venkata Mastan Manoj Kumar11a380d2013-01-17 09:30:56 -080086
Arun Kumar K.R25187572013-02-28 18:47:36 -080087 // for HDMI - retreive all the modes supported by the driver
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070088 if(mFbNum != -1) {
Arun Kumar K.R25187572013-02-28 18:47:36 -080089 supported_video_mode_lut =
90 new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
91 // Populate the mode table for supported modes
92 MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut);
93 MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut,
94 MSM_HDMI_MODES_ALL);
Arun Kumar K.R26808f32013-02-11 19:17:05 -080095 // Update the Source Product Information
96 // Vendor Name
97 setSPDInfo("vendor_name", "ro.product.manufacturer");
98 // Product Description
99 setSPDInfo("product_description", "ro.product.name");
100 }
101}
102/* gets the product manufacturer and product name and writes it
103 * to the sysfs node, so that the driver can get that information
104 * Used to show QCOM 8974 instead of Input 1 for example
105 */
106void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
107 int err = -1;
108 char info[PROPERTY_VALUE_MAX];
109 char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH];
110 memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
111 snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath),
112 "/sys/devices/virtual/graphics/fb%d/%s",
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700113 mFbNum, node);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800114 int spdFile = open(sysFsSPDFilePath, O_RDWR, 0);
115 if (spdFile < 0) {
116 ALOGE("%s: file '%s' not found : ret = %d"
117 "err str: %s", __FUNCTION__, sysFsSPDFilePath,
118 spdFile, strerror(errno));
119 } else {
120 memset(info, 0, sizeof(info));
121 property_get(property, info, UNKNOWN_STRING);
122 ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info);
123 if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) {
124 err = write(spdFile, info, strlen(info));
125 if (err <= 0) {
126 ALOGE("%s: file write failed for '%s'"
127 "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno);
128 }
129 } else {
130 ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s",
131 __FUNCTION__, node);
132 }
133 close(spdFile);
Arun Kumar K.R25187572013-02-28 18:47:36 -0800134 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700135}
136
Saurabh Shah56f610d2012-08-07 15:27:06 -0700137void ExternalDisplay::setHPD(uint32_t startEnd) {
138 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
139 writeHPDOption(startEnd);
140}
141
142void ExternalDisplay::setActionSafeDimension(int w, int h) {
143 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800144 char actionsafeWidth[PROPERTY_VALUE_MAX];
145 char actionsafeHeight[PROPERTY_VALUE_MAX];
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800146 snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
Arun Kumar K.R4d73d642013-04-10 17:06:39 -0700147 property_set("persist.sys.actionsafe.width", actionsafeWidth);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800148 snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
Arun Kumar K.R4d73d642013-04-10 17:06:39 -0700149 property_set("persist.sys.actionsafe.height", actionsafeHeight);
Saurabh Shah56f610d2012-08-07 15:27:06 -0700150}
151
152int ExternalDisplay::getModeCount() const {
153 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
Saurabh Shah56f610d2012-08-07 15:27:06 -0700154 return mModeCount;
155}
156
157void ExternalDisplay::getEDIDModes(int *out) const {
Saurabh Shah56f610d2012-08-07 15:27:06 -0700158 for(int i = 0;i < mModeCount;i++) {
159 out[i] = mEDIDModes[i];
160 }
161}
162
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800163void ExternalDisplay::readCEUnderscanInfo()
164{
165 int hdmiScanInfoFile = -1;
166 int len = -1;
167 char scanInfo[17];
168 char *ce_info_str = NULL;
169 const char token[] = ", \n";
170 int ce_info = -1;
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800171 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
172 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
173 "/sys/devices/virtual/graphics/fb%d/"
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700174 "scan_info", mFbNum);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800175
176 memset(scanInfo, 0, sizeof(scanInfo));
177 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
178 if (hdmiScanInfoFile < 0) {
179 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
180 __FUNCTION__, sysFsScanInfoFilePath);
181 return;
182 } else {
183 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
184 ALOGD("%s: Scan Info string: %s length = %d",
185 __FUNCTION__, scanInfo, len);
186 if (len <= 0) {
187 close(hdmiScanInfoFile);
188 ALOGE("%s: Scan Info file empty '%s'",
189 __FUNCTION__, sysFsScanInfoFilePath);
190 return;
191 }
192 scanInfo[len] = '\0'; /* null terminate the string */
193 }
194 close(hdmiScanInfoFile);
195
196 /*
197 * The scan_info contains the three fields
198 * PT - preferred video format
199 * IT - video format
200 * CE video format - containing the underscan support information
201 */
202
203 /* PT */
204 ce_info_str = strtok(scanInfo, token);
205 if (ce_info_str) {
206 /* IT */
207 ce_info_str = strtok(NULL, token);
208 if (ce_info_str) {
209 /* CE */
210 ce_info_str = strtok(NULL, token);
211 if (ce_info_str)
212 ce_info = atoi(ce_info_str);
213 }
214 }
215
216 if (ce_info_str) {
217 // ce_info contains the underscan information
218 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
219 ce_info == EXT_SCAN_BOTH_SUPPORTED)
220 // if TV supported underscan, then driver will always underscan
221 // hence no need to apply action safe rectangle
222 mUnderscanSupported = true;
223 } else {
224 ALOGE("%s: scan_info string error", __FUNCTION__);
225 }
226
227 // Store underscan support info in a system property
228 const char* prop = (mUnderscanSupported) ? "1" : "0";
229 property_set("hw.underscan_supported", prop);
230 return;
231}
232
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700233ExternalDisplay::~ExternalDisplay()
234{
Arun Kumar K.R25187572013-02-28 18:47:36 -0800235 delete [] supported_video_mode_lut;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700236 closeFrameBuffer();
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700237}
238
Arun Kumar K.R25187572013-02-28 18:47:36 -0800239/*
240 * sets the fb_var_screeninfo from the hdmi_mode_timing_info
241 */
242void setDisplayTiming(struct fb_var_screeninfo &info,
243 const msm_hdmi_mode_timing_info* mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700244{
245 info.reserved[0] = 0;
246 info.reserved[1] = 0;
247 info.reserved[2] = 0;
Ken Zhang7b03a952013-01-16 13:23:48 -0500248#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
Arun Kumar K.R25187572013-02-28 18:47:36 -0800249 info.reserved[3] = (info.reserved[3] & 0xFFFF) |
250 (mode->video_format << 16);
Ken Zhang7b03a952013-01-16 13:23:48 -0500251#endif
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700252 info.xoffset = 0;
253 info.yoffset = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800254 info.xres = mode->active_h;
255 info.yres = mode->active_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700256
Arun Kumar K.R25187572013-02-28 18:47:36 -0800257 info.pixclock = (mode->pixel_freq)*1000;
258 info.vmode = mode->interlaced ?
259 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700260
Arun Kumar K.R25187572013-02-28 18:47:36 -0800261 info.right_margin = mode->front_porch_h;
262 info.hsync_len = mode->pulse_width_h;
263 info.left_margin = mode->back_porch_h;
264 info.lower_margin = mode->front_porch_v;
265 info.vsync_len = mode->pulse_width_v;
266 info.upper_margin = mode->back_porch_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700267}
268
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700269int ExternalDisplay::parseResolution(char* edidStr, int* edidModes)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700270{
271 char delim = ',';
272 int count = 0;
273 char *start, *end;
274 // EDIDs are string delimited by ','
275 // Ex: 16,4,5,3,32,34,1
276 // Parse this string to get mode(int)
277 start = (char*) edidStr;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700278 end = &delim;
279 while(*end == delim) {
280 edidModes[count] = (int) strtol(start, &end, 10);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700281 start = end+1;
282 count++;
283 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700284 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
285 for (int i = 0; i < count; i++)
286 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700287 return count;
288}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700289
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700290bool ExternalDisplay::readResolution()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700291{
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800292 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
293 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700294 "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800295
296 int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700297 int len = -1;
298
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700299 if (hdmiEDIDFile < 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700300 ALOGE("%s: edid_modes file '%s' not found",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800301 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700302 return false;
303 } else {
304 len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700305 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
306 __FUNCTION__, mEDIDs, len);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700307 if ( len <= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700308 ALOGE("%s: edid_modes file empty '%s'",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800309 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700310 }
311 else {
312 while (len > 1 && isspace(mEDIDs[len-1]))
313 --len;
314 mEDIDs[len] = 0;
315 }
316 }
317 close(hdmiEDIDFile);
318 if(len > 0) {
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800319 // Get EDID modes from the EDID strings
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700320 mModeCount = parseResolution(mEDIDs, mEDIDModes);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700321 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
322 mModeCount);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700323 }
324
325 return (strlen(mEDIDs) > 0);
326}
327
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700328bool ExternalDisplay::openFrameBuffer()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700329{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700330 if (mFd == -1) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700331 char strDevPath[MAX_SYSFS_FILE_PATH];
332 snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
333 mFd = open(strDevPath, O_RDWR);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700334 if (mFd < 0)
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700335 ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
336 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700337 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700338 return (mFd > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700339}
340
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700341bool ExternalDisplay::closeFrameBuffer()
342{
343 int ret = 0;
Naseer Ahmedf53b3772013-02-15 19:13:50 -0500344 if(mFd >= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700345 ret = close(mFd);
346 mFd = -1;
347 }
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700348 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700349 return (ret == 0);
350}
351
352// clears the vinfo, edid, best modes
353void ExternalDisplay::resetInfo()
354{
355 memset(&mVInfo, 0, sizeof(mVInfo));
356 memset(mEDIDs, 0, sizeof(mEDIDs));
357 memset(mEDIDModes, 0, sizeof(mEDIDModes));
358 mModeCount = 0;
359 mCurrentMode = -1;
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800360 mUnderscanSupported = false;
361 // Reset the underscan supported system property
362 const char* prop = "0";
363 property_set("hw.underscan_supported", prop);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700364}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700365
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700366int ExternalDisplay::getModeOrder(int mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700367{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800368 // XXX: We dont support interlaced modes but having
Arun Kumar K.R25187572013-02-28 18:47:36 -0800369 // it here for future
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700370 switch (mode) {
371 default:
Arun Kumar K.R25187572013-02-28 18:47:36 -0800372 case HDMI_VFRMT_1440x480i60_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700373 return 1; // 480i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800374 case HDMI_VFRMT_1440x480i60_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700375 return 2; // 480i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800376 case HDMI_VFRMT_1440x576i50_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700377 return 3; // i576i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800378 case HDMI_VFRMT_1440x576i50_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700379 return 4; // 576i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800380 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800381 return 5; // 1080i 16:9
382 case HDMI_VFRMT_640x480p60_4_3:
383 return 6; // 640x480 4:3
384 case HDMI_VFRMT_720x480p60_4_3:
385 return 7; // 480p 4:3
386 case HDMI_VFRMT_720x480p60_16_9:
387 return 8; // 480p 16:9
388 case HDMI_VFRMT_720x576p50_4_3:
389 return 9; // 576p 4:3
390 case HDMI_VFRMT_720x576p50_16_9:
391 return 10; // 576p 16:9
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700392 case HDMI_VFRMT_1024x768p60_4_3:
393 return 11; // 768p 4:3 Vesa format
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800394 case HDMI_VFRMT_1280x1024p60_5_4:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700395 return 12; // 1024p Vesa format
Arun Kumar K.R25187572013-02-28 18:47:36 -0800396 case HDMI_VFRMT_1280x720p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700397 return 13; // 720p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800398 case HDMI_VFRMT_1280x720p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700399 return 14; // 720p@60Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800400 case HDMI_VFRMT_1920x1080p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700401 return 15; //1080p@24Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800402 case HDMI_VFRMT_1920x1080p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700403 return 16; //108-p@25Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800404 case HDMI_VFRMT_1920x1080p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700405 return 17; //1080p@30Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800406 case HDMI_VFRMT_1920x1080p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700407 return 18; //1080p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800408 case HDMI_VFRMT_1920x1080p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700409 return 19; //1080p@60Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800410 case HDMI_VFRMT_2560x1600p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700411 return 20; //WQXGA@60Hz541
Ujwal Patelb9430d22012-11-15 18:10:19 -0800412 case HDMI_VFRMT_3840x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700413 return 21;//2160@24Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800414 case HDMI_VFRMT_3840x2160p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700415 return 22;//2160@25Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800416 case HDMI_VFRMT_3840x2160p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700417 return 23; //2160@30Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800418 case HDMI_VFRMT_4096x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700419 return 24; //4kx2k@24Hz
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700420 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700421}
422
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800423/// Returns the user mode set(if any) using adb shell
424int ExternalDisplay::getUserMode() {
425 /* Based on the property set the resolution */
426 char property_value[PROPERTY_VALUE_MAX];
Arun Kumar K.Rc31bdcb2013-02-25 17:47:42 -0800427 property_get("hw.hdmi.resolution", property_value, "-1");
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800428 int mode = atoi(property_value);
429 // We dont support interlaced modes
430 if(isValidMode(mode) && !isInterlacedMode(mode)) {
Naseer Ahmed74214722013-02-09 08:11:36 -0500431 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800432 return mode;
433 }
434 return -1;
435}
436
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700437// Get the best mode for the current HD TV
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700438int ExternalDisplay::getBestMode() {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700439 int bestOrder = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800440 int bestMode = HDMI_VFRMT_640x480p60_4_3;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700441 // for all the edid read, get the best mode
442 for(int i = 0; i < mModeCount; i++) {
443 int mode = mEDIDModes[i];
444 int order = getModeOrder(mode);
445 if (order > bestOrder) {
446 bestOrder = order;
447 bestMode = mode;
448 }
449 }
450 return bestMode;
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700451}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700452
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700453inline bool ExternalDisplay::isValidMode(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700454{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800455 bool valid = false;
456 for (int i = 0; i < mModeCount; i++) {
457 if(ID == mEDIDModes[i]) {
458 valid = true;
459 break;
460 }
461 }
462 return valid;
463}
464
465// returns true if the mode(ID) is interlaced mode format
466bool ExternalDisplay::isInterlacedMode(int ID) {
467 bool interlaced = false;
468 switch(ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800469 case HDMI_VFRMT_1440x480i60_4_3:
470 case HDMI_VFRMT_1440x480i60_16_9:
471 case HDMI_VFRMT_1440x576i50_4_3:
472 case HDMI_VFRMT_1440x576i50_16_9:
473 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800474 interlaced = true;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700475 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800476 default:
477 interlaced = false;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700478 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800479 }
480 return interlaced;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700481}
482
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700483void ExternalDisplay::setResolution(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700484{
485 struct fb_var_screeninfo info;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700486 int ret = 0;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700487 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
488 if(ret < 0) {
489 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
490 strerror(errno));
491 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700492 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
493 "(%d,%d,%d) %dMHz>", __FUNCTION__,
494 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
495 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
496 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
497 mVInfo.pixclock/1000/1000);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800498 //If its a new ID - update var_screeninfo
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700499 if ((isValidMode(ID)) && mCurrentMode != ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800500 const struct msm_hdmi_mode_timing_info *mode =
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700501 &supported_video_mode_lut[0];
Arun Kumar K.R25187572013-02-28 18:47:36 -0800502 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
503 const struct msm_hdmi_mode_timing_info *cur =
504 &supported_video_mode_lut[i];
505 if (cur->video_format == (uint32_t)ID) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700506 mode = cur;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800507 break;
508 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700509 }
Arun Kumar K.R25187572013-02-28 18:47:36 -0800510 setDisplayTiming(mVInfo, mode);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700511 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700512 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800513 mode->video_format, mVInfo.xres, mVInfo.yres,
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700514 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
515 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
516 mVInfo.pixclock/1000/1000);
Ken Zhang7b03a952013-01-16 13:23:48 -0500517#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
518 struct msmfb_metadata metadata;
519 memset(&metadata, 0 , sizeof(metadata));
520 metadata.op = metadata_op_vic;
521 metadata.data.video_info_code = mode->video_format;
522 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
523 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
524 __FUNCTION__, strerror(errno));
525 }
526#endif
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800527 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
528 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
529 if(ret < 0) {
530 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
531 __FUNCTION__, strerror(errno));
532 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700533 mCurrentMode = ID;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700534 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700535}
536
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700537bool ExternalDisplay::writeHPDOption(int userOption) const
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700538{
539 bool ret = true;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700540 if(mFbNum != -1) {
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700541 char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
542 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700543 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700544 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
545 if (hdmiHPDFile < 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700546 ALOGE("%s: state file '%s' not found : ret%d err str: %s",
547 __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700548 ret = false;
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700549 } else {
550 int err = -1;
551 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
552 if(userOption)
553 err = write(hdmiHPDFile, "1", 2);
554 else
555 err = write(hdmiHPDFile, "0" , 2);
556 if (err <= 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700557 ALOGE("%s: file write failed '%s'", __FUNCTION__,
558 sysFsHPDFilePath);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700559 ret = false;
560 }
561 close(hdmiHPDFile);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700562 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700563 }
564 return ret;
565}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700566
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700567void ExternalDisplay::setAttributes() {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700568 int width = 0, height = 0, fps = 0;
569 getAttrForMode(width, height, fps);
Ramkumar Radhakrishnan31f4c4e2013-08-22 13:32:18 -0700570
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700571 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
Ramkumar Radhakrishnan31f4c4e2013-08-22 13:32:18 -0700572 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
573 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
574 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
575 1000000000l / fps;
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700576}
577
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800578void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700579 switch (mCurrentMode) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800580 case HDMI_VFRMT_640x480p60_4_3:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700581 width = 640;
582 height = 480;
583 fps = 60;
584 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800585 case HDMI_VFRMT_720x480p60_4_3:
586 case HDMI_VFRMT_720x480p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700587 width = 720;
588 height = 480;
589 fps = 60;
590 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800591 case HDMI_VFRMT_720x576p50_4_3:
592 case HDMI_VFRMT_720x576p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700593 width = 720;
594 height = 576;
595 fps = 50;
596 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800597 case HDMI_VFRMT_1280x720p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700598 width = 1280;
599 height = 720;
600 fps = 50;
601 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800602 case HDMI_VFRMT_1280x720p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700603 width = 1280;
604 height = 720;
605 fps = 60;
606 break;
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800607 case HDMI_VFRMT_1280x1024p60_5_4:
608 width = 1280;
609 height = 1024;
610 fps = 60;
611 break;
Manoj Rao564ee922013-05-07 21:32:57 -0700612 case HDMI_VFRMT_1024x768p60_4_3:
613 width = 1024;
614 height = 768;
615 fps = 60;
616 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800617 case HDMI_VFRMT_1920x1080p24_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700618 width = 1920;
619 height = 1080;
620 fps = 24;
621 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800622 case HDMI_VFRMT_1920x1080p25_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700623 width = 1920;
624 height = 1080;
625 fps = 25;
626 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800627 case HDMI_VFRMT_1920x1080p30_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700628 width = 1920;
629 height = 1080;
630 fps = 30;
631 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800632 case HDMI_VFRMT_1920x1080p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700633 width = 1920;
634 height = 1080;
635 fps = 50;
636 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800637 case HDMI_VFRMT_1920x1080p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700638 width = 1920;
639 height = 1080;
640 fps = 60;
641 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800642 case HDMI_VFRMT_2560x1600p60_16_9:
643 width = 2560;
644 height = 1600;
645 fps = 60;
646 break;
647 case HDMI_VFRMT_3840x2160p24_16_9:
648 width = 3840;
649 height = 2160;
650 fps = 24;
651 break;
Arun Kumar K.R92ebf9d2013-04-09 19:23:14 -0700652 case HDMI_VFRMT_3840x2160p25_16_9:
653 width = 3840;
654 height = 2160;
655 fps = 25;
656 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800657 case HDMI_VFRMT_3840x2160p30_16_9:
658 width = 3840;
659 height = 2160;
660 fps = 30;
661 break;
662 case HDMI_VFRMT_4096x2160p24_16_9:
663 width = 4096;
664 height = 2160;
665 fps = 24;
666 break;
667
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700668 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700669}
670
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700671};