Merge "overlay: maintain client requested size and aligned buffer size"
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 5038025..fb23470 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -54,6 +54,8 @@
     open: hwc_device_open
 };
 
+static void reset_panel(struct hwc_composer_device_1* dev);
+
 hwc_module_t HAL_MODULE_INFO_SYM = {
     common: {
         tag: HARDWARE_MODULE_TAG,
@@ -138,7 +140,9 @@
 
 static void handleGeomChange(hwc_context_t *ctx, int dpy,
         hwc_display_contents_1_t *list) {
-    if(list->flags & HWC_GEOMETRY_CHANGED) {
+    /* No point to calling overlay_set on MDP3 */
+    if(list->flags & HWC_GEOMETRY_CHANGED &&
+            ctx->mMDP.version >= qdutils::MDP_V4_0) {
         ctx->mOverlay->forceSet(dpy);
     }
 }
@@ -263,6 +267,12 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+    if (ctx->mPanelResetStatus) {
+        ALOGW("%s: panel is in bad state. reset the panel", __FUNCTION__);
+        reset_panel(dev);
+    }
+
     //Will be unlocked at the end of set
     ctx->mDrawLock.lock();
     reset(ctx, numDisplays, displays);
@@ -271,8 +281,6 @@
     ctx->mRotMgr->configBegin();
     overlay::Writeback::configBegin();
 
-    Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
-
     for (int32_t i = numDisplays; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
         int dpy = getDpyforExternalDisplay(ctx, i);
@@ -430,6 +438,33 @@
     return ret;
 }
 
+static void reset_panel(struct hwc_composer_device_1* dev)
+{
+    int ret = 0;
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+    if (!ctx->mPanelResetStatus)
+        return;
+
+    ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__);
+    ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1);
+    if (ret < 0) {
+        ALOGE("%s: FBIOBLANK failed to BLANK:  %s", __FUNCTION__,
+                                                            strerror(errno));
+    }
+
+    ALOGD("%s: calling UNBLANK DISPLAY and enabling vsync", __FUNCTION__);
+    ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 0);
+    if (ret < 0) {
+        ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__,
+                                                            strerror(errno));
+    }
+    hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1);
+
+    ctx->mPanelResetStatus = false;
+}
+
+
 static int hwc_query(struct hwc_composer_device_1* dev,
                      int param, int* value)
 {
@@ -664,6 +699,8 @@
     CALC_FPS();
     MDPComp::resetIdleFallBack();
     ctx->mVideoTransFlag = false;
+    if(ctx->mRotMgr->getNumActiveSessions() == 0)
+        Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
     //Was locked at the beginning of prepare
     ctx->mDrawLock.unlock();
     return ret;
@@ -770,6 +807,11 @@
     ovDump[0] = '\0';
     ctx->mRotMgr->getDump(ovDump, 1024);
     dumpsys_log(aBuf, ovDump);
+    ovDump[0] = '\0';
+    if(Writeback::getDump(ovDump, 1024)) {
+        dumpsys_log(aBuf, ovDump);
+        ovDump[0] = '\0';
+    }
     strlcpy(buff, aBuf.string(), buff_len);
 }
 
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 912da27..d54a5f2 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -182,16 +182,10 @@
 
     // Following are MDP3 limitations for which we
     // need to fallback to GPU composition:
-    // 1. HW issues with mdp3 and rotation.
-    // 2. Plane alpha is not supported by MDP3.
+    // 1. Plane alpha is not supported by MDP3.
     if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
         for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
             hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
-            if ((layer->transform & (HAL_TRANSFORM_FLIP_H |
-                   HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90)) &&
-                   ((layer->displayFrame.bottom - layer->displayFrame.top) % 16 ||
-                   (layer->displayFrame.right - layer->displayFrame.left) % 16))
-                return true;
             if (layer->planeAlpha != 0xFF)
                 return true;
         }
@@ -274,19 +268,24 @@
         return false;
     }
 
-    //Wait for the previous frame to complete before rendering onto it
-    if(mRelFd[0] >=0) {
-        sync_wait(mRelFd[0], 1000);
-        close(mRelFd[0]);
-        mRelFd[0] = -1;
-    }
-
     if (ctx->mMDP.version >= qdutils::MDP_V4_0) {
+        //Wait for the previous frame to complete before rendering onto it
+        if(mRelFd[0] >=0) {
+            sync_wait(mRelFd[0], 1000);
+            close(mRelFd[0]);
+            mRelFd[0] = -1;
+        }
+
         //Clear the visible region on the render buffer
         //XXX: Do this only when needed.
         hwc_rect_t clearRegion;
         getNonWormholeRegion(list, clearRegion);
         clear(renderBuffer, clearRegion);
+    } else {
+        if(mRelFd[0] >=0) {
+            copybit_device_t *copybit = getCopyBitDevice();
+            copybit->set_sync(copybit, mRelFd[0]);
+        }
     }
     // numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
     for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
