external.cpp revision 074dab343c4cfc5c77511a77247d759b10089a94
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * Copyright (C) 2012, The Linux Foundation. All rights reserved. 4 * 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 21#define DEBUG 0 22#include <ctype.h> 23#include <fcntl.h> 24#include <media/IAudioPolicyService.h> 25#include <media/AudioSystem.h> 26#include <utils/threads.h> 27#include <utils/Errors.h> 28#include <utils/Log.h> 29 30#include <linux/msm_mdp.h> 31#include <linux/fb.h> 32#include <sys/ioctl.h> 33#include <sys/poll.h> 34#include <sys/resource.h> 35#include <cutils/properties.h> 36#include "hwc_utils.h" 37#include "external.h" 38#include "overlayUtils.h" 39 40using namespace android; 41 42namespace qhwc { 43 44 45#define DEVICE_ROOT "/sys/devices/virtual/graphics" 46#define DEVICE_NODE "fb1" 47 48#define SYSFS_EDID_MODES DEVICE_ROOT "/" DEVICE_NODE "/edid_modes" 49#define SYSFS_HPD DEVICE_ROOT "/" DEVICE_NODE "/hpd" 50 51 52ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), 53 mCurrentMode(-1), mExternalDisplay(0), mModeCount(0), mHwcContext(ctx) 54{ 55 memset(&mVInfo, 0, sizeof(mVInfo)); 56 //Enable HPD for HDMI 57 writeHPDOption(1); 58} 59 60void ExternalDisplay::setEDIDMode(int resMode) { 61 ALOGD_IF(DEBUG,"resMode=%d ", resMode); 62 int extDispType; 63 { 64 Mutex::Autolock lock(mExtDispLock); 65 extDispType = mExternalDisplay; 66 setExternalDisplay(0); 67 setResolution(resMode); 68 } 69 setExternalDisplay(extDispType); 70} 71 72void ExternalDisplay::setHPD(uint32_t startEnd) { 73 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd); 74 writeHPDOption(startEnd); 75} 76 77void ExternalDisplay::setActionSafeDimension(int w, int h) { 78 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h); 79 Mutex::Autolock lock(mExtDispLock); 80 overlay::utils::ActionSafe::getInstance()->setDimension(w, h); 81 setExternalDisplay(mExternalDisplay); 82} 83 84int ExternalDisplay::getModeCount() const { 85 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount); 86 Mutex::Autolock lock(mExtDispLock); 87 return mModeCount; 88} 89 90void ExternalDisplay::getEDIDModes(int *out) const { 91 Mutex::Autolock lock(mExtDispLock); 92 for(int i = 0;i < mModeCount;i++) { 93 out[i] = mEDIDModes[i]; 94 } 95} 96 97ExternalDisplay::~ExternalDisplay() 98{ 99 closeFrameBuffer(); 100} 101 102struct disp_mode_timing_type { 103 int video_format; 104 105 int active_h; 106 int active_v; 107 108 int front_porch_h; 109 int pulse_width_h; 110 int back_porch_h; 111 112 int front_porch_v; 113 int pulse_width_v; 114 int back_porch_v; 115 116 int pixel_freq; 117 bool interlaced; 118 119 void set_info(struct fb_var_screeninfo &info) const; 120}; 121 122void disp_mode_timing_type::set_info(struct fb_var_screeninfo &info) const 123{ 124 info.reserved[0] = 0; 125 info.reserved[1] = 0; 126 info.reserved[2] = 0; 127 info.reserved[3] = (info.reserved[3] & 0xFFFF) | (video_format << 16); 128 129 info.xoffset = 0; 130 info.yoffset = 0; 131 info.xres = active_h; 132 info.yres = active_v; 133 134 info.pixclock = pixel_freq*1000; 135 info.vmode = interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; 136 137 info.right_margin = front_porch_h; 138 info.hsync_len = pulse_width_h; 139 info.left_margin = back_porch_h; 140 info.lower_margin = front_porch_v; 141 info.vsync_len = pulse_width_v; 142 info.upper_margin = back_porch_v; 143} 144 145/* Video formates supported by the HDMI Standard */ 146/* Indicates the resolution, pix clock and the aspect ratio */ 147#define m640x480p60_4_3 1 148#define m720x480p60_4_3 2 149#define m720x480p60_16_9 3 150#define m1280x720p60_16_9 4 151#define m1920x1080i60_16_9 5 152#define m1440x480i60_4_3 6 153#define m1440x480i60_16_9 7 154#define m1920x1080p60_16_9 16 155#define m720x576p50_4_3 17 156#define m720x576p50_16_9 18 157#define m1280x720p50_16_9 19 158#define m1440x576i50_4_3 21 159#define m1440x576i50_16_9 22 160#define m1920x1080p50_16_9 31 161#define m1920x1080p24_16_9 32 162#define m1920x1080p25_16_9 33 163#define m1920x1080p30_16_9 34 164 165static struct disp_mode_timing_type supported_video_mode_lut[] = { 166 {m640x480p60_4_3, 640, 480, 16, 96, 48, 10, 2, 33, 25200, false}, 167 {m720x480p60_4_3, 720, 480, 16, 62, 60, 9, 6, 30, 27030, false}, 168 {m720x480p60_16_9, 720, 480, 16, 62, 60, 9, 6, 30, 27030, false}, 169 {m1280x720p60_16_9, 1280, 720, 110, 40, 220, 5, 5, 20, 74250, false}, 170 {m1920x1080i60_16_9, 1920, 540, 88, 44, 148, 2, 5, 5, 74250, false}, 171 {m1440x480i60_4_3, 1440, 240, 38, 124, 114, 4, 3, 15, 27000, true}, 172 {m1440x480i60_16_9, 1440, 240, 38, 124, 114, 4, 3, 15, 27000, true}, 173 {m1920x1080p60_16_9, 1920, 1080, 88, 44, 148, 4, 5, 36, 148500, false}, 174 {m720x576p50_4_3, 720, 576, 12, 64, 68, 5, 5, 39, 27000, false}, 175 {m720x576p50_16_9, 720, 576, 12, 64, 68, 5, 5, 39, 27000, false}, 176 {m1280x720p50_16_9, 1280, 720, 440, 40, 220, 5, 5, 20, 74250, false}, 177 {m1440x576i50_4_3, 1440, 288, 24, 126, 138, 2, 3, 19, 27000, true}, 178 {m1440x576i50_16_9, 1440, 288, 24, 126, 138, 2, 3, 19, 27000, true}, 179 {m1920x1080p50_16_9, 1920, 1080, 528, 44, 148, 4, 5, 36, 148500, false}, 180 {m1920x1080p24_16_9, 1920, 1080, 638, 44, 148, 4, 5, 36, 74250, false}, 181 {m1920x1080p25_16_9, 1920, 1080, 528, 44, 148, 4, 5, 36, 74250, false}, 182 {m1920x1080p30_16_9, 1920, 1080, 88, 44, 148, 4, 5, 36, 74250, false}, 183}; 184 185int ExternalDisplay::parseResolution(char* edidStr, int* edidModes) 186{ 187 char delim = ','; 188 int count = 0; 189 char *start, *end; 190 // EDIDs are string delimited by ',' 191 // Ex: 16,4,5,3,32,34,1 192 // Parse this string to get mode(int) 193 start = (char*) edidStr; 194 end = &delim; 195 while(*end == delim) { 196 edidModes[count] = (int) strtol(start, &end, 10); 197 start = end+1; 198 count++; 199 } 200 ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count); 201 for (int i = 0; i < count; i++) 202 ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]); 203 return count; 204} 205 206bool ExternalDisplay::readResolution() 207{ 208 int hdmiEDIDFile = open(SYSFS_EDID_MODES, O_RDONLY, 0); 209 int len = -1; 210 211 if (hdmiEDIDFile < 0) { 212 ALOGE("%s: edid_modes file '%s' not found", 213 __FUNCTION__, SYSFS_EDID_MODES); 214 return false; 215 } else { 216 len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1); 217 ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d", 218 __FUNCTION__, mEDIDs, len); 219 if ( len <= 0) { 220 ALOGE("%s: edid_modes file empty '%s'", 221 __FUNCTION__, SYSFS_EDID_MODES); 222 } 223 else { 224 while (len > 1 && isspace(mEDIDs[len-1])) 225 --len; 226 mEDIDs[len] = 0; 227 } 228 } 229 close(hdmiEDIDFile); 230 if(len > 0) { 231 // GEt EDID modes from the EDID strings 232 mModeCount = parseResolution(mEDIDs, mEDIDModes); 233 ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__, 234 mModeCount); 235 } 236 237 return (strlen(mEDIDs) > 0); 238} 239 240bool ExternalDisplay::openFramebuffer() 241{ 242 if (mFd == -1) { 243 mFd = open("/dev/graphics/fb1", O_RDWR); 244 if (mFd < 0) 245 ALOGE("%s: /dev/graphics/fb1 not available", __FUNCTION__); 246 } 247 if(mHwcContext) { 248 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd; 249 } 250 return (mFd > 0); 251} 252 253bool ExternalDisplay::closeFrameBuffer() 254{ 255 int ret = 0; 256 if(mFd > 0) { 257 ret = close(mFd); 258 mFd = -1; 259 } 260 if(mHwcContext) { 261 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd; 262 } 263 return (ret == 0); 264} 265 266// clears the vinfo, edid, best modes 267void ExternalDisplay::resetInfo() 268{ 269 memset(&mVInfo, 0, sizeof(mVInfo)); 270 memset(mEDIDs, 0, sizeof(mEDIDs)); 271 memset(mEDIDModes, 0, sizeof(mEDIDModes)); 272 mModeCount = 0; 273 mCurrentMode = -1; 274} 275 276int ExternalDisplay::getModeOrder(int mode) 277{ 278 switch (mode) { 279 default: 280 case m1440x480i60_4_3: 281 return 1; // 480i 4:3 282 case m1440x480i60_16_9: 283 return 2; // 480i 16:9 284 case m1440x576i50_4_3: 285 return 3; // i576i 4:3 286 case m1440x576i50_16_9: 287 return 4; // 576i 16:9 288 case m640x480p60_4_3: 289 return 5; // 640x480 4:3 290 case m720x480p60_4_3: 291 return 6; // 480p 4:3 292 case m720x480p60_16_9: 293 return 7; // 480p 16:9 294 case m720x576p50_4_3: 295 return 8; // 576p 4:3 296 case m720x576p50_16_9: 297 return 9; // 576p 16:9 298 case m1920x1080i60_16_9: 299 return 10; // 1080i 16:9 300 case m1280x720p50_16_9: 301 return 11; // 720p@50Hz 302 case m1280x720p60_16_9: 303 return 12; // 720p@60Hz 304 case m1920x1080p24_16_9: 305 return 13; //1080p@24Hz 306 case m1920x1080p25_16_9: 307 return 14; //108-p@25Hz 308 case m1920x1080p30_16_9: 309 return 15; //1080p@30Hz 310 case m1920x1080p50_16_9: 311 return 16; //1080p@50Hz 312 case m1920x1080p60_16_9: 313 return 17; //1080p@60Hz 314 } 315} 316 317// Get the best mode for the current HD TV 318int ExternalDisplay::getBestMode() { 319 int bestOrder = 0; 320 int bestMode = m640x480p60_4_3; 321 Mutex::Autolock lock(mExtDispLock); 322 // for all the edid read, get the best mode 323 for(int i = 0; i < mModeCount; i++) { 324 int mode = mEDIDModes[i]; 325 int order = getModeOrder(mode); 326 if (order > bestOrder) { 327 bestOrder = order; 328 bestMode = mode; 329 } 330 } 331 return bestMode; 332} 333 334inline bool ExternalDisplay::isValidMode(int ID) 335{ 336 return ((ID >= m640x480p60_4_3) && (ID <= m1920x1080p30_16_9)); 337} 338 339void ExternalDisplay::setResolution(int ID) 340{ 341 struct fb_var_screeninfo info; 342 int ret = 0; 343 if (!openFramebuffer()) 344 return; 345 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 346 if(ret < 0) { 347 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 348 strerror(errno)); 349 } 350 351 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d)," 352 "(%d,%d,%d) %dMHz>", __FUNCTION__, 353 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, 354 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 355 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 356 mVInfo.pixclock/1000/1000); 357 //If its a valid mode and its a new ID - update var_screeninfo 358 if ((isValidMode(ID)) && mCurrentMode != ID) { 359 const struct disp_mode_timing_type *mode = 360 &supported_video_mode_lut[0]; 361 unsigned count = sizeof(supported_video_mode_lut)/sizeof 362 (*supported_video_mode_lut); 363 for (unsigned int i = 0; i < count; ++i) { 364 const struct disp_mode_timing_type *cur = 365 &supported_video_mode_lut[i]; 366 if (cur->video_format == ID) 367 mode = cur; 368 } 369 mode->set_info(mVInfo); 370 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d" 371 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID, 372 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, 373 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 374 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 375 mVInfo.pixclock/1000/1000); 376 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; 377 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo); 378 if(ret < 0) { 379 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s", 380 __FUNCTION__, strerror(errno)); 381 } 382 mCurrentMode = ID; 383 } 384 //Powerup 385 ret = ioctl(mFd, FBIOBLANK, FB_BLANK_UNBLANK); 386 if(ret < 0) { 387 ALOGD("In %s: FBIOBLANK failed Err Str = %s", __FUNCTION__, 388 strerror(errno)); 389 } 390 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 391 if(ret < 0) { 392 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 393 strerror(errno)); 394 } 395 //Pan_Display 396 ret = ioctl(mFd, FBIOPAN_DISPLAY, &mVInfo); 397 if(ret < 0) { 398 ALOGD("In %s: FBIOPAN_DISPLAY failed Err Str = %s", __FUNCTION__, 399 strerror(errno)); 400 } 401} 402 403void ExternalDisplay::setExternalDisplay(int connected) 404{ 405 406 hwc_context_t* ctx = mHwcContext; 407 if(ctx) { 408 ALOGD_IF(DEBUG, "%s: status = %d", __FUNCTION__, 409 connected); 410 if(connected) { 411 readResolution(); 412 //Get the best mode and set 413 // TODO: DO NOT call this for WFD 414 setResolution(getBestMode()); 415 setDpyAttr(); 416 //enable hdmi vsync 417 } else { 418 // Disable the hdmi vsync 419 closeFrameBuffer(); 420 resetInfo(); 421 } 422 // Store the external display 423 mExternalDisplay = connected; 424 const char* prop = (connected) ? "1" : "0"; 425 // set system property 426 property_set("hw.hdmiON", prop); 427 //Inform SF 428 ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false; 429 //TODO remove invalidate send hotplug 430 //ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL, connected); 431 ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = connected; 432 ctx->proc->invalidate(ctx->proc); 433 } 434 return; 435} 436 437bool ExternalDisplay::writeHPDOption(int userOption) const 438{ 439 bool ret = true; 440 int hdmiHPDFile = open(SYSFS_HPD,O_RDWR, 0); 441 if (hdmiHPDFile < 0) { 442 ALOGE("%s: state file '%s' not found : ret%d" 443 "err str: %s", __FUNCTION__, SYSFS_HPD, hdmiHPDFile, 444 strerror(errno)); 445 ret = false; 446 } else { 447 int err = -1; 448 ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, 449 userOption); 450 if(userOption) 451 err = write(hdmiHPDFile, "1", 2); 452 else 453 err = write(hdmiHPDFile, "0" , 2); 454 if (err <= 0) { 455 ALOGE("%s: file write failed '%s'", 456 __FUNCTION__, SYSFS_HPD); 457 ret = false; 458 } 459 close(hdmiHPDFile); 460 } 461 return ret; 462} 463 464bool ExternalDisplay::post() 465{ 466 if(mFd == -1) { 467 return false; 468 } else if(ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo) == -1) { 469 ALOGE("%s: FBIOPUT_VSCREENINFO failed, str: %s", __FUNCTION__, 470 strerror(errno)); 471 return false; 472 } 473 return true; 474} 475 476void ExternalDisplay::setDpyAttr() { 477 int width = 0, height = 0, fps = 0; 478 getAttrForMode(width, height, fps); 479 if(mHwcContext) { 480 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width; 481 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height; 482 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period = 1000000000l / 483 fps; 484 } 485} 486 487void ExternalDisplay::getAttrForMode(int& width, int& height, 488int& fps) { 489 switch (mCurrentMode) { 490 case m640x480p60_4_3: 491 width = 640; 492 height = 480; 493 fps = 60; 494 break; 495 case m720x480p60_4_3: 496 case m720x480p60_16_9: 497 width = 720; 498 height = 480; 499 fps = 60; 500 break; 501 case m720x576p50_4_3: 502 case m720x576p50_16_9: 503 width = 720; 504 height = 576; 505 fps = 50; 506 break; 507 case m1280x720p50_16_9: 508 width = 1280; 509 height = 720; 510 fps = 50; 511 break; 512 case m1280x720p60_16_9: 513 width = 1280; 514 height = 720; 515 fps = 60; 516 break; 517 case m1920x1080p24_16_9: 518 width = 1920; 519 height = 1080; 520 fps = 24; 521 break; 522 case m1920x1080p25_16_9: 523 width = 1920; 524 height = 1080; 525 fps = 25; 526 break; 527 case m1920x1080p30_16_9: 528 width = 1920; 529 height = 1080; 530 fps = 30; 531 break; 532 case m1920x1080p50_16_9: 533 width = 1920; 534 height = 1080; 535 fps = 50; 536 break; 537 case m1920x1080p60_16_9: 538 width = 1920; 539 height = 1080; 540 fps = 60; 541 break; 542 } 543} 544 545}; 546 547