blob: 1268b0f05957e7384a46ea22f73df88ef660e09c [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;
Ramkumar Radhakrishnan36bd5272014-01-31 20:03:01 -0800178 char *save_ptr;
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800179 const char token[] = ", \n";
180 int ce_info = -1;
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800181 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
182 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
183 "/sys/devices/virtual/graphics/fb%d/"
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700184 "scan_info", mFbNum);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800185
186 memset(scanInfo, 0, sizeof(scanInfo));
187 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
188 if (hdmiScanInfoFile < 0) {
189 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
190 __FUNCTION__, sysFsScanInfoFilePath);
191 return;
192 } else {
193 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
194 ALOGD("%s: Scan Info string: %s length = %d",
195 __FUNCTION__, scanInfo, len);
196 if (len <= 0) {
197 close(hdmiScanInfoFile);
198 ALOGE("%s: Scan Info file empty '%s'",
199 __FUNCTION__, sysFsScanInfoFilePath);
200 return;
201 }
202 scanInfo[len] = '\0'; /* null terminate the string */
203 }
204 close(hdmiScanInfoFile);
205
206 /*
207 * The scan_info contains the three fields
208 * PT - preferred video format
209 * IT - video format
210 * CE video format - containing the underscan support information
211 */
212
213 /* PT */
Ramkumar Radhakrishnan36bd5272014-01-31 20:03:01 -0800214 ce_info_str = strtok_r(scanInfo, token, &save_ptr);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800215 if (ce_info_str) {
216 /* IT */
Ramkumar Radhakrishnan36bd5272014-01-31 20:03:01 -0800217 ce_info_str = strtok_r(NULL, token, &save_ptr);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800218 if (ce_info_str) {
219 /* CE */
Ramkumar Radhakrishnan36bd5272014-01-31 20:03:01 -0800220 ce_info_str = strtok_r(NULL, token, &save_ptr);
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800221 if (ce_info_str)
222 ce_info = atoi(ce_info_str);
223 }
224 }
225
226 if (ce_info_str) {
227 // ce_info contains the underscan information
228 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
229 ce_info == EXT_SCAN_BOTH_SUPPORTED)
230 // if TV supported underscan, then driver will always underscan
231 // hence no need to apply action safe rectangle
232 mUnderscanSupported = true;
233 } else {
234 ALOGE("%s: scan_info string error", __FUNCTION__);
235 }
236
237 // Store underscan support info in a system property
238 const char* prop = (mUnderscanSupported) ? "1" : "0";
239 property_set("hw.underscan_supported", prop);
240 return;
241}
242
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700243ExternalDisplay::~ExternalDisplay()
244{
Arun Kumar K.R25187572013-02-28 18:47:36 -0800245 delete [] supported_video_mode_lut;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700246 closeFrameBuffer();
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700247}
248
Arun Kumar K.R25187572013-02-28 18:47:36 -0800249/*
250 * sets the fb_var_screeninfo from the hdmi_mode_timing_info
251 */
252void setDisplayTiming(struct fb_var_screeninfo &info,
253 const msm_hdmi_mode_timing_info* mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700254{
255 info.reserved[0] = 0;
256 info.reserved[1] = 0;
257 info.reserved[2] = 0;
Ken Zhang7b03a952013-01-16 13:23:48 -0500258#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
Arun Kumar K.R25187572013-02-28 18:47:36 -0800259 info.reserved[3] = (info.reserved[3] & 0xFFFF) |
260 (mode->video_format << 16);
Ken Zhang7b03a952013-01-16 13:23:48 -0500261#endif
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700262 info.xoffset = 0;
263 info.yoffset = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800264 info.xres = mode->active_h;
265 info.yres = mode->active_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700266
Arun Kumar K.R25187572013-02-28 18:47:36 -0800267 info.pixclock = (mode->pixel_freq)*1000;
268 info.vmode = mode->interlaced ?
269 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700270
Arun Kumar K.R25187572013-02-28 18:47:36 -0800271 info.right_margin = mode->front_porch_h;
272 info.hsync_len = mode->pulse_width_h;
273 info.left_margin = mode->back_porch_h;
274 info.lower_margin = mode->front_porch_v;
275 info.vsync_len = mode->pulse_width_v;
276 info.upper_margin = mode->back_porch_v;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700277}
278
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700279int ExternalDisplay::parseResolution(char* edidStr, int* edidModes)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700280{
281 char delim = ',';
282 int count = 0;
283 char *start, *end;
284 // EDIDs are string delimited by ','
285 // Ex: 16,4,5,3,32,34,1
286 // Parse this string to get mode(int)
287 start = (char*) edidStr;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700288 end = &delim;
289 while(*end == delim) {
290 edidModes[count] = (int) strtol(start, &end, 10);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700291 start = end+1;
292 count++;
293 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700294 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
295 for (int i = 0; i < count; i++)
296 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700297 return count;
298}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700299
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700300bool ExternalDisplay::readResolution()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700301{
Arun Kumar K.R26808f32013-02-11 19:17:05 -0800302 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
303 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700304 "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800305
306 int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700307 int len = -1;
Arun Kumar K.R83812342013-09-24 17:30:36 -0700308 char edidStr[128] = {'\0'};
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700309
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700310 if (hdmiEDIDFile < 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700311 ALOGE("%s: edid_modes file '%s' not found",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800312 __FUNCTION__, sysFsEDIDFilePath);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700313 return false;
314 } else {
Arun Kumar K.R83812342013-09-24 17:30:36 -0700315 len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700316 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
Arun Kumar K.R83812342013-09-24 17:30:36 -0700317 __FUNCTION__, edidStr, len);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700318 if ( len <= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700319 ALOGE("%s: edid_modes file empty '%s'",
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800320 __FUNCTION__, sysFsEDIDFilePath);
Arun Kumar K.R83812342013-09-24 17:30:36 -0700321 edidStr[0] = '\0';
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700322 }
323 else {
Arun Kumar K.R83812342013-09-24 17:30:36 -0700324 while (len > 1 && isspace(edidStr[len-1])) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700325 --len;
Arun Kumar K.R83812342013-09-24 17:30:36 -0700326 }
327 edidStr[len] = '\0';
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700328 }
329 }
330 close(hdmiEDIDFile);
331 if(len > 0) {
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800332 // Get EDID modes from the EDID strings
Arun Kumar K.R83812342013-09-24 17:30:36 -0700333 mModeCount = parseResolution(edidStr, mEDIDModes);
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700334 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
335 mModeCount);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700336 }
337
Arun Kumar K.R83812342013-09-24 17:30:36 -0700338 return (len > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700339}
340
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700341bool ExternalDisplay::openFrameBuffer()
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700342{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700343 if (mFd == -1) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700344 char strDevPath[MAX_SYSFS_FILE_PATH];
345 snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
346 mFd = open(strDevPath, O_RDWR);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700347 if (mFd < 0)
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700348 ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
349 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700350 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700351 return (mFd > 0);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700352}
353
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700354bool ExternalDisplay::closeFrameBuffer()
355{
356 int ret = 0;
Naseer Ahmedf53b3772013-02-15 19:13:50 -0500357 if(mFd >= 0) {
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700358 ret = close(mFd);
359 mFd = -1;
360 }
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700361 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700362 return (ret == 0);
363}
364
365// clears the vinfo, edid, best modes
366void ExternalDisplay::resetInfo()
367{
368 memset(&mVInfo, 0, sizeof(mVInfo));
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700369 memset(mEDIDModes, 0, sizeof(mEDIDModes));
370 mModeCount = 0;
371 mCurrentMode = -1;
Arun Kumar K.Rfeb2d8a2013-02-01 02:53:13 -0800372 mUnderscanSupported = false;
373 // Reset the underscan supported system property
374 const char* prop = "0";
375 property_set("hw.underscan_supported", prop);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700376}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700377
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700378int ExternalDisplay::getModeOrder(int mode)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700379{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800380 // XXX: We dont support interlaced modes but having
Arun Kumar K.R25187572013-02-28 18:47:36 -0800381 // it here for future
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700382 switch (mode) {
383 default:
Arun Kumar K.R25187572013-02-28 18:47:36 -0800384 case HDMI_VFRMT_1440x480i60_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700385 return 1; // 480i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800386 case HDMI_VFRMT_1440x480i60_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700387 return 2; // 480i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800388 case HDMI_VFRMT_1440x576i50_4_3:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700389 return 3; // i576i 4:3
Arun Kumar K.R25187572013-02-28 18:47:36 -0800390 case HDMI_VFRMT_1440x576i50_16_9:
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700391 return 4; // 576i 16:9
Arun Kumar K.R25187572013-02-28 18:47:36 -0800392 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800393 return 5; // 1080i 16:9
394 case HDMI_VFRMT_640x480p60_4_3:
395 return 6; // 640x480 4:3
396 case HDMI_VFRMT_720x480p60_4_3:
397 return 7; // 480p 4:3
398 case HDMI_VFRMT_720x480p60_16_9:
399 return 8; // 480p 16:9
400 case HDMI_VFRMT_720x576p50_4_3:
401 return 9; // 576p 4:3
402 case HDMI_VFRMT_720x576p50_16_9:
403 return 10; // 576p 16:9
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700404 case HDMI_VFRMT_1024x768p60_4_3:
405 return 11; // 768p 4:3 Vesa format
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800406 case HDMI_VFRMT_1280x1024p60_5_4:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700407 return 12; // 1024p Vesa format
Arun Kumar K.R25187572013-02-28 18:47:36 -0800408 case HDMI_VFRMT_1280x720p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700409 return 13; // 720p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800410 case HDMI_VFRMT_1280x720p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700411 return 14; // 720p@60Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800412 case HDMI_VFRMT_1920x1080p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700413 return 15; //1080p@24Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800414 case HDMI_VFRMT_1920x1080p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700415 return 16; //108-p@25Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800416 case HDMI_VFRMT_1920x1080p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700417 return 17; //1080p@30Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800418 case HDMI_VFRMT_1920x1080p50_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700419 return 18; //1080p@50Hz
Arun Kumar K.R25187572013-02-28 18:47:36 -0800420 case HDMI_VFRMT_1920x1080p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700421 return 19; //1080p@60Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800422 case HDMI_VFRMT_2560x1600p60_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700423 return 20; //WQXGA@60Hz541
Ujwal Patelb9430d22012-11-15 18:10:19 -0800424 case HDMI_VFRMT_3840x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700425 return 21;//2160@24Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800426 case HDMI_VFRMT_3840x2160p25_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700427 return 22;//2160@25Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800428 case HDMI_VFRMT_3840x2160p30_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700429 return 23; //2160@30Hz
Ujwal Patelb9430d22012-11-15 18:10:19 -0800430 case HDMI_VFRMT_4096x2160p24_16_9:
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700431 return 24; //4kx2k@24Hz
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700432 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700433}
434
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800435/// Returns the user mode set(if any) using adb shell
436int ExternalDisplay::getUserMode() {
437 /* Based on the property set the resolution */
438 char property_value[PROPERTY_VALUE_MAX];
Arun Kumar K.Rc31bdcb2013-02-25 17:47:42 -0800439 property_get("hw.hdmi.resolution", property_value, "-1");
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800440 int mode = atoi(property_value);
441 // We dont support interlaced modes
442 if(isValidMode(mode) && !isInterlacedMode(mode)) {
Naseer Ahmed74214722013-02-09 08:11:36 -0500443 ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800444 return mode;
445 }
446 return -1;
447}
448
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700449// Get the best mode for the current HD TV
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700450int ExternalDisplay::getBestMode() {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700451 int bestOrder = 0;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800452 int bestMode = HDMI_VFRMT_640x480p60_4_3;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700453 // for all the edid read, get the best mode
454 for(int i = 0; i < mModeCount; i++) {
455 int mode = mEDIDModes[i];
456 int order = getModeOrder(mode);
457 if (order > bestOrder) {
458 bestOrder = order;
459 bestMode = mode;
460 }
461 }
462 return bestMode;
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700463}
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700464
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700465inline bool ExternalDisplay::isValidMode(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700466{
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800467 bool valid = false;
468 for (int i = 0; i < mModeCount; i++) {
469 if(ID == mEDIDModes[i]) {
470 valid = true;
471 break;
472 }
473 }
474 return valid;
475}
476
477// returns true if the mode(ID) is interlaced mode format
478bool ExternalDisplay::isInterlacedMode(int ID) {
479 bool interlaced = false;
480 switch(ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800481 case HDMI_VFRMT_1440x480i60_4_3:
482 case HDMI_VFRMT_1440x480i60_16_9:
483 case HDMI_VFRMT_1440x576i50_4_3:
484 case HDMI_VFRMT_1440x576i50_16_9:
485 case HDMI_VFRMT_1920x1080i60_16_9:
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800486 interlaced = true;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700487 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800488 default:
489 interlaced = false;
Arun Kumar K.Rae46f3a2013-05-16 16:40:10 -0700490 break;
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800491 }
492 return interlaced;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700493}
494
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700495void ExternalDisplay::setResolution(int ID)
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700496{
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700497 int ret = 0;
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700498 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
499 if(ret < 0) {
500 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
501 strerror(errno));
502 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700503 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
504 "(%d,%d,%d) %dMHz>", __FUNCTION__,
505 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
506 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
507 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
508 mVInfo.pixclock/1000/1000);
Arun Kumar K.R37552c52012-12-10 12:47:18 -0800509 //If its a new ID - update var_screeninfo
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700510 if ((isValidMode(ID)) && mCurrentMode != ID) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800511 const struct msm_hdmi_mode_timing_info *mode =
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700512 &supported_video_mode_lut[0];
Arun Kumar K.R25187572013-02-28 18:47:36 -0800513 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
514 const struct msm_hdmi_mode_timing_info *cur =
515 &supported_video_mode_lut[i];
516 if (cur->video_format == (uint32_t)ID) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700517 mode = cur;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800518 break;
519 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700520 }
Arun Kumar K.R25187572013-02-28 18:47:36 -0800521 setDisplayTiming(mVInfo, mode);
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700522 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700523 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800524 mode->video_format, mVInfo.xres, mVInfo.yres,
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700525 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
526 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
527 mVInfo.pixclock/1000/1000);
Ken Zhang7b03a952013-01-16 13:23:48 -0500528#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
529 struct msmfb_metadata metadata;
530 memset(&metadata, 0 , sizeof(metadata));
531 metadata.op = metadata_op_vic;
532 metadata.data.video_info_code = mode->video_format;
533 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
534 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
535 __FUNCTION__, strerror(errno));
536 }
537#endif
Arun Kumar K.Re1cea3e2013-02-06 16:57:43 -0800538 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
539 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
540 if(ret < 0) {
541 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
542 __FUNCTION__, strerror(errno));
543 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700544 mCurrentMode = ID;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700545 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700546}
547
Naseer Ahmed72cf9762012-07-21 12:17:13 -0700548bool ExternalDisplay::writeHPDOption(int userOption) const
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700549{
550 bool ret = true;
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700551 if(mFbNum != -1) {
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700552 char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
553 snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700554 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700555 int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
556 if (hdmiHPDFile < 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700557 ALOGE("%s: state file '%s' not found : ret%d err str: %s",
558 __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700559 ret = false;
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700560 } else {
561 int err = -1;
562 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
563 if(userOption)
564 err = write(hdmiHPDFile, "1", 2);
565 else
566 err = write(hdmiHPDFile, "0" , 2);
567 if (err <= 0) {
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700568 ALOGE("%s: file write failed '%s'", __FUNCTION__,
569 sysFsHPDFilePath);
Arun Kumar K.R47d6b642013-06-26 16:20:30 -0700570 ret = false;
571 }
572 close(hdmiHPDFile);
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700573 }
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700574 }
575 return ret;
576}
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700577
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700578
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700579void ExternalDisplay::setAttributes() {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700580 int width = 0, height = 0, fps = 0;
581 getAttrForMode(width, height, fps);
Jeykumar Sankaran27dee262013-08-01 17:09:54 -0700582 ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700583 if(mHwcContext) {
584 // Always set dpyAttr res to mVInfo res
585 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
586 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
587 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
588 if(!qdutils::MDPVersion::getInstance().is8x26()) {
589 int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
590 int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
591 // if primary resolution is more than the hdmi resolution
592 // configure dpy attr to primary resolution and set
593 // downscale mode
Manoj Kumar AVM82a3ac12013-10-23 11:46:07 -0700594 // Restrict this upto 1080p resolution max
595 if(((priW * priH) > (width * height)) &&
Arun Kumar K.Rfcf2fe12013-11-27 17:38:18 -0800596 ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
Amara Venkata Mastan Manoj Kumar376d8a82013-03-13 19:18:47 -0700597 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
598 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
599 // HDMI is always in landscape, so always assign the higher
600 // dimension to hdmi's xres
601 if(priH > priW) {
602 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priH;
603 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priW;
604 }
605 // Set External Display MDP Downscale mode indicator
606 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
607 }
608 }
609 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
610 1000000000l / fps;
611 }
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700612}
613
Amara Venkata Mastan Manoj Kumar5182a782012-12-03 12:08:48 -0800614void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700615 switch (mCurrentMode) {
Arun Kumar K.R25187572013-02-28 18:47:36 -0800616 case HDMI_VFRMT_640x480p60_4_3:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700617 width = 640;
618 height = 480;
619 fps = 60;
620 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800621 case HDMI_VFRMT_720x480p60_4_3:
622 case HDMI_VFRMT_720x480p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700623 width = 720;
624 height = 480;
625 fps = 60;
626 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800627 case HDMI_VFRMT_720x576p50_4_3:
628 case HDMI_VFRMT_720x576p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700629 width = 720;
630 height = 576;
631 fps = 50;
632 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800633 case HDMI_VFRMT_1280x720p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700634 width = 1280;
635 height = 720;
636 fps = 50;
637 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800638 case HDMI_VFRMT_1280x720p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700639 width = 1280;
640 height = 720;
641 fps = 60;
642 break;
Arun Kumar K.R6ce73ff2013-01-24 19:48:24 -0800643 case HDMI_VFRMT_1280x1024p60_5_4:
644 width = 1280;
645 height = 1024;
646 fps = 60;
647 break;
Manoj Rao564ee922013-05-07 21:32:57 -0700648 case HDMI_VFRMT_1024x768p60_4_3:
649 width = 1024;
650 height = 768;
651 fps = 60;
652 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800653 case HDMI_VFRMT_1920x1080p24_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700654 width = 1920;
655 height = 1080;
656 fps = 24;
657 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800658 case HDMI_VFRMT_1920x1080p25_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700659 width = 1920;
660 height = 1080;
661 fps = 25;
662 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800663 case HDMI_VFRMT_1920x1080p30_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700664 width = 1920;
665 height = 1080;
666 fps = 30;
667 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800668 case HDMI_VFRMT_1920x1080p50_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700669 width = 1920;
670 height = 1080;
671 fps = 50;
672 break;
Arun Kumar K.R25187572013-02-28 18:47:36 -0800673 case HDMI_VFRMT_1920x1080p60_16_9:
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700674 width = 1920;
675 height = 1080;
676 fps = 60;
677 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800678 case HDMI_VFRMT_2560x1600p60_16_9:
679 width = 2560;
680 height = 1600;
681 fps = 60;
682 break;
683 case HDMI_VFRMT_3840x2160p24_16_9:
684 width = 3840;
685 height = 2160;
686 fps = 24;
687 break;
Arun Kumar K.R92ebf9d2013-04-09 19:23:14 -0700688 case HDMI_VFRMT_3840x2160p25_16_9:
689 width = 3840;
690 height = 2160;
691 fps = 25;
692 break;
Ujwal Patelb9430d22012-11-15 18:10:19 -0800693 case HDMI_VFRMT_3840x2160p30_16_9:
694 width = 3840;
695 height = 2160;
696 fps = 30;
697 break;
698 case HDMI_VFRMT_4096x2160p24_16_9:
699 width = 4096;
700 height = 2160;
701 fps = 24;
702 break;
703
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700704 }
Naseer Ahmedf8ec1622012-07-31 18:56:23 -0700705}
706
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -0700707};