@@ -319,6 +318,10 @@
         copybit_device_t *copybit = getCopyBitDevice();
         // Async mode
         copybit->flush_get_fence(copybit, fd);
+        if(mRelFd[0] >=0 && ctx->mMDP.version == qdutils::MDP_V3_0_4) {
+            close(mRelFd[0]);
+            mRelFd[0] = -1;
+        }
     }
     return true;
 }
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 12177b3..391b150 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -58,6 +58,7 @@
 }
 
 bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx,
+                                            hwc_layer_1_t *layer,
                                             ovutils::Whf &info,
                                             hwc_rect_t& sourceCrop,
                                             ovutils::eMdpFlags& mdpFlags,
@@ -74,6 +75,7 @@
             mRot = NULL;
             return false;
         }
+       ctx->mLayerRotMap[mDpy]->add(layer, mRot);
         info.format = (mRot)->getDstFormat();
         updateSource(orient, info, sourceCrop);
         rotFlags |= ovutils::ROT_PREROTATED;
@@ -162,7 +164,8 @@
                                    transform, orient);
         setMdpFlags(layer, mdpFlags, 0, transform);
         // For External use rotator if there is a rotation value set
-        ret = preRotateExtDisplay(ctx, info, sourceCrop, mdpFlags, rotFlags);
+        ret = preRotateExtDisplay(ctx, layer, info,
+                sourceCrop, mdpFlags, rotFlags);
         if(!ret) {
             ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
             return false;
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 0e3f29e..ce6af63 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -66,6 +66,7 @@
     bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
             int fbZorder);
     bool preRotateExtDisplay(hwc_context_t *ctx,
+                                 hwc_layer_1_t *layer,
                                  ovutils::Whf &info,
                                  hwc_rect_t& sourceCrop,
                                  ovutils::eMdpFlags& mdpFlags,
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index e65d5e7..bb52728 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -242,10 +242,9 @@
 
 void MDPComp::LayerCache::reset() {
     memset(&hnd, 0, sizeof(hnd));
-    mdpCount = 0;
-    fbCount = 0;
+    memset(&isFBComposed, true, sizeof(isFBComposed));
+    memset(&drop, false, sizeof(drop));
     layerCount = 0;
-    fbZ = -1;
 }
 
 void MDPComp::LayerCache::cacheAll(hwc_display_contents_1_t* list) {
@@ -256,10 +255,21 @@
 }
 
 void MDPComp::LayerCache::updateCounts(const FrameInfo& curFrame) {
-    mdpCount = curFrame.mdpCount;
-    fbCount = curFrame.fbCount;
     layerCount = curFrame.layerCount;
-    fbZ = curFrame.fbZ;
+    memcpy(&isFBComposed, &curFrame.isFBComposed, sizeof(isFBComposed));
+    memcpy(&drop, &curFrame.drop, sizeof(drop));
+}
+
+bool MDPComp::LayerCache::isSameFrame(const FrameInfo& curFrame) {
+    if(layerCount != curFrame.layerCount)
+        return false;
+    for(int i = 0; i < curFrame.layerCount; i++) {
+        if((curFrame.isFBComposed[i] != isFBComposed[i]) ||
+                (curFrame.drop[i] != drop[i])) {
+            return false;
+        }
+    }
+    return true;
 }
 
 bool MDPComp::isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer) {
@@ -1167,13 +1177,9 @@
         } else { //Success
             //Any change in composition types needs an FB refresh
             mCurrentFrame.needsRedraw = false;
-            if(mCurrentFrame.fbCount &&
-                    ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
-                     (mCurrentFrame.fbCount != mCachedFrame.fbCount) ||
-                     (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
-                     (!mCurrentFrame.mdpCount) ||
+            if(!mCachedFrame.isSameFrame(mCurrentFrame) ||
                      (list->flags & HWC_GEOMETRY_CHANGED) ||
-                     isSkipPresent(ctx, mDpy))) {
+                     isSkipPresent(ctx, mDpy)) {
                 mCurrentFrame.needsRedraw = true;
             }
         }
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 3882bee..1d5d715 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -108,10 +108,9 @@
     /* cached data */
     struct LayerCache {
         int layerCount;
-        int mdpCount;
-        int fbCount;
-        int fbZ;
         buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
+        bool isFBComposed[MAX_NUM_APP_LAYERS];
+        bool drop[MAX_NUM_APP_LAYERS];
 
         /* c'tor */
         LayerCache();
@@ -119,6 +118,7 @@
         void reset();
         void cacheAll(hwc_display_contents_1_t* list);
         void updateCounts(const FrameInfo&);
+        bool isSameFrame(const FrameInfo& curFrame);
     };
 
     /* allocates pipe from pipe book */
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 8906216..926f425 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -85,6 +85,24 @@
     return -1;
 }
 
