blob: 045edd8764af39a95ce3bcb593fdd40404730504 [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;
Arun Kumar K.R83812342013-09-24 17:30:36 -0700304 char edidStr[128] = {'\0'};
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700305
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700306 if (hdmiEDIDFile < 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700307 ALOGE("%s: edid_modes file '%s' not found",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800308 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700309 return false;
310 } else {
Arun Kumar K.R83812342013-09-24 17:30:36 -0700311 len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700312 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
Arun Kumar K.R83812342013-09-24 17:30:36 -0700313 __FUNCTION__, edidStr, len);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700314 if ( len <= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700315 ALOGE("%s: edid_modes file empty '%s'",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800316 __FUNCTION__, sysFsEDIDFilePath);
Arun Kumar K.R83812342013-09-24 17:30:36 -0700317 edidStr[0] = '\0';
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700318 }
319 else {
Arun Kumar K.R83812342013-09-24 17:30:36 -0700320 while (len > 1 && isspace(edidStr[len-1])) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700321 --len;
Arun Kumar K.R83812342013-09-24 17:30:36 -0700322 }
323 edidStr[len] = '\0';
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700324 }
325 }
326 close(hdmiEDIDFile);
327 if(len > 0) {
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800328 // Get EDID modes from the EDID strings
Arun Kumar K.R83812342013-09-24 17:30:36 -0700329 mModeCount = parseResolution(edidStr, mEDIDModes);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700330 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
331 mModeCount);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700332 }
333
Arun Kumar K.R83812342013-09-24 17:30:36 -0700334 return (len > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700335}
336
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700337bool ExternalDisplay::openFrameBuffer()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700338{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700339 if (mFd == -1) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700340 char strDevPath[MAX_SYSFS_FILE_PATH];
341 snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
342 mFd = open(strDevPath, O_RDWR);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700343 if (mFd < 0)
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700344 ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
345 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700346 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700347 return (mFd > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700348}
349
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700350bool ExternalDisplay::closeFrameBuffer()
351{
352 int ret = 0;
Naseer Ahmedf53b3772013-02-15 19:13:50 -0500353 if(mFd >= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700354 ret = close(mFd);
355 mFd = -1;
356 }
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700357 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700358 return (ret == 0);
359}
360
361// clears the vinfo, edid, best modes
362void ExternalDisplay::resetInfo()
363{
364 memset(&mVInfo, 0, sizeof(mVInfo));
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700365 memset(mEDIDModes, 0, sizeof(mEDIDModes));
366 mModeCount = 0;
367 mCurrentMode = -1;
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800368 mUnderscanSupported = false;
369 // Reset the underscan supported system property
370 const char* prop = "0";
371 property_set("hw.underscan_supported", prop);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700372}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700373
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700374int ExternalDisplay::getModeOrder(int mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700375{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800376 // XXX: We dont support interlaced modes but having
Arun Kumar K.R25187572013-02-28 18:47:36 -0800377 // it here for future
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700378 switch (mode) {
379 default:
Arun Kumar K.R25187572013-02-28 18:47:36 -0800380 case HDMI_VFRMT_1440x480i60_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700381 return 1; // 480i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800382 case HDMI_VFRMT_1440x480i60_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700383 return 2; // 480i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800384 case HDMI_VFRMT_1440x576i50_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700385 return 3; // i576i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800386 case HDMI_VFRMT_1440x576i50_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700387 return 4; // 576i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800388 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800389 return 5; // 1080i 16:9
390 case HDMI_VFRMT_640x480p60_4_3:
391 return 6; // 640x480 4:3
392 case HDMI_VFRMT_720x480p60_4_3:
393 return 7; // 480p 4:3
394 case HDMI_VFRMT_720x480p60_16_9:
395 return 8; // 480p 16:9
396 case HDMI_VFRMT_720x576p50_4_3:
397 return 9; // 576p 4:3
398 case HDMI_VFRMT_720x576p50_16_9:
399 return 10; // 576p 16:9
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700400 case HDMI_VFRMT_1024x768p60_4_3:
401 return 11; // 768p 4:3 Vesa format
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800402 case HDMI_VFRMT_1280x1024p60_5_4:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700403 return 12; // 1024p Vesa format
Arun Kumar K.R25187572013-02-28 18:47:36 -0800404 case HDMI_VFRMT_1280x720p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700405 return 13; // 720p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800406 case HDMI_VFRMT_1280x720p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700407 return 14; // 720p@60Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800408 case HDMI_VFRMT_1920x1080p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700409 return 15; //1080p@24Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800410 case HDMI_VFRMT_1920x1080p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700411 return 16; //108-p@25Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800412 case HDMI_VFRMT_1920x1080p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700413 return 17; //1080p@30Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800414 case HDMI_VFRMT_1920x1080p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700415 return 18; //1080p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800416 case HDMI_VFRMT_1920x1080p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700417 return 19; //1080p@60Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800418 case HDMI_VFRMT_2560x1600p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700419 return 20; //WQXGA@60Hz541
Ujwal Patelb9430d22012-11-15 18:10:19 -0800420 case HDMI_VFRMT_3840x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700421 return 21;//2160@24Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800422 case HDMI_VFRMT_3840x2160p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700423 return 22;//2160@25Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800424 case HDMI_VFRMT_3840x2160p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700425 return 23; //2160@30Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800426 case HDMI_VFRMT_4096x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700427 return 24; //4kx2k@24Hz
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700428 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700429}
430
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800431/// Returns the user mode set(if any) using adb shell
432int ExternalDisplay::getUserMode() {
433 /* Based on the property set the resolution */
434 char property_value[PROPERTY_VALUE_MAX];
Arun Kumar K.Rc31bdcb2013-02-25 17:47:42 -0800435 property_get("hw.hdmi.resolution", property_value, "-1");
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800436 int mode = atoi(property_value);
437 // We dont support interlaced modes
438 if(isValidMode(mode) && !isInterlacedMode(mode)) {
Naseer Ahmed74214722013-02-09 08:11:36 -0500439 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800440 return mode;
441 }
442 return -1;
443}
444
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700445// Get the best mode for the current HD TV
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700446int ExternalDisplay::getBestMode() {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700447 int bestOrder = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800448 int bestMode = HDMI_VFRMT_640x480p60_4_3;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700449 // for all the edid read, get the best mode
450 for(int i = 0; i < mModeCount; i++) {
451 int mode = mEDIDModes[i];
452 int order = getModeOrder(mode);
453 if (order > bestOrder) {
454 bestOrder = order;
455 bestMode = mode;
456 }
457 }
458 return bestMode;
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700459}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700460
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700461inline bool ExternalDisplay::isValidMode(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700462{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800463 bool valid = false;
464 for (int i = 0; i < mModeCount; i++) {
465 if(ID == mEDIDModes[i]) {
466 valid = true;
467 break;
468 }
469 }
470 return valid;
471}
472
473// returns true if the mode(ID) is interlaced mode format
474bool ExternalDisplay::isInterlacedMode(int ID) {
475 bool interlaced = false;
476 switch(ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800477 case HDMI_VFRMT_1440x480i60_4_3:
478 case HDMI_VFRMT_1440x480i60_16_9:
479 case HDMI_VFRMT_1440x576i50_4_3:
480 case HDMI_VFRMT_1440x576i50_16_9:
481 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800482 interlaced = true;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700483 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800484 default:
485 interlaced = false;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700486 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800487 }
488 return interlaced;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700489}
490
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700491void ExternalDisplay::setResolution(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700492{
493 struct fb_var_screeninfo info;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700494 int ret = 0;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700495 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
496 if(ret < 0) {
497 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
498 strerror(errno));
499 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700500 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
501 "(%d,%d,%d) %dMHz>", __FUNCTION__,
502 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
503 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
504 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
505 mVInfo.pixclock/1000/1000);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800506 //If its a new ID - update var_screeninfo
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700507 if ((isValidMode(ID)) && mCurrentMode != ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800508 const struct msm_hdmi_mode_timing_info *mode =
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700509 &supported_video_mode_lut[0];
Arun Kumar K.R25187572013-02-28 18:47:36 -0800510 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
511 const struct msm_hdmi_mode_timing_info *cur =
512 &supported_video_mode_lut[i];
513 if (cur->video_format == (uint32_t)ID) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700514 mode = cur;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800515 break;
516 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700517 }
Arun Kumar K.R25187572013-02-28 18:47:36 -0800518 setDisplayTiming(mVInfo, mode);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700519 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700520 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800521 mode->video_format, mVInfo.xres, mVInfo.yres,
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700522 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
523 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
524 mVInfo.pixclock/1000/1000);
Ken Zhang7b03a952013-01-16 13:23:48 -0500525#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
526 struct msmfb_metadata metadata;
527 memset(&metadata, 0 , sizeof(metadata));
528 metadata.op = metadata_op_vic;
529 metadata.data.video_info_code = mode->video_format;
530 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
531 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
532 __FUNCTION__, strerror(errno));
533 }
534#endif
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800535 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
536 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
537 if(ret < 0) {
538 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
539 __FUNCTION__, strerror(errno));
540 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700541 mCurrentMode = ID;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700542 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700543}
544
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700545bool ExternalDisplay::writeHPDOption(int userOption) const
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700546{
547 bool ret = true;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700548 if(mFbNum != -1) {
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700549 char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
550 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700551 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700552 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
553 if (hdmiHPDFile < 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700554 ALOGE("%s: state file '%s' not found : ret%d err str: %s",
555 __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700556 ret = false;
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700557 } else {
558 int err = -1;
559 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
560 if(userOption)
561 err = write(hdmiHPDFile, "1", 2);
562 else
563 err = write(hdmiHPDFile, "0" , 2);
564 if (err <= 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700565 ALOGE("%s: file write failed '%s'", __FUNCTION__,
566 sysFsHPDFilePath);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700567 ret = false;
568 }
569 close(hdmiHPDFile);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700570 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700571 }
572 return ret;
573}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700574
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700575
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700576void ExternalDisplay::setAttributes() {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700577 int width = 0, height = 0, fps = 0;
578 getAttrForMode(width, height, fps);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700579 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700580 if(mHwcContext) {
581 // Always set dpyAttr res to mVInfo res
582 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
583 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
584 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
585 if(!qdutils::MDPVersion::getInstance().is8x26()) {
586 int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
587 int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
588 // if primary resolution is more than the hdmi resolution
589 // configure dpy attr to primary resolution and set
590 // downscale mode
Manoj Kumar AVM82a3ac12013-10-23 11:46:07 -0700591 // Restrict this upto 1080p resolution max
592 if(((priW * priH) > (width * height)) &&
593 (priW <= qdutils::MAX_DISPLAY_DIM )) {
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700594 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
595 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
596 // HDMI is always in landscape, so always assign the higher
597 // dimension to hdmi's xres
598 if(priH > priW) {
599 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priH;
600 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priW;
601 }
602 // Set External Display MDP Downscale mode indicator
603 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
604 }
605 }
606 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
607 1000000000l / fps;
608 }
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700609}
610
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800611void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700612 switch (mCurrentMode) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800613 case HDMI_VFRMT_640x480p60_4_3:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700614 width = 640;
615 height = 480;
616 fps = 60;
617 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800618 case HDMI_VFRMT_720x480p60_4_3:
619 case HDMI_VFRMT_720x480p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700620 width = 720;
621 height = 480;
622 fps = 60;
623 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800624 case HDMI_VFRMT_720x576p50_4_3:
625 case HDMI_VFRMT_720x576p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700626 width = 720;
627 height = 576;
628 fps = 50;
629 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800630 case HDMI_VFRMT_1280x720p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700631 width = 1280;
632 height = 720;
633 fps = 50;
634 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800635 case HDMI_VFRMT_1280x720p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700636 width = 1280;
637 height = 720;
638 fps = 60;
639 break;
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800640 case HDMI_VFRMT_1280x1024p60_5_4:
641 width = 1280;
642 height = 1024;
643 fps = 60;
644 break;
Manoj Rao564ee922013-05-07 21:32:57 -0700645 case HDMI_VFRMT_1024x768p60_4_3:
646 width = 1024;
647 height = 768;
648 fps = 60;
649 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800650 case HDMI_VFRMT_1920x1080p24_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700651 width = 1920;
652 height = 1080;
653 fps = 24;
654 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800655 case HDMI_VFRMT_1920x1080p25_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700656 width = 1920;
657 height = 1080;
658 fps = 25;
659 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800660 case HDMI_VFRMT_1920x1080p30_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700661 width = 1920;
662 height = 1080;
663 fps = 30;
664 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800665 case HDMI_VFRMT_1920x1080p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700666 width = 1920;
667 height = 1080;
668 fps = 50;
669 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800670 case HDMI_VFRMT_1920x1080p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700671 width = 1920;
672 height = 1080;
673 fps = 60;
674 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800675 case HDMI_VFRMT_2560x1600p60_16_9:
676 width = 2560;
677 height = 1600;
678 fps = 60;
679 break;
680 case HDMI_VFRMT_3840x2160p24_16_9:
681 width = 3840;
682 height = 2160;
683 fps = 24;
684 break;
Arun Kumar K.R92ebf9d2013-04-09 19:23:14 -0700685 case HDMI_VFRMT_3840x2160p25_16_9:
686 width = 3840;
687 height = 2160;
688 fps = 25;
689 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800690 case HDMI_VFRMT_3840x2160p30_16_9:
691 width = 3840;
692 height = 2160;
693 fps = 30;
694 break;
695 case HDMI_VFRMT_4096x2160p24_16_9:
696 width = 4096;
697 height = 2160;
698 fps = 24;
699 break;
700
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700701 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700702}
703
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700704};