1/* 2 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. 3 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided 12 * with the distribution. 13 * * Neither the name of The Linux Foundation nor the names of its 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29#include <cutils/log.h> 30#include <linux/msm_mdp.h> 31#include "mdp_version.h" 32#include "qd_utils.h" 33 34#define DEBUG 0 35 36ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::MDPVersion); 37namespace qdutils { 38 39#define TOKEN_PARAMS_DELIM "=" 40 41// chip variants have same major number and minor numbers usually vary 42// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000 43// 1001 - major number 44// 0000 - minor number 45// 8x26 v1 minor number is 0000 46// v2 minor number is 0001 etc.. 47#ifndef MDSS_MDP_HW_REV_100 48#define MDSS_MDP_HW_REV_100 0x10000000 //8974 v1 49#endif 50#ifndef MDSS_MDP_HW_REV_101 51#define MDSS_MDP_HW_REV_101 0x10010000 //8x26 52#endif 53#ifndef MDSS_MDP_HW_REV_102 54#define MDSS_MDP_HW_REV_102 0x10020000 //8974 v2 55#endif 56#ifndef MDSS_MDP_HW_REV_103 57#define MDSS_MDP_HW_REV_103 0x10030000 //8084 58#endif 59#ifndef MDSS_MDP_HW_REV_104 60#define MDSS_MDP_HW_REV_104 0x10040000 //Next version 61#endif 62#ifndef MDSS_MDP_HW_REV_105 63#define MDSS_MDP_HW_REV_105 0x10050000 //8994 64#endif 65#ifndef MDSS_MDP_HW_REV_106 66#define MDSS_MDP_HW_REV_106 0x10060000 //8x16 67#endif 68#ifndef MDSS_MDP_HW_REV_107 69#define MDSS_MDP_HW_REV_107 0x10070000 //Next version 70#endif 71#ifndef MDSS_MDP_HW_REV_108 72#define MDSS_MDP_HW_REV_108 0x10080000 //8x39 & 8x36 73#endif 74#ifndef MDSS_MDP_HW_REV_109 75#define MDSS_MDP_HW_REV_109 0x10090000 //Next version 76#endif 77#ifndef MDSS_MDP_HW_REV_200 78#define MDSS_MDP_HW_REV_200 0x20000000 //8092 79#endif 80#ifndef MDSS_MDP_HW_REV_206 81#define MDSS_MDP_HW_REV_206 0x20060000 //Future 82#endif 83 84MDPVersion::MDPVersion() 85{ 86 mMDPVersion = MDSS_V5; 87 mMdpRev = 0; 88 mRGBPipes = 0; 89 mVGPipes = 0; 90 mDMAPipes = 0; 91 mFeatures = 0; 92 mMDPUpscale = 1; 93 mMDPDownscale = 1; 94 mMacroTileEnabled = false; 95 mLowBw = 0; 96 mHighBw = 0; 97 mSourceSplit = false; 98 mSourceSplitAlways = false; 99 mRGBHasNoScalar = false; 100 mRotDownscale = false; 101 102 // this is the default limit of mixer unless driver reports it. 103 // For resolutions beyond this, we use dual/split overlay pipes. 104 mMaxMixerWidth = 2048; 105 106 updatePanelInfo(); 107 108 if(!updateSysFsInfo()) { 109 ALOGE("Unable to read display sysfs node"); 110 } 111 if (mMdpRev == MDP_V3_0_4){ 112 mMDPVersion = MDP_V3_0_4; 113 } 114 else if (mMdpRev == MDP_V3_0_5){ 115 mMDPVersion = MDP_V3_0_5; 116 } 117 118 mHasOverlay = false; 119 if((mMDPVersion >= MDP_V4_0) || 120 (mMDPVersion == MDP_V_UNKNOWN) || 121 (mMDPVersion == MDP_V3_0_4) || 122 (mMDPVersion == MDP_V3_0_5)) 123 mHasOverlay = true; 124 if(!updateSplitInfo()) { 125 ALOGE("Unable to read display split node"); 126 } 127} 128 129MDPVersion::~MDPVersion() { 130 close(mFd); 131} 132 133int MDPVersion::tokenizeParams(char *inputParams, const char *delim, 134 char* tokenStr[], int *idx) { 135 char *tmp_token = NULL; 136 char *temp_ptr; 137 int index = 0; 138 if (!inputParams) { 139 return -1; 140 } 141 tmp_token = strtok_r(inputParams, delim, &temp_ptr); 142 while (tmp_token != NULL) { 143 tokenStr[index++] = tmp_token; 144 tmp_token = strtok_r(NULL, " ", &temp_ptr); 145 } 146 *idx = index; 147 return 0; 148} 149// This function reads the sysfs node to read the primary panel type 150// and updates information accordingly 151void MDPVersion::updatePanelInfo() { 152 FILE *displayDeviceFP = NULL; 153 FILE *panelInfoNodeFP = NULL; 154 char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; 155 const char *strCmdPanel = "mipi dsi cmd panel"; 156 const char *strVideoPanel = "mipi dsi video panel"; 157 const char *strLVDSPanel = "lvds panel"; 158 const char *strEDPPanel = "edp panel"; 159 160 displayDeviceFP = fopen("/sys/class/graphics/fb0/msm_fb_type", "r"); 161 if(displayDeviceFP){ 162 fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, 163 displayDeviceFP); 164 if(strncmp(fbType, strCmdPanel, strlen(strCmdPanel)) == 0) { 165 mPanelInfo.mType = MIPI_CMD_PANEL; 166 } 167 else if(strncmp(fbType, strVideoPanel, strlen(strVideoPanel)) == 0) { 168 mPanelInfo.mType = MIPI_VIDEO_PANEL; 169 } 170 else if(strncmp(fbType, strLVDSPanel, strlen(strLVDSPanel)) == 0) { 171 mPanelInfo.mType = LVDS_PANEL; 172 } 173 else if(strncmp(fbType, strEDPPanel, strlen(strEDPPanel)) == 0) { 174 mPanelInfo.mType = EDP_PANEL; 175 } 176 fclose(displayDeviceFP); 177 } else { 178 ALOGE("Unable to read Primary Panel Information"); 179 } 180 181 panelInfoNodeFP = fopen("/sys/class/graphics/fb0/msm_fb_panel_info", "r"); 182 if(panelInfoNodeFP){ 183 size_t len = PAGE_SIZE; 184 ssize_t read; 185 char *readLine = (char *) malloc (len); 186 char property[PROPERTY_VALUE_MAX]; 187 while((read = getline((char **)&readLine, &len, 188 panelInfoNodeFP)) != -1) { 189 int token_ct=0; 190 char *tokens[10]; 191 memset(tokens, 0, sizeof(tokens)); 192 193 if(!tokenizeParams(readLine, TOKEN_PARAMS_DELIM, tokens, 194 &token_ct)) { 195 if(!strncmp(tokens[0], "pu_en", strlen("pu_en"))) { 196 mPanelInfo.mPartialUpdateEnable = atoi(tokens[1]); 197 ALOGI("PartialUpdate status: %s", 198 mPanelInfo.mPartialUpdateEnable? "Enabled" : 199 "Disabled"); 200 } 201 if(!strncmp(tokens[0], "xstart", strlen("xstart"))) { 202 mPanelInfo.mLeftAlign = atoi(tokens[1]); 203 ALOGI("Left Align: %d", mPanelInfo.mLeftAlign); 204 } 205 if(!strncmp(tokens[0], "walign", strlen("walign"))) { 206 mPanelInfo.mWidthAlign = atoi(tokens[1]); 207 ALOGI("Width Align: %d", mPanelInfo.mWidthAlign); 208 } 209 if(!strncmp(tokens[0], "ystart", strlen("ystart"))) { 210 mPanelInfo.mTopAlign = atoi(tokens[1]); 211 ALOGI("Top Align: %d", mPanelInfo.mTopAlign); 212 } 213 if(!strncmp(tokens[0], "halign", strlen("halign"))) { 214 mPanelInfo.mHeightAlign = atoi(tokens[1]); 215 ALOGI("Height Align: %d", mPanelInfo.mHeightAlign); 216 } 217 if(!strncmp(tokens[0], "min_w", strlen("min_w"))) { 218 mPanelInfo.mMinROIWidth = atoi(tokens[1]); 219 ALOGI("Min ROI Width: %d", mPanelInfo.mMinROIWidth); 220 } 221 if(!strncmp(tokens[0], "min_h", strlen("min_h"))) { 222 mPanelInfo.mMinROIHeight = atoi(tokens[1]); 223 ALOGI("Min ROI Height: %d", mPanelInfo.mMinROIHeight); 224 } 225 if(!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) { 226 mPanelInfo.mNeedsROIMerge = atoi(tokens[1]); 227 ALOGI("Needs ROI Merge: %d", mPanelInfo.mNeedsROIMerge); 228 } 229 if(!strncmp(tokens[0], "dyn_fps_en", strlen("dyn_fps_en"))) { 230 mPanelInfo.mDynFpsSupported = atoi(tokens[1]); 231 ALOGI("Dynamic Fps: %s", mPanelInfo.mDynFpsSupported ? 232 "Enabled" : "Disabled"); 233 } 234 if(!strncmp(tokens[0], "min_fps", strlen("min_fps"))) { 235 mPanelInfo.mMinFps = atoi(tokens[1]); 236 ALOGI("Min Panel fps: %d", mPanelInfo.mMinFps); 237 } 238 if(!strncmp(tokens[0], "max_fps", strlen("max_fps"))) { 239 mPanelInfo.mMaxFps = atoi(tokens[1]); 240 ALOGI("Max Panel fps: %d", mPanelInfo.mMaxFps); 241 } 242 } 243 } 244 if((property_get("persist.hwc.pubypass", property, 0) > 0) && 245 (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || 246 (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { 247 mPanelInfo.mPartialUpdateEnable = 0; 248 ALOGI("PartialUpdate disabled by property"); 249 } 250 fclose(panelInfoNodeFP); 251 } else { 252 ALOGE("Failed to open msm_fb_panel_info node"); 253 } 254} 255 256// This function reads the sysfs node to read MDP capabilities 257// and parses and updates information accordingly. 258bool MDPVersion::updateSysFsInfo() { 259 FILE *sysfsFd; 260 size_t len = PAGE_SIZE; 261 ssize_t read; 262 char *line = NULL; 263 char sysfsPath[255]; 264 memset(sysfsPath, 0, sizeof(sysfsPath)); 265 snprintf(sysfsPath , sizeof(sysfsPath), 266 "/sys/class/graphics/fb0/mdp/caps"); 267 char property[PROPERTY_VALUE_MAX]; 268 bool enableMacroTile = false; 269 270 if((property_get("persist.hwc.macro_tile_enable", property, NULL) > 0) && 271 (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || 272 (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { 273 enableMacroTile = true; 274 } 275 276 sysfsFd = fopen(sysfsPath, "rb"); 277 278 if (sysfsFd == NULL) { 279 ALOGE("%s: sysFsFile file '%s' not found", 280 __FUNCTION__, sysfsPath); 281 return false; 282 } else { 283 line = (char *) malloc(len); 284 while((read = getline(&line, &len, sysfsFd)) != -1) { 285 int index=0; 286 char *tokens[10]; 287 memset(tokens, 0, sizeof(tokens)); 288 289 // parse the line and update information accordingly 290 if(!tokenizeParams(line, TOKEN_PARAMS_DELIM, tokens, &index)) { 291 if(!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) { 292 mMdpRev = atoi(tokens[1]); 293 } 294 else if(!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) { 295 mRGBPipes = (uint8_t)atoi(tokens[1]); 296 } 297 else if(!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) { 298 mVGPipes = (uint8_t)atoi(tokens[1]); 299 } 300 else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) { 301 mDMAPipes = (uint8_t)atoi(tokens[1]); 302 } 303 else if(!strncmp(tokens[0], "max_downscale_ratio", 304 strlen("max_downscale_ratio"))) { 305 mMDPDownscale = atoi(tokens[1]); 306 } 307 else if(!strncmp(tokens[0], "max_upscale_ratio", 308 strlen("max_upscale_ratio"))) { 309 mMDPUpscale = atoi(tokens[1]); 310 } else if(!strncmp(tokens[0], "max_bandwidth_low", 311 strlen("max_bandwidth_low"))) { 312 mLowBw = atol(tokens[1]); 313 } else if(!strncmp(tokens[0], "max_bandwidth_high", 314 strlen("max_bandwidth_high"))) { 315 mHighBw = atol(tokens[1]); 316 } else if(!strncmp(tokens[0], "max_mixer_width", 317 strlen("max_mixer_width"))) { 318 mMaxMixerWidth = atoi(tokens[1]); 319 } else if(!strncmp(tokens[0], "features", strlen("features"))) { 320 for(int i=1; i<index;i++) { 321 if(!strncmp(tokens[i], "bwc", strlen("bwc"))) { 322 mFeatures |= MDP_BWC_EN; 323 } else if(!strncmp(tokens[i], "decimation", 324 strlen("decimation"))) { 325 mFeatures |= MDP_DECIMATION_EN; 326 } else if(!strncmp(tokens[i], "tile_format", 327 strlen("tile_format"))) { 328 if(enableMacroTile) 329 mMacroTileEnabled = true; 330 } else if(!strncmp(tokens[i], "src_split", 331 strlen("src_split"))) { 332 mSourceSplit = true; 333 } else if(!strncmp(tokens[i], "non_scalar_rgb", 334 strlen("non_scalar_rgb"))) { 335 mRGBHasNoScalar = true; 336 } else if(!strncmp(tokens[i], "rotator_downscale", 337 strlen("rotator_downscale"))) { 338 mRotDownscale = true; 339 } 340 } 341 } 342 } 343 } 344 free(line); 345 fclose(sysfsFd); 346 } 347 348 if(mMDPVersion >= qdutils::MDP_V4_2 and mMDPVersion < qdutils::MDSS_V5) { 349 mRotDownscale = true; 350 } 351 352 if(mSourceSplit) { 353 memset(sysfsPath, 0, sizeof(sysfsPath)); 354 snprintf(sysfsPath , sizeof(sysfsPath), 355 "/sys/class/graphics/fb0/msm_fb_src_split_info"); 356 357 sysfsFd = fopen(sysfsPath, "rb"); 358 if (sysfsFd == NULL) { 359 ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__, 360 sysfsPath, strerror(errno)); 361 return false; 362 } else { 363 line = (char *) malloc(len); 364 if((read = getline(&line, &len, sysfsFd)) != -1) { 365 if(!strncmp(line, "src_split_always", 366 strlen("src_split_always"))) { 367 mSourceSplitAlways = true; 368 } 369 } 370 free(line); 371 fclose(sysfsFd); 372 } 373 } 374 375 ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d," 376 "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev, 377 mRGBPipes, mVGPipes); 378 ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d", 379 __FUNCTION__, mDMAPipes, mMDPDownscale, mFeatures); 380 ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__, mLowBw, 381 mHighBw); 382 383 return true; 384} 385 386// This function reads the sysfs node to read MDP capabilities 387// and parses and updates information accordingly. 388bool MDPVersion::updateSplitInfo() { 389 if(mMDPVersion >= MDSS_V5) { 390 char split[64] = {0}; 391 FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r"); 392 if(fp){ 393 //Format "left right" space as delimiter 394 if(fread(split, sizeof(char), 64, fp)) { 395 split[sizeof(split) - 1] = '\0'; 396 mSplit.mLeft = atoi(split); 397 ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft); 398 char *rght = strpbrk(split, " "); 399 if(rght) 400 mSplit.mRight = atoi(rght + 1); 401 ALOGI_IF(mSplit.mRight, "Right Split=%d", mSplit.mRight); 402 } 403 } else { 404 ALOGE("Failed to open mdss_fb_split node"); 405 return false; 406 } 407 if(fp) 408 fclose(fp); 409 } 410 return true; 411} 412 413 414bool MDPVersion::hasMinCropWidthLimitation() const { 415 return mMdpRev <= MDSS_MDP_HW_REV_102; 416} 417 418bool MDPVersion::supportsDecimation() { 419 return mFeatures & MDP_DECIMATION_EN; 420} 421 422uint32_t MDPVersion::getMaxMDPDownscale() { 423 return mMDPDownscale; 424} 425 426uint32_t MDPVersion::getMaxMDPUpscale() { 427 return mMDPUpscale; 428} 429 430bool MDPVersion::supportsBWC() { 431 // BWC - Bandwidth Compression 432 return (mFeatures & MDP_BWC_EN); 433} 434 435bool MDPVersion::supportsMacroTile() { 436 // MACRO TILE support 437 return mMacroTileEnabled; 438} 439 440bool MDPVersion::isSrcSplit() const { 441 return mSourceSplit; 442} 443 444bool MDPVersion::isSrcSplitAlways() const { 445 return mSourceSplitAlways; 446} 447 448bool MDPVersion::isRGBScalarSupported() const { 449 return (!mRGBHasNoScalar); 450} 451 452bool MDPVersion::is8x26() { 453 return (mMdpRev >= MDSS_MDP_HW_REV_101 and 454 mMdpRev < MDSS_MDP_HW_REV_102); 455} 456 457bool MDPVersion::is8x74v2() { 458 return (mMdpRev >= MDSS_MDP_HW_REV_102 and 459 mMdpRev < MDSS_MDP_HW_REV_103); 460} 461 462bool MDPVersion::is8084() { 463 return (mMdpRev >= MDSS_MDP_HW_REV_103 and 464 mMdpRev < MDSS_MDP_HW_REV_104); 465} 466 467bool MDPVersion::is8092() { 468 return (mMdpRev >= MDSS_MDP_HW_REV_200 and 469 mMdpRev < MDSS_MDP_HW_REV_206); 470} 471 472bool MDPVersion::is8994() { 473 return (mMdpRev >= MDSS_MDP_HW_REV_105 and 474 mMdpRev < MDSS_MDP_HW_REV_106); 475} 476 477bool MDPVersion::is8x16() { 478 return (mMdpRev >= MDSS_MDP_HW_REV_106 and 479 mMdpRev < MDSS_MDP_HW_REV_107); 480} 481 482bool MDPVersion::is8x39() { 483 return (mMdpRev >= MDSS_MDP_HW_REV_108 and 484 mMdpRev < MDSS_MDP_HW_REV_109); 485} 486 487 488}; //namespace qdutils 489 490