+static bool getPanelResetStatus(hwc_context_t* ctx, const char* strUdata, int len)
+{
+    const char* iter_str = strUdata;
+    if (strcasestr("change@/devices/virtual/graphics/fb0", strUdata)) {
+        while(((iter_str - strUdata) <= len) && (*iter_str)) {
+            char* pstr = strstr(iter_str, "PANEL_ALIVE=0");
+            if (pstr != NULL) {
+                ALOGE("%s: got change event in fb0 with PANEL_ALIVE=0",
+                                                           __FUNCTION__);
+                ctx->mPanelResetStatus = true;
+                return true;
+            }
+            iter_str += strlen(iter_str)+1;
+        }
+    }
+    return false;
+}
+
 /* Parse uevent data for action requested for the display */
 static int getConnectedState(const char* strUdata, int len)
 {
@@ -101,6 +119,11 @@
 
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
+    bool bpanelReset = getPanelResetStatus(ctx, udata, len);
+    if (bpanelReset) {
+        return;
+    }
+
     int dpy = getConnectedDisplay(udata);
     if(dpy < 0) {
         ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 06d387d..61f3f1c 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -312,6 +312,12 @@
 
     float fbWidth = ctx->dpyAttr[dpy].xres;
     float fbHeight = ctx->dpyAttr[dpy].yres;
+    if(ctx->dpyAttr[dpy].mDownScaleMode) {
+        // if downscale Mode is enabled for external, need to query
+        // the actual width and height, as that is the physical w & h
+        ctx->mExtDisplay->getAttributes((int&)fbWidth, (int&)fbHeight);
+    }
+
 
     // Since external is rotated 90, need to swap width/height
     int extOrient = getExtOrientation(ctx);
@@ -1448,7 +1454,8 @@
             ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
         *rot = ctx->mRotMgr->getNext();
         if(*rot == NULL) return -1;
-        BwcPM::setBwc(ctx, crop, dst, transform, mdpFlags);
+        if(!dpy)
+            BwcPM::setBwc(ctx, crop, dst, transform, mdpFlags);
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
@@ -1718,10 +1725,6 @@
     if((crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
         return;
     }
-    //External connected
-    if(ctx->mExtDisplay->isConnected()|| ctx->mVirtualDisplay->isConnected()) {
-        return;
-    }
     //Decimation necessary, cannot use BWC. H/W requirement.
     if(qdutils::MDPVersion::getInstance().supportsDecimation()) {
         int src_w = crop.right - crop.left;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index d281fb0..1f1953b 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -427,6 +427,9 @@
     bool mBufferMirrorMode;
 
     qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
+
+    // Panel reset flag will be set if BTA check fails
+    bool mPanelResetStatus;
 };
 
 namespace qhwc {
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 84a9818..7b3dda1 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -168,8 +168,8 @@
             mRot[i]->getDump(buf, len);
         }
     }
-    char str[32] = {'\0'};
-    snprintf(str, 32, "\n================\n");
+    char str[4] = {'\0'};
+    snprintf(str, 4, "\n");
     strncat(buf, str, strlen(str));
 }
 
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index f551f1d..7c1095f 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -238,6 +238,7 @@
      */
     void getDump(char *buf, size_t len);
     int getRotDevFd();
+    int getNumActiveSessions() { return mUseCount; }
 private:
     overlay::Rotator *mRot[MAX_ROT_SESS];
     int mUseCount;
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index fd8bfe2..1377182 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -427,9 +427,8 @@
         const msmfb_data& ov) {
     char str_data[256] = {'\0'};
     snprintf(str_data, 256,
-            "%s offset=%d memid=%d id=%d flags=0x%x priv=%d\n",
-            prefix, ov.offset, ov.memory_id, ov.id, ov.flags,
-            ov.priv);
+            "%s offset=%d memid=%d id=%d flags=0x%x\n",
+            prefix, ov.offset, ov.memory_id, ov.id, ov.flags);
     strncat(buf, str_data, strlen(str_data));
 }
 
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
index 5c6d773..50aa337 100644
--- a/liboverlay/overlayWriteback.cpp
+++ b/liboverlay/overlayWriteback.cpp
@@ -240,6 +240,17 @@
     }
 }
 
