blob: e6395fb6261a0a33f6cee76c136d1ea64160b995 [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
Arun Kumar K.Rfcf2fe12013-11-27 17:38:18 -080045/* Max. resolution assignable to when downscale */
46#define SUPPORTED_DOWNSCALE_EXT_AREA (1920*1080)
47
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070048
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070049int ExternalDisplay::configure() {
50 if(!openFrameBuffer()) {
51 ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080052 return -1;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070053 }
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -080054 readCEUnderscanInfo();
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080055 readResolution();
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080056 // TODO: Move this to activate
Arun Kumar K.R37552c52012-12-10 12:47:18 -080057 /* 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);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070066 setAttributes();
Amara Venkata Mastan Manoj Kumarb156a2f2013-02-07 16:42:50 -080067 // set system property
68 property_set("hw.hdmiON", "1");
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080069 return 0;
70}
71
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -070072void ExternalDisplay::getAttributes(int& width, int& height) {
73 int fps = 0;
74 getAttrForMode(width, height, fps);
75}
76
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070077int ExternalDisplay::teardown() {
78 closeFrameBuffer();
79 resetInfo();
80 // unset system property
81 property_set("hw.hdmiON", "0");
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -080082 return 0;
83}
84
Naseer Ahmedf8ec1622012-07-31 18:56:23 -070085ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070086 mCurrentMode(-1), mModeCount(0),
87 mUnderscanSupported(false), mHwcContext(ctx)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070088{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -070089 memset(&mVInfo, 0, sizeof(mVInfo));
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070090 mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL);
Arun Kumar K.Re746ac52013-03-20 15:56:15 -070091 // 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);
Amara Venkata Mastan Manoj Kumar11a380d2013-01-17 09:30:56 -080095
Arun Kumar K.R25187572013-02-28 18:47:36 -080096 // for HDMI - retreive all the modes supported by the driver
Jeykumar Sankaran27dee262013-08-01 17:09:54 -070097 if(mFbNum != -1) {
Arun Kumar K.R25187572013-02-28 18:47:36 -080098 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);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800104 // 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 */
115void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
116 int 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",
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700122 mFbNum, node);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800123 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);
Arun Kumar K.R25187572013-02-28 18:47:36 -0800143 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700144}
145
Saurabh Shah56f610d2012-08-07 15:27:06 -0700146void ExternalDisplay::setHPD(uint32_t startEnd) {
147 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
148 writeHPDOption(startEnd);
149}
150
151void ExternalDisplay::setActionSafeDimension(int w, int h) {
152 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800153 char actionsafeWidth[PROPERTY_VALUE_MAX];
154 char actionsafeHeight[PROPERTY_VALUE_MAX];
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800155 snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
Arun Kumar K.R4d73d642013-04-10 17:06:39 -0700156 property_set("persist.sys.actionsafe.width", actionsafeWidth);
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800157 snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
Arun Kumar K.R4d73d642013-04-10 17:06:39 -0700158 property_set("persist.sys.actionsafe.height", actionsafeHeight);
Saurabh Shah56f610d2012-08-07 15:27:06 -0700159}
160
161int ExternalDisplay::getModeCount() const {
162 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
Saurabh Shah56f610d2012-08-07 15:27:06 -0700163 return mModeCount;
164}
165
166void ExternalDisplay::getEDIDModes(int *out) const {
Saurabh Shah56f610d2012-08-07 15:27:06 -0700167 for(int i = 0;i < mModeCount;i++) {
168 out[i] = mEDIDModes[i];
169 }
170}
171
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800172void ExternalDisplay::readCEUnderscanInfo()
173{
174 int hdmiScanInfoFile = -1;
175 int len = -1;
176 char scanInfo[17];
177 char *ce_info_str = NULL;
178 const char token[] = ", \n";
179 int ce_info = -1;
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800180 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
181 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
182 "/sys/devices/virtual/graphics/fb%d/"
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700183 "scan_info", mFbNum);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800184
185 memset(scanInfo, 0, sizeof(scanInfo));
186 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
187 if (hdmiScanInfoFile < 0) {
188 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
189 __FUNCTION__, sysFsScanInfoFilePath);
190 return;
191 } else {
192 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
193 ALOGD("%s: Scan Info string: %s length = %d",
194 __FUNCTION__, scanInfo, len);
195 if (len <= 0) {
196 close(hdmiScanInfoFile);
197 ALOGE("%s: Scan Info file empty '%s'",
198 __FUNCTION__, sysFsScanInfoFilePath);
199 return;
200 }
201 scanInfo[len] = '\0'; /* null terminate the string */
202 }
203 close(hdmiScanInfoFile);
204
205 /*
206 * The scan_info contains the three fields
207 * PT - preferred video format
208 * IT - video format
209 * CE video format - containing the underscan support information
210 */
211
212 /* PT */
213 ce_info_str = strtok(scanInfo, token);
214 if (ce_info_str) {
215 /* IT */
216 ce_info_str = strtok(NULL, token);
217 if (ce_info_str) {
218 /* CE */
219 ce_info_str = strtok(NULL, token);
220 if (ce_info_str)
221 ce_info = atoi(ce_info_str);
222 }
223 }
224
225 if (ce_info_str) {
226 // ce_info contains the underscan information
227 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
228 ce_info == EXT_SCAN_BOTH_SUPPORTED)
229 // if TV supported underscan, then driver will always underscan
230 // hence no need to apply action safe rectangle
231 mUnderscanSupported = true;
232 } else {
233 ALOGE("%s: scan_info string error", __FUNCTION__);
234 }
235
236 // Store underscan support info in a system property
237 const char* prop = (mUnderscanSupported) ? "1" : "0";
238 property_set("hw.underscan_supported", prop);
239 return;
240}
241
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700242ExternalDisplay::~ExternalDisplay()
243{
Arun Kumar K.R25187572013-02-28 18:47:36 -0800244 delete [] supported_video_mode_lut;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700245 closeFrameBuffer();
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700246}
247
Arun Kumar K.R25187572013-02-28 18:47:36 -0800248/*
249 * sets the fb_var_screeninfo from the hdmi_mode_timing_info
250 */
251void setDisplayTiming(struct fb_var_screeninfo &info,
252 const msm_hdmi_mode_timing_info* mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700253{
254 info.reserved[0] = 0;
255 info.reserved[1] = 0;
256 info.reserved[2] = 0;
Ken Zhang7b03a952013-01-16 13:23:48 -0500257#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
Arun Kumar K.R25187572013-02-28 18:47:36 -0800258 info.reserved[3] = (info.reserved[3] & 0xFFFF) |
259 (mode->video_format << 16);
Ken Zhang7b03a952013-01-16 13:23:48 -0500260#endif
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700261 info.xoffset = 0;
262 info.yoffset = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800263 info.xres = mode->active_h;
264 info.yres = mode->active_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700265
Arun Kumar K.R25187572013-02-28 18:47:36 -0800266 info.pixclock = (mode->pixel_freq)*1000;
267 info.vmode = mode->interlaced ?
268 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700269
Arun Kumar K.R25187572013-02-28 18:47:36 -0800270 info.right_margin = mode->front_porch_h;
271 info.hsync_len = mode->pulse_width_h;
272 info.left_margin = mode->back_porch_h;
273 info.lower_margin = mode->front_porch_v;
274 info.vsync_len = mode->pulse_width_v;
275 info.upper_margin = mode->back_porch_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700276}
277
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700278int ExternalDisplay::parseResolution(char* edidStr, int* edidModes)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700279{
280 char delim = ',';
281 int count = 0;
282 char *start, *end;
283 // EDIDs are string delimited by ','
284 // Ex: 16,4,5,3,32,34,1
285 // Parse this string to get mode(int)
286 start = (char*) edidStr;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700287 end = &delim;
288 while(*end == delim) {
289 edidModes[count] = (int) strtol(start, &end, 10);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700290 start = end+1;
291 count++;
292 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700293 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
294 for (int i = 0; i < count; i++)
295 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700296 return count;
297}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700298
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700299bool ExternalDisplay::readResolution()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700300{
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800301 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
302 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700303 "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800304
305 int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700306 int len = -1;
Arun Kumar K.R83812342013-09-24 17:30:36 -0700307 char edidStr[128] = {'\0'};
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700308
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700309 if (hdmiEDIDFile < 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700310 ALOGE("%s: edid_modes file '%s' not found",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800311 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700312 return false;
313 } else {
Arun Kumar K.R83812342013-09-24 17:30:36 -0700314 len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700315 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
Arun Kumar K.R83812342013-09-24 17:30:36 -0700316 __FUNCTION__, edidStr, len);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700317 if ( len <= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700318 ALOGE("%s: edid_modes file empty '%s'",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800319 __FUNCTION__, sysFsEDIDFilePath);
Arun Kumar K.R83812342013-09-24 17:30:36 -0700320 edidStr[0] = '\0';
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700321 }
322 else {
Arun Kumar K.R83812342013-09-24 17:30:36 -0700323 while (len > 1 && isspace(edidStr[len-1])) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700324 --len;
Arun Kumar K.R83812342013-09-24 17:30:36 -0700325 }
326 edidStr[len] = '\0';
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700327 }
328 }
329 close(hdmiEDIDFile);
330 if(len > 0) {
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800331 // Get EDID modes from the EDID strings
Arun Kumar K.R83812342013-09-24 17:30:36 -0700332 mModeCount = parseResolution(edidStr, mEDIDModes);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700333 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
334 mModeCount);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700335 }
336
Arun Kumar K.R83812342013-09-24 17:30:36 -0700337 return (len > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700338}
339
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700340bool ExternalDisplay::openFrameBuffer()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700341{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700342 if (mFd == -1) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700343 char strDevPath[MAX_SYSFS_FILE_PATH];
344 snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
345 mFd = open(strDevPath, O_RDWR);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700346 if (mFd < 0)
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700347 ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
348 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700349 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700350 return (mFd > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700351}
352
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700353bool ExternalDisplay::closeFrameBuffer()
354{
355 int ret = 0;
Naseer Ahmedf53b3772013-02-15 19:13:50 -0500356 if(mFd >= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700357 ret = close(mFd);
358 mFd = -1;
359 }
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700360 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700361 return (ret == 0);
362}
363
364// clears the vinfo, edid, best modes
365void ExternalDisplay::resetInfo()
366{
367 memset(&mVInfo, 0, sizeof(mVInfo));
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700368 memset(mEDIDModes, 0, sizeof(mEDIDModes));
369 mModeCount = 0;
370 mCurrentMode = -1;
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800371 mUnderscanSupported = false;
372 // Reset the underscan supported system property
373 const char* prop = "0";
374 property_set("hw.underscan_supported", prop);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700375}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700376
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700377int ExternalDisplay::getModeOrder(int mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700378{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800379 // XXX: We dont support interlaced modes but having
Arun Kumar K.R25187572013-02-28 18:47:36 -0800380 // it here for future
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700381 switch (mode) {
382 default:
Arun Kumar K.R25187572013-02-28 18:47:36 -0800383 case HDMI_VFRMT_1440x480i60_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700384 return 1; // 480i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800385 case HDMI_VFRMT_1440x480i60_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700386 return 2; // 480i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800387 case HDMI_VFRMT_1440x576i50_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700388 return 3; // i576i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800389 case HDMI_VFRMT_1440x576i50_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700390 return 4; // 576i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800391 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800392 return 5; // 1080i 16:9
393 case HDMI_VFRMT_640x480p60_4_3:
394 return 6; // 640x480 4:3
395 case HDMI_VFRMT_720x480p60_4_3:
396 return 7; // 480p 4:3
397 case HDMI_VFRMT_720x480p60_16_9:
398 return 8; // 480p 16:9
399 case HDMI_VFRMT_720x576p50_4_3:
400 return 9; // 576p 4:3
401 case HDMI_VFRMT_720x576p50_16_9:
402 return 10; // 576p 16:9
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700403 case HDMI_VFRMT_1024x768p60_4_3:
404 return 11; // 768p 4:3 Vesa format
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800405 case HDMI_VFRMT_1280x1024p60_5_4:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700406 return 12; // 1024p Vesa format
Arun Kumar K.R25187572013-02-28 18:47:36 -0800407 case HDMI_VFRMT_1280x720p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700408 return 13; // 720p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800409 case HDMI_VFRMT_1280x720p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700410 return 14; // 720p@60Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800411 case HDMI_VFRMT_1920x1080p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700412 return 15; //1080p@24Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800413 case HDMI_VFRMT_1920x1080p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700414 return 16; //108-p@25Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800415 case HDMI_VFRMT_1920x1080p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700416 return 17; //1080p@30Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800417 case HDMI_VFRMT_1920x1080p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700418 return 18; //1080p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800419 case HDMI_VFRMT_1920x1080p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700420 return 19; //1080p@60Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800421 case HDMI_VFRMT_2560x1600p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700422 return 20; //WQXGA@60Hz541
Ujwal Patelb9430d22012-11-15 18:10:19 -0800423 case HDMI_VFRMT_3840x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700424 return 21;//2160@24Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800425 case HDMI_VFRMT_3840x2160p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700426 return 22;//2160@25Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800427 case HDMI_VFRMT_3840x2160p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700428 return 23; //2160@30Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800429 case HDMI_VFRMT_4096x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700430 return 24; //4kx2k@24Hz
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700431 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700432}
433
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800434/// Returns the user mode set(if any) using adb shell
435int ExternalDisplay::getUserMode() {
436 /* Based on the property set the resolution */
437 char property_value[PROPERTY_VALUE_MAX];
Arun Kumar K.Rc31bdcb2013-02-25 17:47:42 -0800438 property_get("hw.hdmi.resolution", property_value, "-1");
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800439 int mode = atoi(property_value);
440 // We dont support interlaced modes
441 if(isValidMode(mode) && !isInterlacedMode(mode)) {
Naseer Ahmed74214722013-02-09 08:11:36 -0500442 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800443 return mode;
444 }
445 return -1;
446}
447
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700448// Get the best mode for the current HD TV
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700449int ExternalDisplay::getBestMode() {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700450 int bestOrder = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800451 int bestMode = HDMI_VFRMT_640x480p60_4_3;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700452 // for all the edid read, get the best mode
453 for(int i = 0; i < mModeCount; i++) {
454 int mode = mEDIDModes[i];
455 int order = getModeOrder(mode);
456 if (order > bestOrder) {
457 bestOrder = order;
458 bestMode = mode;
459 }
460 }
461 return bestMode;
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700462}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700463
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700464inline bool ExternalDisplay::isValidMode(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700465{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800466 bool valid = false;
467 for (int i = 0; i < mModeCount; i++) {
468 if(ID == mEDIDModes[i]) {
469 valid = true;
470 break;
471 }
472 }
473 return valid;
474}
475
476// returns true if the mode(ID) is interlaced mode format
477bool ExternalDisplay::isInterlacedMode(int ID) {
478 bool interlaced = false;
479 switch(ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800480 case HDMI_VFRMT_1440x480i60_4_3:
481 case HDMI_VFRMT_1440x480i60_16_9:
482 case HDMI_VFRMT_1440x576i50_4_3:
483 case HDMI_VFRMT_1440x576i50_16_9:
484 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800485 interlaced = true;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700486 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800487 default:
488 interlaced = false;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700489 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800490 }
491 return interlaced;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700492}
493
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700494void ExternalDisplay::setResolution(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700495{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700496 int ret = 0;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700497 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
498 if(ret < 0) {
499 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
500 strerror(errno));
501 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700502 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
503 "(%d,%d,%d) %dMHz>", __FUNCTION__,
504 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
505 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
506 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
507 mVInfo.pixclock/1000/1000);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800508 //If its a new ID - update var_screeninfo
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700509 if ((isValidMode(ID)) && mCurrentMode != ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800510 const struct msm_hdmi_mode_timing_info *mode =
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700511 &supported_video_mode_lut[0];
Arun Kumar K.R25187572013-02-28 18:47:36 -0800512 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
513 const struct msm_hdmi_mode_timing_info *cur =
514 &supported_video_mode_lut[i];
515 if (cur->video_format == (uint32_t)ID) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700516 mode = cur;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800517 break;
518 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700519 }
Arun Kumar K.R25187572013-02-28 18:47:36 -0800520 setDisplayTiming(mVInfo, mode);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700521 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700522 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800523 mode->video_format, mVInfo.xres, mVInfo.yres,
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700524 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
525 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
526 mVInfo.pixclock/1000/1000);
Ken Zhang7b03a952013-01-16 13:23:48 -0500527#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
528 struct msmfb_metadata metadata;
529 memset(&metadata, 0 , sizeof(metadata));
530 metadata.op = metadata_op_vic;
531 metadata.data.video_info_code = mode->video_format;
532 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
533 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
534 __FUNCTION__, strerror(errno));
535 }
536#endif
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800537 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
538 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
539 if(ret < 0) {
540 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
541 __FUNCTION__, strerror(errno));
542 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700543 mCurrentMode = ID;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700544 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700545}
546
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700547bool ExternalDisplay::writeHPDOption(int userOption) const
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700548{
549 bool ret = true;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700550 if(mFbNum != -1) {
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700551 char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
552 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700553 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700554 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
555 if (hdmiHPDFile < 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700556 ALOGE("%s: state file '%s' not found : ret%d err str: %s",
557 __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700558 ret = false;
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700559 } else {
560 int err = -1;
561 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
562 if(userOption)
563 err = write(hdmiHPDFile, "1", 2);
564 else
565 err = write(hdmiHPDFile, "0" , 2);
566 if (err <= 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700567 ALOGE("%s: file write failed '%s'", __FUNCTION__,
568 sysFsHPDFilePath);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700569 ret = false;
570 }
571 close(hdmiHPDFile);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700572 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700573 }
574 return ret;
575}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700576
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700577
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700578void ExternalDisplay::setAttributes() {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700579 int width = 0, height = 0, fps = 0;
580 getAttrForMode(width, height, fps);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700581 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700582 if(mHwcContext) {
583 // Always set dpyAttr res to mVInfo res
584 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
585 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
586 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
587 if(!qdutils::MDPVersion::getInstance().is8x26()) {
588 int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
589 int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
590 // if primary resolution is more than the hdmi resolution
591 // configure dpy attr to primary resolution and set
592 // downscale mode
Manoj Kumar AVM82a3ac12013-10-23 11:46:07 -0700593 // Restrict this upto 1080p resolution max
594 if(((priW * priH) > (width * height)) &&
Arun Kumar K.Rfcf2fe12013-11-27 17:38:18 -0800595 ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700596 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
597 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
598 // HDMI is always in landscape, so always assign the higher
599 // dimension to hdmi's xres
600 if(priH > priW) {
601 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priH;
602 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priW;
603 }
604 // Set External Display MDP Downscale mode indicator
605 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
606 }
607 }
608 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
609 1000000000l / fps;
610 }
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700611}
612
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800613void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700614 switch (mCurrentMode) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800615 case HDMI_VFRMT_640x480p60_4_3:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700616 width = 640;
617 height = 480;
618 fps = 60;
619 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800620 case HDMI_VFRMT_720x480p60_4_3:
621 case HDMI_VFRMT_720x480p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700622 width = 720;
623 height = 480;
624 fps = 60;
625 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800626 case HDMI_VFRMT_720x576p50_4_3:
627 case HDMI_VFRMT_720x576p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700628 width = 720;
629 height = 576;
630 fps = 50;
631 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800632 case HDMI_VFRMT_1280x720p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700633 width = 1280;
634 height = 720;
635 fps = 50;
636 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800637 case HDMI_VFRMT_1280x720p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700638 width = 1280;
639 height = 720;
640 fps = 60;
641 break;
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800642 case HDMI_VFRMT_1280x1024p60_5_4:
643 width = 1280;
644 height = 1024;
645 fps = 60;
646 break;
Manoj Rao564ee922013-05-07 21:32:57 -0700647 case HDMI_VFRMT_1024x768p60_4_3:
648 width = 1024;
649 height = 768;
650 fps = 60;
651 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800652 case HDMI_VFRMT_1920x1080p24_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700653 width = 1920;
654 height = 1080;
655 fps = 24;
656 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800657 case HDMI_VFRMT_1920x1080p25_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700658 width = 1920;
659 height = 1080;
660 fps = 25;
661 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800662 case HDMI_VFRMT_1920x1080p30_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700663 width = 1920;
664 height = 1080;
665 fps = 30;
666 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800667 case HDMI_VFRMT_1920x1080p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700668 width = 1920;
669 height = 1080;
670 fps = 50;
671 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800672 case HDMI_VFRMT_1920x1080p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700673 width = 1920;
674 height = 1080;
675 fps = 60;
676 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800677 case HDMI_VFRMT_2560x1600p60_16_9:
678 width = 2560;
679 height = 1600;
680 fps = 60;
681 break;
682 case HDMI_VFRMT_3840x2160p24_16_9:
683 width = 3840;
684 height = 2160;
685 fps = 24;
686 break;
Arun Kumar K.R92ebf9d2013-04-09 19:23:14 -0700687 case HDMI_VFRMT_3840x2160p25_16_9:
688 width = 3840;
689 height = 2160;
690 fps = 25;
691 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800692 case HDMI_VFRMT_3840x2160p30_16_9:
693 width = 3840;
694 height = 2160;
695 fps = 30;
696 break;
697 case HDMI_VFRMT_4096x2160p24_16_9:
698 width = 4096;
699 height = 2160;
700 fps = 24;
701 break;
702
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700703 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700704}
705
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700706};