+bool Writeback::getDump(char *buf, size_t len) {
+    if(sWb) {
+        utils::getDump(buf, len, "WBData", sWb->mFbData);
+        char str[4] = {'\0'};
+        snprintf(str, 4, "\n");
+        strncat(buf, str, strlen(str));
+        return true;
+    }
+    return false;
+}
+
 Writeback *Writeback::sWb = 0;
 bool Writeback::sUsed = false;
 
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
index 8c0c52a..9785b64 100644
--- a/liboverlay/overlayWriteback.h
+++ b/liboverlay/overlayWriteback.h
@@ -92,6 +92,9 @@
     static void configBegin() { sUsed = false; }
     static void configDone();
     static void clear();
+    //Will take a dump of data structure only if there is an instance existing
+    //Returns true if dump is added to the input buffer, false otherwise
+    static bool getDump(char *buf, size_t len);
 
 private:
     explicit Writeback();
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index a444920..259d078 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -33,66 +33,55 @@
 #include <linux/msm_mdp.h>
 #include "mdp_version.h"
 
+#define DEBUG 0
+
 ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::MDPVersion);
 namespace qdutils {
 
+#define TOKEN_PARAMS_DELIM  "="
+
 MDPVersion::MDPVersion()
 {
     int fb_fd = open("/dev/graphics/fb0", O_RDWR);
-    int mdp_version = MDP_V_UNKNOWN;
     char panel_type = 0;
     struct fb_fix_screeninfo fb_finfo;
 
+    mMDPVersion = MDP_V_UNKNOWN;
     mMdpRev = 0;
     mRGBPipes = 0;
     mVGPipes = 0;
     mDMAPipes = 0;
     mFeatures = 0;
+    mMDPUpscale = 0;
     //TODO get this from driver, default for A-fam to 8
     mMDPDownscale = 8;
     mFd = fb_fd;
 
     if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_finfo) < 0) {
         ALOGE("FBIOGET_FSCREENINFO failed");
-        mdp_version =  MDP_V_UNKNOWN;
     } else {
         if(!strncmp(fb_finfo.id, "msmfb", 5)) {
             char str_ver[4] = { 0 };
             memcpy(str_ver, &fb_finfo.id[5], 3);
             str_ver[3] = '\0';
-            mdp_version = atoi(str_ver);
-
+            mMDPVersion = atoi(str_ver);
             //Normalize MDP version to ease comparison.
             //This is needed only because
             //MDP 3.0.3 reports value as 303 which
             //is more than all the others
-            if (mdp_version < 100)
-                mdp_version *= 10;
+            if (mMDPVersion < 100)
+                mMDPVersion *= 10;
 
             mRGBPipes = mVGPipes = 2;
 
         } else if (!strncmp(fb_finfo.id, "mdssfb", 6)) {
-            mdp_version = MDSS_V5;
-#ifdef MDSS_TARGET
-            struct msmfb_metadata metadata;
-            memset(&metadata, 0 , sizeof(metadata));
-            metadata.op = metadata_op_get_caps;
-            if (ioctl(fb_fd, MSMFB_METADATA_GET, &metadata) == -1) {
-                ALOGE("Error retrieving MDP revision and pipes info");
-                mdp_version = MDP_V_UNKNOWN;
-            } else {
-                mMdpRev = metadata.data.caps.mdp_rev;
-                mRGBPipes = metadata.data.caps.rgb_pipes;
-                mVGPipes = metadata.data.caps.vig_pipes;
-                mDMAPipes = metadata.data.caps.dma_pipes;
-                mFeatures = metadata.data.caps.features;
-                if (metadata.data.caps.mdp_rev == MDP_V3_0_4){
-                    mdp_version = MDP_V3_0_4;
-                }
+            mMDPVersion = MDSS_V5;
+            if(!updateSysFsInfo()) {
+                ALOGE("Unable to read updateSysFsInfo");
             }
-#endif
-        } else {
-            mdp_version = MDP_V_UNKNOWN;
+            if (mMdpRev == MDP_V3_0_4){
+                mMDPVersion = MDP_V3_0_4;
+            }
         }
 
         /* Assumes panel type is 2nd element in '_' delimited id string */
@@ -104,16 +93,12 @@
         panel_type = *ptype;
     }
     mPanelType = panel_type;
-    mMDPVersion = mdp_version;
     mHasOverlay = false;
     if((mMDPVersion >= MDP_V4_0) ||
        (mMDPVersion == MDP_V_UNKNOWN) ||
        (mMDPVersion == MDP_V3_0_4))
         mHasOverlay = true;
     if(mMDPVersion >= MDSS_V5) {
-        //TODO get this from driver
-        mMDPDownscale = 4;
-
         char split[64] = {0};
         FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
         if(fp){
@@ -139,6 +124,95 @@
     close(mFd);
 }
 
+int MDPVersion::tokenizeParams(char *inputParams, const char *delim,
+                                char* tokenStr[], int *idx) {
+    char *tmp_token = NULL;
+    char *temp_ptr;
+    int ret = 0, index = 0;
+    if (!inputParams) {
+        return -1;
+    }
+    tmp_token = strtok_r(inputParams, delim, &temp_ptr);
+    while (tmp_token != NULL) {
+        tokenStr[index++] = tmp_token;
+        tmp_token = strtok_r(NULL, " ", &temp_ptr);
+    }
+    *idx = index;
+    return 0;
+}
+
+
+// This function reads the sysfs node to read MDP capabilities
+// and parses and updates information accordingly.
+bool MDPVersion::updateSysFsInfo() {
+    FILE *sysfsFd;
+    size_t len = 0;
+    ssize_t read;
+    char *line = NULL;
+    char sysfsPath[255];
+    memset(sysfsPath, 0, sizeof(sysfsPath));
+    snprintf(sysfsPath , sizeof(sysfsPath),
+            "/sys/class/graphics/fb0/mdp/caps");
+
+    sysfsFd = fopen(sysfsPath, "rb");
+
+    if (sysfsFd == NULL) {
+        ALOGE("%s: sysFsFile file '%s' not found",
+                __FUNCTION__, sysfsPath);
+        return false;
+    } else {
+        while((read = getline(&line, &len, sysfsFd)) != -1) {
+            int index=0;
+            char *tokens[10];
+            memset(tokens, 0, sizeof(tokens));
+
+            // parse the line and update information accordingly
+            if(!tokenizeParams(line, TOKEN_PARAMS_DELIM, tokens, &index)) {
+                if(!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) {
+                    mMdpRev = atoi(tokens[1]);
+                }
+                else if(!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) {
+                    mRGBPipes = atoi(tokens[1]);
+                }
+                else if(!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) {
+                    mVGPipes = atoi(tokens[1]);
+                }
+                else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
+                    mDMAPipes = atoi(tokens[1]);
+                }
+                else if(!strncmp(tokens[0], "max_downscale_ratio",
+                                strlen("max_downscale_ratio"))) {
+                    mMDPDownscale = atoi(tokens[1]);
+                }
+                else if(!strncmp(tokens[0], "max_upscale_ratio",
+                                strlen("max_upscale_ratio"))) {
+                    mMDPUpscale = atoi(tokens[1]);
+                }
+                else if(!strncmp(tokens[0], "features", strlen("features"))) {
+                    for(int i=1; i<index;i++) {
+                        if(!strncmp(tokens[i], "bwc", strlen("bwc"))) {
+                           mFeatures |= MDP_BWC_EN;
+                        }
+                        else if(!strncmp(tokens[i], "decimation",
+                                    strlen("decimation"))) {
+                           mFeatures |= MDP_DECIMATION_EN;
+                        }
+                    }
+                }
+            }
+            free(line);
+            line = NULL;
+        }
+        fclose(sysfsFd);
+    }
+    ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
+                    "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev,
+                    mRGBPipes, mVGPipes);
+    ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d",
+                     __FUNCTION__,  mDMAPipes, mMDPDownscale, mFeatures);
+    return true;
+}
+
 bool MDPVersion::supportsDecimation() {
     return mFeatures & MDP_DECIMATION_EN;
 }
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 8d23b2d..a14592b 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -106,6 +106,9 @@
     int getLeftSplit() { return mSplit.left(); }
     int getRightSplit() { return mSplit.right(); }
 private:
+    bool updateSysFsInfo();
+    int tokenizeParams(char *inputParams, const char *delim,
+                        char* tokenStr[], int *idx);
     int mFd;
     int mMDPVersion;
     char mPanelType;
@@ -116,6 +119,7 @@
     uint8_t mDMAPipes;
     uint32_t mFeatures;
     uint32_t mMDPDownscale;
+    uint32_t mMDPUpscale;
     Split mSplit;
 };
 }; //namespace qdutils