Merge "hwc: allow DMA pipe in BLOCK mode for virtual dpy"
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 5d8da05..47d9b93 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -714,6 +714,10 @@
     ctx->mAlpha = MDP_ALPHA_NOP;
     ctx->mFlags = 0;
     ctx->sync.flags = 0;
+    ctx->relFence = -1;
+    for (int i=0; i < MDP_MAX_FENCE_FD; i++) {
+        ctx->acqFence[i] = -1;
+    }
     ctx->sync.acq_fen_fd = ctx->acqFence;
     ctx->sync.rel_fen_fd = &ctx->relFence;
     ctx->list.count = 0;
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 045edd8..d905e0d 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -42,6 +42,9 @@
 #define MAX_SYSFS_FILE_PATH             255
 #define UNKNOWN_STRING                  "unknown"
 #define SPD_NAME_LENGTH                 16
+/* Max. resolution assignable to when downscale */
+#define SUPPORTED_DOWNSCALE_EXT_AREA    (1920*1080)
+
 
 int ExternalDisplay::configure() {
     if(!openFrameBuffer()) {
@@ -590,7 +593,7 @@
             // downscale mode
             // Restrict this upto 1080p resolution max
             if(((priW * priH) > (width * height)) &&
-                 (priW <= qdutils::MAX_DISPLAY_DIM )) {
+               ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
                 // HDMI is always in landscape, so always assign the higher
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index bb1b032..bb6a49c 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -178,13 +178,14 @@
             hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
             if (layer->planeAlpha != 0xFF)
                 return true;
+            hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
 
             if (layer->transform & HAL_TRANSFORM_ROT_90) {
-                src_h = layer->sourceCrop.right - layer->sourceCrop.left;
-                src_w = layer->sourceCrop.bottom - layer->sourceCrop.top;
+                src_h = sourceCrop.right - sourceCrop.left;
+                src_w = sourceCrop.bottom - sourceCrop.top;
             } else {
-                src_h = layer->sourceCrop.bottom - layer->sourceCrop.top;
-                src_w = layer->sourceCrop.right - layer->sourceCrop.left;
+                src_h = sourceCrop.bottom - sourceCrop.top;
+                src_w = sourceCrop.right - sourceCrop.left;
             }
             dst_h = layer->displayFrame.bottom - layer->displayFrame.top;
             dst_w = layer->displayFrame.right - layer->displayFrame.left;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 2a1b123..a0b9646 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -43,8 +43,9 @@
 bool MDPComp::sEnableMixedMode = true;
 bool MDPComp::sEnablePartialFrameUpdate = false;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
-float MDPComp::sMaxBw = 2.3f;
+double MDPComp::sMaxBw = 0.0;
 double MDPComp::sBwClaimed = 0.0;
+bool MDPComp::sEnable4k2kYUVSplit = false;
 
 MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
     if(isDisplaySplit(ctx, dpy)) {
@@ -128,13 +129,6 @@
             sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
     }
 
-    if(property_get("debug.mdpcomp.bw", property, "0") > 0) {
-        float val = atof(property);
-        if(val > 0.0f) {
-            sMaxBw = val;
-        }
-    }
-
     if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
         // Idle invalidation is not necessary on command mode panels
         long idle_timeout = DEFAULT_IDLE_TIME;
@@ -154,6 +148,12 @@
             idleInvalidator->init(timeout_handler, ctx, idle_timeout);
         }
     }
+
+    if((property_get("debug.mdpcomp.4k2kSplit", property, "0") > 0) &&
+            (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+             (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+        sEnable4k2kYUVSplit = true;
+    }
     return true;
 }
 
@@ -293,6 +293,10 @@
     private_handle_t *hnd = (private_handle_t *)layer->handle;
 
     if(!hnd) {
+        if (layer->flags & HWC_COLOR_FILL) {
+            // Color layer
+            return true;
+        }
         ALOGE("%s: layer handle is NULL", __FUNCTION__);
         return false;
     }
@@ -322,23 +326,25 @@
     if((crop_w < 5)||(crop_h < 5))
         return false;
 
-    const uint32_t downscale =
+    if((w_dscale > 1.0f) || (h_dscale > 1.0f)) {
+        const uint32_t downscale =
             qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
-    if(ctx->mMDP.version >= qdutils::MDSS_V5) {
-        /* Workaround for downscales larger than 4x.
-         * Will be removed once decimator block is enabled for MDSS
-         */
-        if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
-            if(crop_w > MAX_DISPLAY_DIM || w_dscale > downscale ||
-                    h_dscale > downscale)
-                return false;
-        } else {
-            if(w_dscale > 64 || h_dscale > 64)
+        if(ctx->mMDP.version >= qdutils::MDSS_V5) {
+            /* Workaround for downscales larger than 4x.
+             * Will be removed once decimator block is enabled for MDSS
+             */
+            if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
+                if(crop_w > MAX_DISPLAY_DIM || w_dscale > downscale ||
+                   h_dscale > downscale)
+                    return false;
+            } else {
+                if(w_dscale > 64 || h_dscale > 64)
+                    return false;
+            }
+        } else { //A-family
+            if(w_dscale > downscale || h_dscale > downscale)
                 return false;
         }
-    } else { //A-family
-        if(w_dscale > downscale || h_dscale > downscale)
-            return false;
     }
 
     return true;
@@ -588,6 +594,10 @@
     mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
         mCurrentFrame.dropCount;
 
+    if(sEnable4k2kYUVSplit){
+        modifymdpCountfor4k2k(ctx, list);
+    }
+
     if(!resourceCheck(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
         return false;
@@ -643,6 +653,10 @@
 
     int mdpCount = mCurrentFrame.mdpCount;
 
+    if(sEnable4k2kYUVSplit){
+        modifymdpCountfor4k2k(ctx, list);
+    }
+
     //Will benefit cases where a video has non-updating background.
     if((mDpy > HWC_DISPLAY_PRIMARY) and
             (mdpCount > MAX_SEC_LAYERS)) {
@@ -713,6 +727,10 @@
     mCurrentFrame.fbCount = batchSize;
     mCurrentFrame.mdpCount = mCurrentFrame.layerCount - batchSize;
 
+    if(sEnable4k2kYUVSplit){
+        modifymdpCountfor4k2k(ctx, list);
+    }
+
     if(!resourceCheck(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
         return false;
@@ -764,6 +782,10 @@
     mCurrentFrame.fbCount = fbBatchSize;
     mCurrentFrame.mdpCount = mCurrentFrame.layerCount - fbBatchSize;
 
+    if(sEnable4k2kYUVSplit){
+        modifymdpCountfor4k2k(ctx, list);
+    }
+
     if(!resourceCheck(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
         return false;
@@ -1092,10 +1114,23 @@
             MdpPipeInfo* cur_pipe = mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
             cur_pipe->zOrder = mdpNextZOrder++;
 
-
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+                if(configure4k2kYuv(ctx, layer,
+                            mCurrentFrame.mdpToLayer[mdpIndex])
+                        != 0 ){
+                    ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
+                            for layer %d",__FUNCTION__, index);
+                    return false;
+                }
+                else{
+                    mdpNextZOrder++;
+                }
+                continue;
+            }
             if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
                 ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
-                         layer %d",__FUNCTION__, index);
+                        layer %d",__FUNCTION__, index);
                 return false;
             }
         }
@@ -1119,6 +1154,20 @@
                     mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
             cur_pipe->zOrder = mdpIdx++;
 
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+                if(configure4k2kYuv(ctx, layer,
+                            mCurrentFrame.mdpToLayer[mdpIndex])
+                        != 0 ){
+                    ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
+                            for layer %d",__FUNCTION__, index);
+                    return false;
+                }
+                else{
+                    mdpIdx++;
+                }
+                continue;
+            }
             if(configure(ctx, layer,
                         mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
                 ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
@@ -1142,7 +1191,7 @@
         return false;
     }
 
-    uint32_t size = calcMDPBytesRead(ctx, list);
+    double size = calcMDPBytesRead(ctx, list);
     if(!bandwidthCheck(ctx, size)) {
         ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
         return false;
@@ -1151,12 +1200,15 @@
     return true;
 }
 
-uint32_t MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
+double MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
-    uint32_t size = 0;
+    double size = 0;
+    const double GIG = 1000000000.0;
 
-    if(!qdutils::MDPVersion::getInstance().is8x74v2())
-        return 0;
+    //Skip for targets where no device tree value for bw is supplied
+    if(sMaxBw <= 0.0) {
+        return 0.0;
+    }
 
     for (uint32_t i = 0; i < list->numHwLayers - 1; i++) {
         if(!mCurrentFrame.isFBComposed[i]) {
@@ -1166,33 +1218,37 @@
                 hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
                 hwc_rect_t dst = layer->displayFrame;
                 float bpp = ((float)hnd->size) / (hnd->width * hnd->height);
-                size += bpp * (crop.right - crop.left) *
-                    (crop.bottom - crop.top) *
-                    ctx->dpyAttr[mDpy].yres / (dst.bottom - dst.top);
+                size += (bpp * (crop.right - crop.left) *
+                        (crop.bottom - crop.top) *
+                        ctx->dpyAttr[mDpy].yres / (dst.bottom - dst.top)) /
+                        GIG;
             }
         }
     }
 
     if(mCurrentFrame.fbCount) {
         hwc_layer_1_t* layer = &list->hwLayers[list->numHwLayers - 1];
-        private_handle_t *hnd = (private_handle_t *)layer->handle;
-        if (hnd)
-            size += hnd->size;
+        int tempw, temph;
+        size += (getBufferSizeAndDimensions(
+                    layer->displayFrame.right - layer->displayFrame.left,
+                    layer->displayFrame.bottom - layer->displayFrame.top,
+                    HAL_PIXEL_FORMAT_RGBA_8888,
+                    tempw, temph)) / GIG;
     }
 
     return size;
 }
 
-bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const uint32_t& size) {
-    //Will be added for other targets if we run into bandwidth issues and when
-    //we have profiling data to set an upper limit.
-    if(qdutils::MDPVersion::getInstance().is8x74v2()) {
-        const uint32_t ONE_GIG = 1000 * 1000 * 1000;
-        double panelRefRate =
-                1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
-        if((size * panelRefRate) > ((sMaxBw - sBwClaimed) * ONE_GIG)) {
-            return false;
-        }
+bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const double& size) {
+    //Skip for targets where no device tree value for bw is supplied
+    if(sMaxBw <= 0.0) {
+        return true;
+    }
+
+    double panelRefRate =
+            1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+    if((size * panelRefRate) > (sMaxBw - sBwClaimed)) {
+        return false;
     }
     return true;
 }
@@ -1200,6 +1256,7 @@
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int ret = 0;
     const int numLayers = ctx->listStats[mDpy].numAppLayers;
+    MDPVersion& mdpVersion = qdutils::MDPVersion::getInstance();
 
     //reset old data
     mCurrentFrame.reset(numLayers);
@@ -1227,11 +1284,31 @@
 
     generateROI(ctx, list);
 
+    //Convert from kbps to gbps
+    sMaxBw = mdpVersion.getHighBw() / 1000000.0;
+    if (ctx->mExtDisplay->isConnected() || ctx->mMDP.panel != MIPI_CMD_PANEL) {
+        sMaxBw = mdpVersion.getLowBw() / 1000000.0;
+    }
+
     //Check whether layers marked for MDP Composition is actually doable.
     if(isFullFrameDoable(ctx, list)) {
         mCurrentFrame.map();
         //Configure framebuffer first if applicable
         if(mCurrentFrame.fbZ >= 0) {
+            //If 4k2k Yuv layer split is possible,  and if
+            //fbz is above 4k2k layer, increment fb zorder by 1
+            //as we split 4k2k layer and increment zorder for right half
+            //of the layer
+            if(sEnable4k2kYUVSplit){
+                int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
+                for(int index = 0; index < n4k2kYuvCount; index++){
+                    int n4k2kYuvIndex =
+                            ctx->listStats[mDpy].yuv4k2kIndices[index];
+                    if(mCurrentFrame.fbZ > n4k2kYuvIndex){
+                        mCurrentFrame.fbZ += 1;
+                    }
+                }
+            }
             if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list,
                         mCurrentFrame.fbZ)) {
                 ALOGE("%s configure framebuffer failed", __func__);
@@ -1262,6 +1339,11 @@
         //Try to compose atleast YUV layers through MDP comp and let
         //all the RGB layers compose in FB
         //Destination over
+
+        if(sEnable4k2kYUVSplit){
+            modifymdpCountfor4k2k(ctx, list);
+        }
+
         mCurrentFrame.fbZ = -1;
         if(mCurrentFrame.fbCount)
             mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
@@ -1305,14 +1387,51 @@
     }
 
 exit:
-    //gbps (bytes / nanosec = gigabytes / sec)
-    sBwClaimed += calcMDPBytesRead(ctx, list) /
-            (double)ctx->dpyAttr[mDpy].vsync_period;
+    double panelRefRate =
+            1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+    sBwClaimed += calcMDPBytesRead(ctx, list) * panelRefRate;
     return ret;
 }
 
+bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list, int index) {
+
+    bool bRet = true;
+    hwc_layer_1_t* layer = &list->hwLayers[index];
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    int mdpIndex = mCurrentFrame.layerToMDP[index];
+    PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+    info.pipeInfo = new MdpYUVPipeInfo;
+    info.rot = NULL;
+    MdpYUVPipeInfo& pipe_info = *(MdpYUVPipeInfo*)info.pipeInfo;
+    ePipeType type =  MDPCOMP_OV_VG;
+
+    pipe_info.lIndex = ovutils::OV_INVALID;
+    pipe_info.rIndex = ovutils::OV_INVALID;
+
+    pipe_info.lIndex = getMdpPipe(ctx, type, Overlay::MIXER_DEFAULT);
+    if(pipe_info.lIndex == ovutils::OV_INVALID){
+        bRet = false;
+        ALOGD_IF(isDebug(),"%s: allocating first VG pipe failed",
+                __FUNCTION__);
+    }
+    pipe_info.rIndex = getMdpPipe(ctx, type, Overlay::MIXER_DEFAULT);
+    if(pipe_info.rIndex == ovutils::OV_INVALID){
+        bRet = false;
+        ALOGD_IF(isDebug(),"%s: allocating second VG pipe failed",
+                __FUNCTION__);
+    }
+    return bRet;
+}
 //=============MDPCompNonSplit===================================================
 
+void MDPCompNonSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
+         hwc_display_contents_1_t* list){
+    //As we split 4kx2k yuv layer and program to 2 VG pipes
+    //(if available) increase mdpcount accordingly
+    mCurrentFrame.mdpCount += ctx->listStats[mDpy].yuv4k2kCount;
+}
+
 /*
  * Configures pipe(s) for MDP composition
  */
@@ -1364,7 +1483,10 @@
             hwc_layer_1_t* layer = &list->hwLayers[i];
             hwc_rect_t dst = layer->displayFrame;
             private_handle_t *hnd = (private_handle_t *)layer->handle;
-            if(isYuvBuffer(hnd)) {
+            if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+                pipesNeeded = pipesNeeded + 2;
+            }
+            else if(isYuvBuffer(hnd)) {
                 pipesNeeded++;
             }
         }
@@ -1389,6 +1511,12 @@
 
         hwc_layer_1_t* layer = &list->hwLayers[index];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
+        if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+            if(allocSplitVGPipesfor4k2k(ctx, list, index)){
+                continue;
+            }
+        }
+
         int mdpIndex = mCurrentFrame.layerToMDP[index];
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
         info.pipeInfo = new MdpPipeInfoNonSplit;
@@ -1414,6 +1542,20 @@
     return true;
 }
 
+int MDPCompNonSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        PipeLayerPair& PipeLayerPair) {
+    MdpYUVPipeInfo& mdp_info =
+            *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
+    eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+    eIsFg isFg = IS_FG_OFF;
+    eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+    eDest lDest = mdp_info.lIndex;
+    eDest rDest = mdp_info.rIndex;
+
+    return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
+            lDest, rDest, &PipeLayerPair.rot);
+}
+
 bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
 
     if(!isEnabled()) {
@@ -1446,42 +1588,86 @@
         hwc_layer_1_t *layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         if(!hnd) {
-            ALOGE("%s handle null", __FUNCTION__);
-            return false;
+            if (!(layer->flags & HWC_COLOR_FILL)) {
+                ALOGE("%s handle null", __FUNCTION__);
+                return false;
+            }
+            // No PLAY for Color layer
+            layerProp[i].mFlags &= ~HWC_MDPCOMP;
+            continue;
         }
 
         int mdpIndex = mCurrentFrame.layerToMDP[i];
 
-        MdpPipeInfoNonSplit& pipe_info =
+        if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit)
+        {
+            MdpYUVPipeInfo& pipe_info =
+                *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+            Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+            ovutils::eDest indexL = pipe_info.lIndex;
+            ovutils::eDest indexR = pipe_info.rIndex;
+            int fd = hnd->fd;
+            uint32_t offset = hnd->offset;
+            if(rot) {
+                rot->queueBuffer(fd, offset);
+                fd = rot->getDstMemId();
+                offset = rot->getDstOffset();
+            }
+            if(indexL != ovutils::OV_INVALID) {
+                ovutils::eDest destL = (ovutils::eDest)indexL;
+                ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                        using  pipe: %d", __FUNCTION__, layer, hnd, indexL );
+                if (!ov.queueBuffer(fd, offset, destL)) {
+                    ALOGE("%s: queueBuffer failed for display:%d",
+                            __FUNCTION__, mDpy);
+                    return false;
+                }
+            }
+
+            if(indexR != ovutils::OV_INVALID) {
+                ovutils::eDest destR = (ovutils::eDest)indexR;
+                ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                        using  pipe: %d", __FUNCTION__, layer, hnd, indexR );
+                if (!ov.queueBuffer(fd, offset, destR)) {
+                    ALOGE("%s: queueBuffer failed for display:%d",
+                            __FUNCTION__, mDpy);
+                    return false;
+                }
+            }
+        }
+        else{
+            MdpPipeInfoNonSplit& pipe_info =
             *(MdpPipeInfoNonSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
-        ovutils::eDest dest = pipe_info.index;
-        if(dest == ovutils::OV_INVALID) {
-            ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
-            return false;
-        }
-
-        if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
-            continue;
-        }
-
-        ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
-                 using  pipe: %d", __FUNCTION__, layer,
-                 hnd, dest );
-
-        int fd = hnd->fd;
-        uint32_t offset = hnd->offset;
-
-        Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
-        if(rot) {
-            if(!rot->queueBuffer(fd, offset))
+            ovutils::eDest dest = pipe_info.index;
+            if(dest == ovutils::OV_INVALID) {
+                ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
                 return false;
-            fd = rot->getDstMemId();
-            offset = rot->getDstOffset();
-        }
+            }
 
-        if (!ov.queueBuffer(fd, offset, dest)) {
-            ALOGE("%s: queueBuffer failed for display:%d ", __FUNCTION__, mDpy);
-            return false;
+            if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
+                continue;
+            }
+
+            ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                    using  pipe: %d", __FUNCTION__, layer,
+                    hnd, dest );
+
+            int fd = hnd->fd;
+            uint32_t offset = hnd->offset;
+
+            Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+            if(rot) {
+                if(!rot->queueBuffer(fd, offset))
+                    return false;
+                fd = rot->getDstMemId();
+                offset = rot->getDstOffset();
+            }
+
+            if (!ov.queueBuffer(fd, offset, dest)) {
+                ALOGE("%s: queueBuffer failed for display:%d ",
+                        __FUNCTION__, mDpy);
+                return false;
+            }
         }
 
         layerProp[i].mFlags &= ~HWC_MDPCOMP;
@@ -1491,6 +1677,23 @@
 
 //=============MDPCompSplit===================================================
 
+void MDPCompSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
+         hwc_display_contents_1_t* list){
+    //if 4kx2k yuv layer is totally present in either in left half
+    //or right half then try splitting the yuv layer to avoid decimation
+    int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
+    const int lSplit = getLeftSplit(ctx, mDpy);
+    for(int index = 0; index < n4k2kYuvCount; index++){
+        int n4k2kYuvIndex = ctx->listStats[mDpy].yuv4k2kIndices[index];
+        hwc_layer_1_t* layer = &list->hwLayers[n4k2kYuvIndex];
+        hwc_rect_t dst = layer->displayFrame;
+
+        if((dst.left > lSplit)||(dst.right < lSplit)){
+            mCurrentFrame.mdpCount += 1;
+        }
+    }
+}
+
 int MDPCompSplit::pipesNeeded(hwc_context_t *ctx,
         hwc_display_contents_1_t* list,
         int mixer) {
@@ -1563,6 +1766,12 @@
             hwc_layer_1_t* layer = &list->hwLayers[i];
             hwc_rect_t dst = layer->displayFrame;
             private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+                if((dst.left > lSplit)||(dst.right < lSplit)){
+                    pipesNeeded = pipesNeeded + 2;
+                    continue;
+                }
+            }
             if(isYuvBuffer(hnd)) {
                 if(dst.left < lSplit) {
                     pipesNeeded++;
@@ -1618,6 +1827,15 @@
 
         hwc_layer_1_t* layer = &list->hwLayers[index];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
+        hwc_rect_t dst = layer->displayFrame;
+        const int lSplit = getLeftSplit(ctx, mDpy);
+        if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+            if((dst.left > lSplit)||(dst.right < lSplit)){
+                if(allocSplitVGPipesfor4k2k(ctx, list, index)){
+                    continue;
+                }
+            }
+        }
         int mdpIndex = mCurrentFrame.layerToMDP[index];
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
         info.pipeInfo = new MdpPipeInfoSplit;
@@ -1642,6 +1860,27 @@
     return true;
 }
 
+int MDPCompSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        PipeLayerPair& PipeLayerPair) {
+    const int lSplit = getLeftSplit(ctx, mDpy);
+    hwc_rect_t dst = layer->displayFrame;
+    if((dst.left > lSplit)||(dst.right < lSplit)){
+        MdpYUVPipeInfo& mdp_info =
+                *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
+        eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+        eIsFg isFg = IS_FG_OFF;
+        eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+        eDest lDest = mdp_info.lIndex;
+        eDest rDest = mdp_info.rIndex;
+
+        return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
+                lDest, rDest, &PipeLayerPair.rot);
+    }
+    else{
+        return configure(ctx, layer, PipeLayerPair);
+    }
+}
+
 /*
  * Configures pipe(s) for MDP composition
  */
@@ -1704,48 +1943,88 @@
 
         int mdpIndex = mCurrentFrame.layerToMDP[i];
 
-        MdpPipeInfoSplit& pipe_info =
-            *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
-        Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+        if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit)
+        {
+            MdpYUVPipeInfo& pipe_info =
+                *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+            Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+            ovutils::eDest indexL = pipe_info.lIndex;
+            ovutils::eDest indexR = pipe_info.rIndex;
+            int fd = hnd->fd;
+            uint32_t offset = hnd->offset;
+            if(rot) {
+                rot->queueBuffer(fd, offset);
+                fd = rot->getDstMemId();
+                offset = rot->getDstOffset();
+            }
+            if(indexL != ovutils::OV_INVALID) {
+                ovutils::eDest destL = (ovutils::eDest)indexL;
+                ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                        using  pipe: %d", __FUNCTION__, layer, hnd, indexL );
+                if (!ov.queueBuffer(fd, offset, destL)) {
+                    ALOGE("%s: queueBuffer failed for display:%d",
+                            __FUNCTION__, mDpy);
+                    return false;
+                }
+            }
 
-        ovutils::eDest indexL = pipe_info.lIndex;
-        ovutils::eDest indexR = pipe_info.rIndex;
-
-        int fd = hnd->fd;
-        int offset = hnd->offset;
-
-        if(ctx->mAD->isModeOn()) {
-            if(ctx->mAD->draw(ctx, fd, offset)) {
-                fd = ctx->mAD->getDstFd(ctx);
-                offset = ctx->mAD->getDstOffset(ctx);
+            if(indexR != ovutils::OV_INVALID) {
+                ovutils::eDest destR = (ovutils::eDest)indexR;
+                ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                        using  pipe: %d", __FUNCTION__, layer, hnd, indexR );
+                if (!ov.queueBuffer(fd, offset, destR)) {
+                    ALOGE("%s: queueBuffer failed for display:%d",
+                            __FUNCTION__, mDpy);
+                    return false;
+                }
             }
         }
+        else{
+            MdpPipeInfoSplit& pipe_info =
+                *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+            Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
 
-        if(rot) {
-            rot->queueBuffer(fd, offset);
-            fd = rot->getDstMemId();
-            offset = rot->getDstOffset();
-        }
+            ovutils::eDest indexL = pipe_info.lIndex;
+            ovutils::eDest indexR = pipe_info.rIndex;
 
-        //************* play left mixer **********
-        if(indexL != ovutils::OV_INVALID) {
-            ovutils::eDest destL = (ovutils::eDest)indexL;
-            ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
-                     using  pipe: %d", __FUNCTION__, layer, hnd, indexL );
-            if (!ov.queueBuffer(fd, offset, destL)) {
-                ALOGE("%s: queueBuffer failed for left mixer", __FUNCTION__);
-                return false;
+            int fd = hnd->fd;
+            int offset = hnd->offset;
+
+            if(ctx->mAD->isModeOn()) {
+                if(ctx->mAD->draw(ctx, fd, offset)) {
+                    fd = ctx->mAD->getDstFd(ctx);
+                    offset = ctx->mAD->getDstOffset(ctx);
+                }
             }
-        }
 
-        //************* play right mixer **********
-        if(indexR != ovutils::OV_INVALID) {
-            ovutils::eDest destR = (ovutils::eDest)indexR;
-            ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
-                     using  pipe: %d", __FUNCTION__, layer, hnd, indexR );
-            if (!ov.queueBuffer(fd, offset, destR)) {
-                ALOGE("%s: queueBuffer failed for right mixer", __FUNCTION__);
-                return false;
+            if(rot) {
+                rot->queueBuffer(fd, offset);
+                fd = rot->getDstMemId();
+                offset = rot->getDstOffset();
+            }
+
+            //************* play left mixer **********
+            if(indexL != ovutils::OV_INVALID) {
+                ovutils::eDest destL = (ovutils::eDest)indexL;
+                ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                        using  pipe: %d", __FUNCTION__, layer, hnd, indexL );
+                if (!ov.queueBuffer(fd, offset, destL)) {
+                    ALOGE("%s: queueBuffer failed for left mixer",
+                            __FUNCTION__);
+                    return false;
+                }
+            }
+
+            //************* play right mixer **********
+            if(indexR != ovutils::OV_INVALID) {
+                ovutils::eDest destR = (ovutils::eDest)indexR;
+                ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                        using  pipe: %d", __FUNCTION__, layer, hnd, indexR );
+                if (!ov.queueBuffer(fd, offset, destR)) {
+                    ALOGE("%s: queueBuffer failed for right mixer",
+                            __FUNCTION__);
+                    return false;
+                }
             }
         }
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index adf74bb..7e646d7 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -70,6 +70,12 @@
         virtual ~MdpPipeInfo(){};
     };
 
+    struct MdpYUVPipeInfo : public MdpPipeInfo{
+        ovutils::eDest lIndex;
+        ovutils::eDest rIndex;
+        virtual ~MdpYUVPipeInfo(){};
+    };
+
     /* per layer data */
     struct PipeLayerPair {
         MdpPipeInfo *pipeInfo;
@@ -133,7 +139,12 @@
     /* Checks for pipes needed versus pipes available */
     virtual bool arePipesAvailable(hwc_context_t *ctx,
             hwc_display_contents_1_t* list) = 0;
-
+    /* increments mdpCount if 4k2k yuv layer split is enabled*/
+    virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list) = 0;
+    /* configures 4kx2k yuv layer*/
+    virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+            PipeLayerPair& PipeLayerPair) = 0;
     /* set/reset flags for MDPComp */
     void setMDPCompLayerFlags(hwc_context_t *ctx,
                               hwc_display_contents_1_t* list);
@@ -165,11 +176,11 @@
             bool secureOnly);
     /* checks for conditions where YUV layers cannot be bypassed */
     bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
-    /* calcs bytes read by MDP for a given frame */
-    uint32_t calcMDPBytesRead(hwc_context_t *ctx,
+    /* calcs bytes read by MDP in gigs for a given frame */
+    double calcMDPBytesRead(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
     /* checks if the required bandwidth exceeds a certain max */
-    bool bandwidthCheck(hwc_context_t *ctx, const uint32_t& size);
+    bool bandwidthCheck(hwc_context_t *ctx, const double& size);
     /* generates ROI based on the modified area of the frame */
     void generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     bool validateAndApplyROI(hwc_context_t *ctx, hwc_display_contents_1_t* list,
@@ -212,13 +223,17 @@
     static bool sIdleFallBack;
     static int sMaxPipesPerMixer;
     //Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
-    static float sMaxBw;
+    static double sMaxBw;
     //Tracks composition bandwidth claimed. Represented as the total
     //w*h*bpp*fps (gigabytes-per-second) going to MDP mixers.
     static double sBwClaimed;
     static IdleInvalidator *idleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
+    //Enable 4kx2k yuv layer split
+    static bool sEnable4k2kYUVSplit;
+    bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list, int index);
 };
 
 class MDPCompNonSplit : public MDPComp {
@@ -248,6 +263,14 @@
     /* Checks for video pipes needed versus pipes available */
     virtual bool areVGPipesAvailable(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
+
+    /* increments mdpCount if 4k2k yuv layer split is enabled*/
+    virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+             hwc_display_contents_1_t* list);
+
+    /* configures 4kx2k yuv layer to 2 VG pipes*/
+    virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+            PipeLayerPair& PipeLayerPair);
 };
 
 class MDPCompSplit : public MDPComp {
@@ -281,6 +304,14 @@
     virtual bool areVGPipesAvailable(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
 
+    /* increments mdpCount if 4k2k yuv layer split is enabled*/
+    virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+
+    /* configures 4kx2k yuv layer*/
+    virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+            PipeLayerPair& PipeLayerPair);
+
     int pipesNeeded(hwc_context_t *ctx, hwc_display_contents_1_t* list,
             int mixer);
 };
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index a17565b..3b98788 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -51,57 +51,28 @@
     ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
 }
 
-status_t QClient::notifyCallback(uint32_t msg, uint32_t value) {
-
-    if (msg > IQService::VPU_COMMAND_LIST_START &&
-        msg < IQService::VPU_COMMAND_LIST_END) {
-        return vpuCommand(msg, value);
-    }
-
-    switch(msg) {
-        case IQService::SECURING:
-            securing(value);
-            break;
-        case IQService::UNSECURING:
-            unsecuring(value);
-            break;
-        case IQService::SCREEN_REFRESH:
-            return screenRefresh();
-            break;
-        case IQService::EXTERNAL_ORIENTATION:
-            setExtOrientation(value);
-            break;
-        case IQService::BUFFER_MIRRORMODE:
-            setBufferMirrorMode(value);
-            break;
-        default:
-            return NO_ERROR;
-    }
-    return NO_ERROR;
-}
-
-void QClient::securing(uint32_t startEnd) {
-    Locker::Autolock _sl(mHwcContext->mDrawLock);
+static void securing(hwc_context_t *ctx, uint32_t startEnd) {
+    Locker::Autolock _sl(ctx->mDrawLock);
     //The only way to make this class in this process subscribe to media
     //player's death.
     IMediaDeathNotifier::getMediaPlayerService();
 
-    mHwcContext->mSecuring = startEnd;
+    ctx->mSecuring = startEnd;
     //We're done securing
     if(startEnd == IQService::END)
-        mHwcContext->mSecureMode = true;
-    if(mHwcContext->proc)
-        mHwcContext->proc->invalidate(mHwcContext->proc);
+        ctx->mSecureMode = true;
+    if(ctx->proc)
+        ctx->proc->invalidate(ctx->proc);
 }
 
-void QClient::unsecuring(uint32_t startEnd) {
-    Locker::Autolock _sl(mHwcContext->mDrawLock);
-    mHwcContext->mSecuring = startEnd;
+static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    ctx->mSecuring = startEnd;
     //We're done unsecuring
     if(startEnd == IQService::END)
-        mHwcContext->mSecureMode = false;
-    if(mHwcContext->proc)
-        mHwcContext->proc->invalidate(mHwcContext->proc);
+        ctx->mSecureMode = false;
+    if(ctx->proc)
+        ctx->proc->invalidate(ctx->proc);
 }
 
 void QClient::MPDeathNotifier::died() {
@@ -113,33 +84,68 @@
         mHwcContext->proc->invalidate(mHwcContext->proc);
 }
 
-android::status_t QClient::screenRefresh() {
+static android::status_t screenRefresh(hwc_context_t *ctx) {
     status_t result = NO_INIT;
 #ifdef QCOM_BSP
-    if(mHwcContext->proc) {
-        mHwcContext->proc->invalidate(mHwcContext->proc);
+    if(ctx->proc) {
+        ctx->proc->invalidate(ctx->proc);
         result = NO_ERROR;
     }
 #endif
     return result;
 }
 
-android::status_t QClient::vpuCommand(uint32_t command, uint32_t setting) {
+static android::status_t vpuCommand(hwc_context_t *ctx,
+        uint32_t command,
+        const Parcel* inParcel,
+        Parcel* outParcel) {
     status_t result = NO_INIT;
 #ifdef QCOM_BSP
 #ifdef VPU_TARGET
-    result = mHwcContext->mVPUClient->processCommand(command, setting);
+    result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
 #endif
 #endif
     return result;
 }
 
-void QClient::setExtOrientation(uint32_t orientation) {
-    mHwcContext->mExtOrientation = orientation;
+static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
+    ctx->mExtOrientation = orientation;
 }
 
-void QClient::setBufferMirrorMode(uint32_t enable) {
-    mHwcContext->mBufferMirrorMode = enable;
+static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
+    ctx->mBufferMirrorMode = enable;
 }
 
+status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
+        Parcel* outParcel) {
+
+    if (command > IQService::VPU_COMMAND_LIST_START &&
+        command < IQService::VPU_COMMAND_LIST_END) {
+        return vpuCommand(mHwcContext, command, inParcel, outParcel);
+    }
+
+    switch(command) {
+        case IQService::SECURING:
+            securing(mHwcContext, inParcel->readInt32());
+            break;
+        case IQService::UNSECURING:
+            unsecuring(mHwcContext, inParcel->readInt32());
+            break;
+        case IQService::SCREEN_REFRESH:
+            return screenRefresh(mHwcContext);
+            break;
+        case IQService::EXTERNAL_ORIENTATION:
+            setExtOrientation(mHwcContext, inParcel->readInt32());
+            break;
+        case IQService::BUFFER_MIRRORMODE:
+            setBufferMirrorMode(mHwcContext, inParcel->readInt32());
+            break;
+        default:
+            return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+
+
 }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index fa1d6b0..d955377 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -39,6 +39,7 @@
 
 struct hwc_context_t;
 
+class Params;
 namespace qClient {
 // ----------------------------------------------------------------------------
 
@@ -46,7 +47,9 @@
 public:
     QClient(hwc_context_t *ctx);
     virtual ~QClient();
-    virtual android::status_t notifyCallback(uint32_t msg, uint32_t value);
+    virtual android::status_t notifyCallback(uint32_t command,
+            const android::Parcel* inParcel,
+            android::Parcel* outParcel);
 
 private:
     //Notifies of Media Player death
@@ -57,13 +60,6 @@
         hwc_context_t *mHwcContext;
     };
 
-    void securing(uint32_t startEnd);
-    void unsecuring(uint32_t startEnd);
-    android::status_t screenRefresh();
-    void setExtOrientation(uint32_t orientation);
-    void setBufferMirrorMode(uint32_t enable);
-    android::status_t vpuCommand(uint32_t command, uint32_t setting);
-
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
 };
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 977cf0e..50111d1 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -743,6 +743,7 @@
     ctx->listStats[dpy].roi = ovutils::Dim(0, 0,
                       (int)ctx->dpyAttr[dpy].xres, (int)ctx->dpyAttr[dpy].yres);
     ctx->listStats[dpy].secureUI = false;
+    ctx->listStats[dpy].yuv4k2kCount = 0;
 
     trimList(ctx, list, dpy);
     optimizeLayerRects(ctx, list, dpy);
@@ -765,6 +766,7 @@
 
         //reset yuv indices
         ctx->listStats[dpy].yuvIndices[i] = -1;
+        ctx->listStats[dpy].yuv4k2kIndices[i] = -1;
 
         if (isSecureBuffer(hnd)) {
             ctx->listStats[dpy].isSecurePresent = true;
@@ -779,6 +781,12 @@
             ctx->listStats[dpy].yuvIndices[yuvCount] = i;
             yuvCount++;
 
+            if(UNLIKELY(is4kx2kYuvBuffer(hnd))){
+                int& yuv4k2kCount = ctx->listStats[dpy].yuv4k2kCount;
+                ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = i;
+                yuv4k2kCount++;
+            }
+
             if((layer->transform & HWC_TRANSFORM_ROT_90) &&
                     canUseRotator(ctx, dpy)) {
                 if( (dpy == HWC_DISPLAY_PRIMARY) &&
@@ -1366,6 +1374,42 @@
     return 0;
 }
 
+int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
+        eIsFg& isFg, const eDest& dest) {
+
+    hwc_rect_t dst = layer->displayFrame;
+    trimLayer(ctx, dpy, 0, dst, dst);
+
+    int w = ctx->dpyAttr[dpy].xres;
+    int h = ctx->dpyAttr[dpy].yres;
+    int dst_w = dst.right - dst.left;
+    int dst_h = dst.bottom - dst.top;
+    uint32_t color = layer->transform;
+    Whf whf(w, h, getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888), 0);
+
+    if (layer->blending == HWC_BLENDING_PREMULT)
+        ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_BLEND_FG_PREMULT);
+
+    PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(0),
+                  layer->planeAlpha,
+                  (ovutils::eBlending) getBlending(layer->blending));
+
+    // Configure MDP pipe for Color layer
+    Dim pos(dst.left, dst.top, dst_w, dst_h);
+    ctx->mOverlay->setSource(parg, dest);
+    ctx->mOverlay->setColor(color, dest);
+    ctx->mOverlay->setTransform(0, dest);
+    ctx->mOverlay->setCrop(pos, dest);
+    ctx->mOverlay->setPosition(pos, dest);
+
+    if (!ctx->mOverlay->commit(dest)) {
+        ALOGE("%s: Configure color layer failed!", __FUNCTION__);
+        return -1;
+    }
+    return 0;
+}
+
 void updateSource(eTransform& orient, Whf& whf,
         hwc_rect_t& crop) {
     Dim srcCrop(crop.left, crop.top,
@@ -1396,7 +1440,12 @@
         eIsFg& isFg, const eDest& dest, Rotator **rot) {
 
     private_handle_t *hnd = (private_handle_t *)layer->handle;
+
     if(!hnd) {
+        if (layer->flags & HWC_COLOR_FILL) {
+            // Configure Color layer
+            return configColorLayer(ctx, layer, dpy, mdpFlags, z, isFg, dest);
+        }
         ALOGE("%s: layer handle is NULL", __FUNCTION__);
         return -1;
     }
@@ -1681,6 +1730,129 @@
     return 0;
 }
 
+int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+        eIsFg& isFg, const eDest& lDest, const eDest& rDest,
+        Rotator **rot) {
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    if(!hnd) {
+        ALOGE("%s: layer handle is NULL", __FUNCTION__);
+        return -1;
+    }
+
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+    int hw_w = ctx->dpyAttr[dpy].xres;
+    int hw_h = ctx->dpyAttr[dpy].yres;
+    hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);;
+    hwc_rect_t dst = layer->displayFrame;
+    int transform = layer->transform;
+    eTransform orient = static_cast<eTransform>(transform);
+    const int downscale = 0;
+    int rotFlags = ROT_FLAGS_NONE;
+    //Splitting only YUV layer on primary panel needs different zorders
+    //for both layers as both the layers are configured to single mixer
+    eZorder lz = z;
+    eZorder rz = (eZorder)(z + 1);
+
+    Whf whf(getWidth(hnd), getHeight(hnd),
+            getMdpFormat(hnd->format), hnd->size);
+
+    setMdpFlags(layer, mdpFlagsL, 0, transform);
+    trimLayer(ctx, dpy, transform, crop, dst);
+
+    if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
+        (*rot) = ctx->mRotMgr->getNext();
+        if((*rot) == NULL) return -1;
+        if(!dpy)
+            BwcPM::setBwc(ctx, crop, dst, transform, mdpFlagsL);
+        //Configure rotator for pre-rotation
+        if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+            ALOGE("%s: configRotator failed!", __FUNCTION__);
+            ctx->mOverlay->clear(dpy);
+            return -1;
+        }
+        ctx->mLayerRotMap[dpy]->add(layer, *rot);
+        whf.format = (*rot)->getDstFormat();
+        updateSource(orient, whf, crop);
+        rotFlags |= ROT_PREROTATED;
+    }
+
+    eMdpFlags mdpFlagsR = mdpFlagsL;
+    int lSplit = dst.left + (dst.right - dst.left)/2;
+
+    hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0};
+    hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0};
+
+    if(lDest != OV_INVALID) {
+        tmp_cropL = crop;
+        tmp_dstL = dst;
+        hwc_rect_t scissor = {dst.left, dst.top, lSplit, dst.bottom };
+        qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
+    }
+    if(rDest != OV_INVALID) {
+        tmp_cropR = crop;
+        tmp_dstR = dst;
+        hwc_rect_t scissor = {lSplit, dst.top, dst.right, dst.bottom };
+        qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
+    }
+
+    sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd);
+
+    //When buffer is H-flipped, contents of mixer config also needs to swapped
+    //Not needed if the layer is confined to one half of the screen.
+    //If rotator has been used then it has also done the flips, so ignore them.
+    if((orient & OVERLAY_TRANSFORM_FLIP_H) && lDest != OV_INVALID
+            && rDest != OV_INVALID && (*rot) == NULL) {
+        hwc_rect_t new_cropR;
+        new_cropR.left = tmp_cropL.left;
+        new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left);
+
+        hwc_rect_t new_cropL;
+        new_cropL.left  = new_cropR.right;
+        new_cropL.right = tmp_cropR.right;
+
+        tmp_cropL.left =  new_cropL.left;
+        tmp_cropL.right =  new_cropL.right;
+
+        tmp_cropR.left = new_cropR.left;
+        tmp_cropR.right =  new_cropR.right;
+
+    }
+
+    //For the mdp, since either we are pre-rotating or MDP does flips
+    orient = OVERLAY_TRANSFORM_0;
+    transform = 0;
+
+    //configure left half
+    if(lDest != OV_INVALID) {
+        PipeArgs pargL(mdpFlagsL, whf, lz, isFg,
+                static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+                (ovutils::eBlending) getBlending(layer->blending));
+
+        if(configMdp(ctx->mOverlay, pargL, orient,
+                    tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
+            ALOGE("%s: commit failed for left half config", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    //configure right half
+    if(rDest != OV_INVALID) {
+        PipeArgs pargR(mdpFlagsR, whf, rz, isFg,
+                static_cast<eRotFlags>(rotFlags),
+                layer->planeAlpha,
+                (ovutils::eBlending) getBlending(layer->blending));
+        if(configMdp(ctx->mOverlay, pargR, orient,
+                    tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
+            ALOGE("%s: commit failed for right half config", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
 bool canUseRotator(hwc_context_t *ctx, int dpy) {
     if(qdutils::MDPVersion::getInstance().is8x26() &&
             ctx->mVirtualDisplay->isConnected() &&
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 66a02d6..29b38fc 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -99,6 +99,8 @@
     int extOnlyLayerIndex;
     bool needsAlphaScale;
     bool preMultipliedAlpha;
+    int yuv4k2kIndices[MAX_NUM_APP_LAYERS];
+    int yuv4k2kCount;
     // Notifies hwcomposer about the start and end of animation
     // This will be set to true during animation, otherwise false.
     bool isDisplayAnimating;
@@ -268,6 +270,10 @@
         const hwc_rect_t& pos, const MetaData_t *metadata,
         const ovutils::eDest& dest);
 
+int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+        ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+        ovutils::eIsFg& isFg, const ovutils::eDest& dest);
+
 void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
         hwc_rect_t& crop);
 
@@ -283,6 +289,13 @@
         ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
         const ovutils::eDest& rDest, overlay::Rotator **rot);
 
+//Routine to split and configure high resolution YUV layer (> 2048 width)
+int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        const int& dpy,
+        ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+        ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
+        const ovutils::eDest& rDest, overlay::Rotator **rot);
+
 //On certain targets DMA pipes are used for rotation and they won't be available
 //for line operations. On a per-target basis we can restrict certain use cases
 //from using rotator, since we know before-hand that such scenarios can lead to
@@ -305,6 +318,12 @@
     return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
 }
 
+// Returns true if the buffer is yuv
+static inline bool is4kx2kYuvBuffer(const private_handle_t* hnd) {
+    return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) &&
+            (hnd->width > 2048));
+}
+
 // Returns true if the buffer is secure
 static inline bool isSecureBuffer(const private_handle_t* hnd) {
     return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags));
@@ -459,7 +478,8 @@
 }
 
 static inline bool has90Transform(hwc_layer_1_t *layer) {
-    return (layer->transform & HWC_TRANSFORM_ROT_90);
+    return ((layer->transform & HWC_TRANSFORM_ROT_90) &&
+            !(layer->flags & HWC_COLOR_FILL));
 }
 
 inline bool isSecurePresent(hwc_context_t *ctx, int dpy) {
diff --git a/libhwcomposer/hwc_vpuclient.cpp b/libhwcomposer/hwc_vpuclient.cpp
index bdfeae5..23c6841 100644
--- a/libhwcomposer/hwc_vpuclient.cpp
+++ b/libhwcomposer/hwc_vpuclient.cpp
@@ -31,9 +31,11 @@
 #include "hwc_vpuclient.h"
 #include "hwc_utils.h"
 #include <vpu/vpu.h>
+#include <binder/Parcel.h>
 
 
 using namespace vpu;
+using namespace android;
 namespace qhwc {
 
 VPUClient::VPUClient()
@@ -78,11 +80,14 @@
     return err;
 }
 
-int VPUClient::processCommand(uint32_t command, uint32_t setting)
+int VPUClient::processCommand(uint32_t command,
+        const Parcel* inParcel, Parcel* outParcel)
 {
     if(!mVPU)
         return 0;
-    return mVPU->processCommand(command, setting);
+    //XXX: Enable when VPU enables it
+    //return mVPU->processCommand(command, inParcel, outParcel);
+    return 0;
 }
 
 }; // namespace qhwc
diff --git a/libhwcomposer/hwc_vpuclient.h b/libhwcomposer/hwc_vpuclient.h
index 8cc7137..9985517 100644
--- a/libhwcomposer/hwc_vpuclient.h
+++ b/libhwcomposer/hwc_vpuclient.h
@@ -39,6 +39,9 @@
 namespace vpu {
 class VPU;
 };
+namespace android {
+class Parcel;
+};
 
 namespace qhwc {
 
@@ -52,7 +55,8 @@
 
     int draw(hwc_context_t *ctx, hwc_display_contents_1_t* list);
 
-    int processCommand(uint32_t command, uint32_t setting);
+    int processCommand(uint32_t command,
+            const android::Parcel* inParcel, android::Parcel* outParcel);
 
 private:
     vpu::VPU *mVPU;
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index d9baadd..e6da3c5 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -81,7 +81,8 @@
 
 void Overlay::configDone() {
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
-        if(PipeBook::isNotUsed(i)) {
+        if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) ||
+                    isSessionEnded((eDest)i)) {
             //Forces UNSET on pipes, flushes rotator memory and session, closes
             //fds
             if(mPipeBook[i].valid()) {
@@ -107,6 +108,27 @@
 #endif
 }
 
+int Overlay::getPipeId(utils::eDest dest) {
+    return mPipeBook[(int)dest].mPipe->getPipeId();
+}
+
+eDest Overlay::getDest(int pipeid) {
+    eDest dest = OV_INVALID;
+    // finding the dest corresponding to the given pipe
+    for(int i=0; i < PipeBook::NUM_PIPES; ++i) {
+        if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) {
+            return (eDest)i;
+        }
+    }
+    return dest;
+}
+
+eDest Overlay::reservePipe(int pipeid) {
+    eDest dest = getDest(pipeid);
+    PipeBook::setAllocation((int)dest);
+    return dest;
+}
+
 eDest Overlay::nextPipe(eMdpPipeType type, int dpy, int mixer) {
     eDest dest = OV_INVALID;
 
@@ -134,6 +156,7 @@
         mPipeBook[index].mMixer = mixer;
         if(not mPipeBook[index].valid()) {
             mPipeBook[index].mPipe = new GenericPipe(dpy);
+            mPipeBook[index].mSession = PipeBook::NONE;
             char str[32];
             snprintf(str, 32, "Set=%s dpy=%d mix=%d; ",
                      PipeBook::getDestStr(dest), dpy, mixer);
@@ -149,6 +172,13 @@
     return dest;
 }
 
+void Overlay::endAllSessions() {
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
+            mPipeBook[i].mSession = PipeBook::END;
+    }
+}
+
 bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
         if(type == PipeBook::getPipeType((eDest)i) &&
@@ -203,6 +233,13 @@
     mPipeBook[index].mPipe->setCrop(d);
 }
 
+void Overlay::setColor(const uint32_t color,
+        utils::eDest dest) {
+    int index = (int)dest;
+    validate(index);
+    mPipeBook[index].mPipe->setColor(color);
+}
+
 void Overlay::setPosition(const utils::Dim& d,
         utils::eDest dest) {
     int index = (int)dest;
@@ -456,6 +493,7 @@
     }
     mDisplay = DPY_UNUSED;
     mMixer = MIXER_UNUSED;
+    mSession = NONE;
 }
 
 Overlay* Overlay::sInstance = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 4df921f..48825ea 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -77,15 +77,33 @@
      * asisgned to a mixer within a display it cannot be reused for another
      * mixer without being UNSET once*/
     utils::eDest nextPipe(utils::eMdpPipeType, int dpy, int mixer);
+    /* Returns the eDest corresponding to an already allocated pipeid.
+     * Useful for the reservation case, when libvpu reserves the pipe at its
+     * end, and expect the overlay to allocate a given pipe for a layer.
+     */
+    utils::eDest reservePipe(int pipeid);
+    /* getting dest for the given pipeid */
+    utils::eDest getDest(int pipeid);
+    /* getting overlay.pipeid for the given dest */
+    int getPipeId(utils::eDest dest);
 
     void setSource(const utils::PipeArgs args, utils::eDest dest);
     void setCrop(const utils::Dim& d, utils::eDest dest);
+    void setColor(const uint32_t color, utils::eDest dest);
     void setTransform(const int orientation, utils::eDest dest);
     void setPosition(const utils::Dim& dim, utils::eDest dest);
     void setVisualParams(const MetaData_t& data, utils::eDest dest);
     bool commit(utils::eDest dest);
     bool queueBuffer(int fd, uint32_t offset, utils::eDest dest);
 
+    /* pipe reservation session is running */
+    bool sessionInProgress(utils::eDest dest);
+    /* pipe reservation session has ended*/
+    bool isSessionEnded(utils::eDest dest);
+    /* start session for the pipe reservation */
+    void startSession(utils::eDest dest);
+    /* end all started sesisons */
+    void endAllSessions();
     /* Returns available ("unallocated") pipes for a display's mixer */
     int availablePipes(int dpy, int mixer);
     /* Returns available ("unallocated") pipes for a display */
@@ -162,7 +180,13 @@
 
         static int NUM_PIPES;
         static utils::eMdpPipeType pipeTypeLUT[utils::OV_MAX];
-
+        /* Session for reserved pipes */
+        enum Session {
+            NONE,
+            START,
+            END
+        };
+        Session mSession;
 
     private:
         //usage tracks if a successful commit happened. So a pipe could be
@@ -321,6 +345,18 @@
     return pipeTypeLUT[(int)dest];
 }
 
+inline void Overlay::startSession(utils::eDest dest) {
+    mPipeBook[(int)dest].mSession = PipeBook::START;
+}
+
+inline bool Overlay::sessionInProgress(utils::eDest dest) {
+    return (mPipeBook[(int)dest].mSession == PipeBook::START);
+}
+
+inline bool Overlay::isSessionEnded(utils::eDest dest) {
+    return (mPipeBook[(int)dest].mSession == PipeBook::END);
+}
+
 inline const char* Overlay::PipeBook::getDestStr(utils::eDest dest) {
     switch(getPipeType(dest)) {
         case utils::OV_MDP_PIPE_RGB: return "RGB";
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 6746792..18ef5e6 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -61,6 +61,8 @@
     void setSource(const utils::PipeArgs& args);
     /* set crop info and pass it down to mdp */
     void setCrop(const utils::Dim& d);
+    /* set color for mdp pipe */
+    void setColor(const uint32_t color);
     /* set orientation */
     void setTransform(const utils::eTransform& p);
     /* set mdp position using dim */
@@ -174,6 +176,11 @@
     mMdp.setCrop(d);
 }
 
+inline void Ctrl::setColor(const uint32_t color)
+{
+    mMdp.setColor(color);
+}
+
 inline bool Ctrl::setVisualParams(const MetaData_t &metadata)
 {
     if (!mMdp.setVisualParams(metadata)) {
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index b4058bd..fbb173e 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -122,6 +122,10 @@
     setSrcRectDim(d);
 }
 
+void MdpCtrl::setColor(const uint32_t color) {
+    mOVInfo.bg_color = color;
+}
+
 void MdpCtrl::setPosition(const overlay::utils::Dim& d) {
     setDstRectDim(d);
 }
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index fe4ad69..6dd3976 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -57,6 +57,8 @@
      * Dim - ROI dimensions.
      */
     void setCrop(const utils::Dim& d);
+    /* set color for mdp pipe */
+    void setColor(const uint32_t color);
     void setTransform(const utils::eTransform& orient);
     /* given a dim and w/h, set overlay dim */
     void setPosition(const utils::Dim& dim);
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 06e8257..c03378b 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -84,6 +84,10 @@
     mCtrlData.ctrl.setCrop(d);
 }
 
+void GenericPipe::setColor(const uint32_t color) {
+    mCtrlData.ctrl.setColor(color);
+}
+
 void GenericPipe::setTransform(const utils::eTransform& orient) {
     mCtrlData.ctrl.setTransform(orient);
 }
@@ -167,4 +171,8 @@
     mCtrlData.ctrl.forceSet();
 }
 
+int GenericPipe::getPipeId() {
+    return mCtrlData.ctrl.getPipeId();
+}
+
 } //namespace overlay
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 2472f4e..5c963bc 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -48,6 +48,8 @@
     void setSource(const utils::PipeArgs& args);
     /* set crop a.k.a the region of interest */
     void setCrop(const utils::Dim& d);
+    /* set color for mdp pipe */
+    void setColor(const uint32_t color);
     /* set orientation*/
     void setTransform(const utils::eTransform& param);
     /* set mdp posision using dim */
@@ -77,6 +79,7 @@
      * even if they haven't changed
      */
     void forceSet();
+    int getPipeId();
 
 private:
     /* set Closed pipe */
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 0809fd0..e12b319 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -48,6 +48,8 @@
     mMDPUpscale = 0;
     mMDPDownscale = 0;
     mPanelType = NO_PANEL;
+    mLowBw = 0;
+    mHighBw = 0;
 
     if(!updatePanelInfo()) {
         ALOGE("Unable to read Primary Panel Information");
@@ -168,8 +170,13 @@
                 else if(!strncmp(tokens[0], "max_upscale_ratio",
                                 strlen("max_upscale_ratio"))) {
                     mMDPUpscale = atoi(tokens[1]);
-                }
-                else if(!strncmp(tokens[0], "features", strlen("features"))) {
+                } else if(!strncmp(tokens[0], "max_bandwidth_low",
+                        strlen("max_bandwidth_low"))) {
+                    mLowBw = atol(tokens[1]);
+                } else if(!strncmp(tokens[0], "max_bandwidth_high",
+                        strlen("max_bandwidth_high"))) {
+                    mHighBw = atol(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;
@@ -191,6 +198,9 @@
                     mRGBPipes, mVGPipes);
     ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d",
                      __FUNCTION__,  mDMAPipes, mMDPDownscale, mFeatures);
+    ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__,  mLowBw,
+            mHighBw);
+
     return true;
 }
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 1e1e35e..fb7920e 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -113,6 +113,8 @@
     bool is8x92();
     int getLeftSplit() { return mSplit.left(); }
     int getRightSplit() { return mSplit.right(); }
+    unsigned long getLowBw() { return mLowBw; }
+    unsigned long getHighBw() { return mHighBw; }
 private:
     bool updateSysFsInfo();
     bool updatePanelInfo();
@@ -131,6 +133,8 @@
     uint32_t mMDPDownscale;
     uint32_t mMDPUpscale;
     Split mSplit;
+    unsigned long mLowBw; //kbps
+    unsigned long mHighBw; //kbps
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER
diff --git a/libqservice/IQClient.cpp b/libqservice/IQClient.cpp
index 30fbb64..a6251c8 100644
--- a/libqservice/IQClient.cpp
+++ b/libqservice/IQClient.cpp
@@ -28,6 +28,9 @@
 using namespace android;
 
 // ---------------------------------------------------------------------------
+// XXX: Since qservice currently runs as part of hwc instead of a standalone
+// process, the implementation below is overridden and the notifyCallback in
+// hwc_qclient is directly called.
 
 namespace qClient {
 
@@ -41,13 +44,17 @@
     BpQClient(const sp<IBinder>& impl)
         : BpInterface<IQClient>(impl) {}
 
-    virtual status_t notifyCallback(uint32_t msg, uint32_t value) {
-        Parcel data, reply;
+    virtual status_t notifyCallback(uint32_t command,
+            const Parcel* inParcel,
+            Parcel* outParcel) {
+        Parcel data;
+        Parcel *reply = outParcel;
         data.writeInterfaceToken(IQClient::getInterfaceDescriptor());
-        data.writeInt32(msg);
-        data.writeInt32(value);
-        remote()->transact(NOTIFY_CALLBACK, data, &reply);
-        status_t result = reply.readInt32();
+        data.writeInt32(command);
+        if (inParcel->dataAvail())
+            data.appendFrom(inParcel, inParcel->dataPosition(),
+                    inParcel->dataAvail());
+        status_t result = remote()->transact(NOTIFY_CALLBACK, data, reply);
         return result;
     }
 };
@@ -55,21 +62,21 @@
 IMPLEMENT_META_INTERFACE(QClient, "android.display.IQClient");
 
 // ----------------------------------------------------------------------
-
+//Stub implementation - nothing needed here
 status_t BnQClient::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch(code) {
         case NOTIFY_CALLBACK: {
             CHECK_INTERFACE(IQClient, data, reply);
-            uint32_t msg = data.readInt32();
-            uint32_t value = data.readInt32();
-            notifyCallback(msg, value);
+            uint32_t command = data.readInt32();
+            notifyCallback(command, &data, reply);
             return NO_ERROR;
         } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
+
 }
 
 }; // namespace qClient
diff --git a/libqservice/IQClient.h b/libqservice/IQClient.h
index a28f826..7d816d2 100644
--- a/libqservice/IQClient.h
+++ b/libqservice/IQClient.h
@@ -33,7 +33,9 @@
 {
 public:
     DECLARE_META_INTERFACE(QClient);
-    virtual android::status_t notifyCallback(uint32_t msg, uint32_t value) = 0;
+    virtual android::status_t notifyCallback(uint32_t command,
+            const android::Parcel* inParcel,
+            android::Parcel* outParcel) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index 33f79c6..d2180bb 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -27,9 +27,10 @@
 #include <binder/IPCThreadState.h>
 #include <utils/Errors.h>
 #include <private/android_filesystem_config.h>
-
 #include <IQService.h>
 
+#define QSERVICE_DEBUG 0
+
 using namespace android;
 using namespace qClient;
 
@@ -43,56 +44,25 @@
     BpQService(const sp<IBinder>& impl)
         : BpInterface<IQService>(impl) {}
 
-    virtual void securing(uint32_t startEnd) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
-        data.writeInt32(startEnd);
-        remote()->transact(SECURING, data, &reply);
-    }
-
-    virtual void unsecuring(uint32_t startEnd) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
-        data.writeInt32(startEnd);
-        remote()->transact(UNSECURING, data, &reply);
-    }
-
     virtual void connect(const sp<IQClient>& client) {
+        ALOGD_IF(QSERVICE_DEBUG, "%s: connect client", __FUNCTION__);
         Parcel data, reply;
         data.writeInterfaceToken(IQService::getInterfaceDescriptor());
         data.writeStrongBinder(client->asBinder());
         remote()->transact(CONNECT, data, &reply);
     }
 
-    virtual status_t screenRefresh() {
-        Parcel data, reply;
+    virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel,
+            Parcel* outParcel) {
+        ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel);
+        status_t err = android::FAILED_TRANSACTION;
+        Parcel data;
+        Parcel *reply = outParcel;
         data.writeInterfaceToken(IQService::getInterfaceDescriptor());
-        remote()->transact(SCREEN_REFRESH, data, &reply);
-        status_t result = reply.readInt32();
-        return result;
-    }
-
-    virtual void setExtOrientation(uint32_t orientation) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
-        data.writeInt32(orientation);
-        remote()->transact(EXTERNAL_ORIENTATION, data, &reply);
-    }
-
-    virtual void setBufferMirrorMode(uint32_t enable) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
-        data.writeInt32(enable);
-        remote()->transact(BUFFER_MIRRORMODE, data, &reply);
-    }
-
-    virtual status_t vpuCommand(uint32_t command, uint32_t setting) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
-        data.writeInt32(setting);
-        remote()->transact(command, data, &reply);
-        status_t result = reply.readInt32();
-        return result;
+        if (inParcel && inParcel->dataSize() > 0)
+            data.appendFrom(inParcel, 0, inParcel->dataSize());
+        err = remote()->transact(command, data, reply);
+        return err;
     }
 };
 
@@ -105,7 +75,8 @@
 status_t BnQService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
-    // IPC should be from mediaserver only
+    ALOGD_IF(QSERVICE_DEBUG, "%s: code: %d", __FUNCTION__, code);
+    // IPC should be from certain processes only
     IPCThreadState* ipc = IPCThreadState::self();
     const int callerPid = ipc->getCallingPid();
     const int callerUid = ipc->getCallingUid();
@@ -114,94 +85,35 @@
 
     getProcName(callerPid, callingProcName, MAX_BUF_SIZE);
 
-    const bool permission = (callerUid == AID_MEDIA);
+    const bool permission = (callerUid == AID_MEDIA ||
+            callerUid == AID_GRAPHICS ||
+            callerUid == AID_ROOT ||
+            callerUid == AID_SYSTEM);
 
-    if (code > VPU_COMMAND_LIST_START && code < VPU_COMMAND_LIST_END) {
-        if(callerUid != AID_SYSTEM && callerUid != AID_ROOT) {
-            ALOGE("display.qservice VPU command access denied: \
-                  pid=%d uid=%d process=%s",callerPid,
+    if (code == CONNECT) {
+        CHECK_INTERFACE(IQService, data, reply);
+        if(callerUid != AID_GRAPHICS) {
+            ALOGE("display.qservice CONNECT access denied: \
+                    pid=%d uid=%d process=%s",
+                    callerPid, callerUid, callingProcName);
+            return PERMISSION_DENIED;
+        }
+        sp<IQClient> client =
+                interface_cast<IQClient>(data.readStrongBinder());
+        connect(client);
+        return NO_ERROR;
+    } else if (code > COMMAND_LIST_START && code < COMMAND_LIST_END) {
+        if(!permission) {
+            ALOGE("display.qservice access denied: command=%d\
+                  pid=%d uid=%d process=%s", code, callerPid,
                   callerUid, callingProcName);
             return PERMISSION_DENIED;
         }
         CHECK_INTERFACE(IQService, data, reply);
-        int32_t setting = data.readInt32();
-        return vpuCommand(code, setting);
-    }
-
-    switch(code) {
-        case SECURING: {
-            if(!permission) {
-                ALOGE("display.qservice SECURING access denied: \
-                      pid=%d uid=%d process=%s",
-                      callerPid, callerUid, callingProcName);
-                return PERMISSION_DENIED;
-            }
-            CHECK_INTERFACE(IQService, data, reply);
-            uint32_t startEnd = data.readInt32();
-            securing(startEnd);
-            return NO_ERROR;
-        } break;
-        case UNSECURING: {
-            if(!permission) {
-                ALOGE("display.qservice UNSECURING access denied: \
-                      pid=%d uid=%d process=%s",
-                      callerPid, callerUid, callingProcName);
-                return PERMISSION_DENIED;
-            }
-            CHECK_INTERFACE(IQService, data, reply);
-            uint32_t startEnd = data.readInt32();
-            unsecuring(startEnd);
-            return NO_ERROR;
-        } break;
-        case CONNECT: {
-            CHECK_INTERFACE(IQService, data, reply);
-            if(callerUid != AID_GRAPHICS) {
-                ALOGE("display.qservice CONNECT access denied: \
-                      pid=%d uid=%d process=%s",
-                      callerPid, callerUid, callingProcName);
-                return PERMISSION_DENIED;
-            }
-            sp<IQClient> client =
-                interface_cast<IQClient>(data.readStrongBinder());
-            connect(client);
-            return NO_ERROR;
-        } break;
-        case SCREEN_REFRESH: {
-            CHECK_INTERFACE(IQService, data, reply);
-            if(callerUid != AID_SYSTEM) {
-                ALOGE("display.qservice SCREEN_REFRESH access denied: \
-                      pid=%d uid=%d process=%s",callerPid,
-                      callerUid, callingProcName);
-                return PERMISSION_DENIED;
-            }
-            return screenRefresh();
-        } break;
-        case EXTERNAL_ORIENTATION: {
-            CHECK_INTERFACE(IQService, data, reply);
-            if(callerUid != AID_SYSTEM) {
-                ALOGE("display.qservice EXTERNAL_ORIENTATION access denied: \
-                      pid=%d uid=%d process=%s",callerPid,
-                      callerUid, callingProcName);
-                return PERMISSION_DENIED;
-            }
-            uint32_t orientation = data.readInt32();
-            setExtOrientation(orientation);
-            return NO_ERROR;
-        } break;
-        case BUFFER_MIRRORMODE: {
-            CHECK_INTERFACE(IQService, data, reply);
-            if(callerUid != AID_SYSTEM) {
-                ALOGE("display.qservice BUFFER_MIRRORMODE access denied: \
-                      pid=%d uid=%d process=%s",callerPid,
-                      callerUid, callingProcName);
-                return PERMISSION_DENIED;
-            }
-            uint32_t enable = data.readInt32();
-            setBufferMirrorMode(enable);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
+        dispatch(code, &data, reply);
+        return NO_ERROR;
+    } else {
+        return BBinder::onTransact(code, data, reply, flags);
     }
 }
 
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 9cd122e..7ad443d 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -29,35 +29,39 @@
 #include <binder/IBinder.h>
 #include <IQClient.h>
 
+
 namespace qService {
 // ----------------------------------------------------------------------------
+
 class IQService : public android::IInterface
 {
 public:
     DECLARE_META_INTERFACE(QService);
     enum {
-        // Hardware securing start/end notification
-        SECURING = android::IBinder::FIRST_CALL_TRANSACTION,
-        UNSECURING, // Hardware unsecuring start/end notification
-        CONNECT,
-        SCREEN_REFRESH,
-        EXTERNAL_ORIENTATION,
-        BUFFER_MIRRORMODE,
-        //VPU command codes - list is defined in vpu.h
-        VPU_COMMAND_LIST_START = 100,
-        VPU_COMMAND_LIST_END = 200,
+        COMMAND_LIST_START = android::IBinder::FIRST_CALL_TRANSACTION,
+        SECURING,                // Hardware securing start/end notification
+        UNSECURING,              // Hardware unsecuring start/end notification
+        CONNECT,                 // Connect to qservice
+        SCREEN_REFRESH,          // Refresh screen through SF invalidate
+        EXTERNAL_ORIENTATION,    // Set external orientation
+        BUFFER_MIRRORMODE,       // Buffer mirrormode
+        VPU_COMMAND_LIST_START = 100, //Reserved block for VPU commands
+        VPU_COMMAND_LIST_END   = 200,
+        COMMAND_LIST_END = 400,
     };
+
     enum {
         END = 0,
         START,
     };
-    virtual void securing(uint32_t startEnd) = 0;
-    virtual void unsecuring(uint32_t startEnd) = 0;
+
+    // Register a client that can be notified
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
-    virtual android::status_t screenRefresh() = 0;
-    virtual void setExtOrientation(uint32_t orientation) = 0;
-    virtual void setBufferMirrorMode(uint32_t enable) = 0;
-    virtual android::status_t vpuCommand(uint32_t command, uint32_t setting) = 0;
+    // Generic function to dispatch binder commands
+    // The type of command decides how the data is parceled
+    virtual android::status_t dispatch(uint32_t command,
+            const android::Parcel* inParcel,
+            android::Parcel* outParcel) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 327888c..aac5788 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -47,49 +47,19 @@
     ALOGD_IF(QSERVICE_DEBUG,"QService Destructor invoked");
 }
 
-void QService::securing(uint32_t startEnd) {
-    if(mClient.get()) {
-        mClient->notifyCallback(SECURING, startEnd);
-    }
-}
-
-void QService::unsecuring(uint32_t startEnd) {
-    if(mClient.get()) {
-        mClient->notifyCallback(UNSECURING, startEnd);
-    }
-}
-
 void QService::connect(const sp<qClient::IQClient>& client) {
+    ALOGD_IF(QSERVICE_DEBUG,"client connected");
     mClient = client;
 }
 
-android::status_t QService::screenRefresh() {
-    status_t result = NO_ERROR;
-    if(mClient.get()) {
-        result = mClient->notifyCallback(SCREEN_REFRESH, 0);
+status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
+        Parcel* outParcel) {
+    status_t err = FAILED_TRANSACTION;
+    if (mClient.get()) {
+        ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
+        err = mClient->notifyCallback(command, inParcel, outParcel);
     }
-    return result;
-}
-
-android::status_t QService::vpuCommand(uint32_t command, uint32_t setting ) {
-    status_t result = NO_ERROR;
-    if(mClient.get()) {
-        result = mClient->notifyCallback(command, setting);
-    }
-    return result;
-}
-
-
-void QService::setExtOrientation(uint32_t orientation) {
-    if(mClient.get()) {
-        mClient->notifyCallback(EXTERNAL_ORIENTATION, orientation);
-    }
-}
-
-void QService::setBufferMirrorMode(uint32_t enable) {
-    if(mClient.get()) {
-        mClient->notifyCallback(BUFFER_MIRRORMODE, enable);
-    }
+    return err;
 }
 
 void QService::init()
diff --git a/libqservice/QService.h b/libqservice/QService.h
index de18b59..a8e4cdb 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -45,13 +45,10 @@
 class QService : public BnQService {
 public:
     virtual ~QService();
-    virtual void securing(uint32_t startEnd);
-    virtual void unsecuring(uint32_t startEnd);
     virtual void connect(const android::sp<qClient::IQClient>& client);
-    virtual android::status_t screenRefresh();
-    virtual void setExtOrientation(uint32_t orientation);
-    virtual void setBufferMirrorMode(uint32_t enable);
-    virtual android::status_t vpuCommand(uint32_t command, uint32_t setting);
+    virtual android::status_t dispatch(uint32_t command,
+            const android::Parcel* data,
+            android::Parcel* reply);
     static void init();
 private:
     QService();
diff --git a/libqservice/QServiceUtils.h b/libqservice/QServiceUtils.h
new file mode 100644
index 0000000..3d1adc0
--- /dev/null
+++ b/libqservice/QServiceUtils.h
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef QSERVICEUTILS_H
+#define QSERVICEUTILS_H
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+#include <utils/RefBase.h>
+#include <IQService.h>
+
+// ----------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------
+inline android::sp<qService::IQService> getBinder() {
+    android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+    android::sp<qService::IQService> binder =
+            android::interface_cast<qService::IQService>
+            (sm->getService(android::String16("display.qservice")));
+    if (binder == NULL) {
+        ALOGE("%s: invalid binder object", __FUNCTION__);
+    }
+    return binder;
+}
+
+inline android::status_t sendSingleParam(uint32_t command, uint32_t value) {
+    android::status_t err = android::FAILED_TRANSACTION;
+    android::sp<qService::IQService> binder = getBinder();
+    android::Parcel inParcel, outParcel;
+    inParcel.writeInt32(value);
+    if(binder != NULL) {
+        err = binder->dispatch(command, &inParcel , &outParcel);
+    }
+    return err;
+}
+
+// ----------------------------------------------------------------------------
+// Convenience wrappers that clients can call
+// ----------------------------------------------------------------------------
+inline android::status_t securing(uint32_t startEnd) {
+    return sendSingleParam(qService::IQService::SECURING, startEnd);
+}
+
+inline android::status_t unsecuring(uint32_t startEnd) {
+    return sendSingleParam(qService::IQService::UNSECURING, startEnd);
+}
+
+inline android::status_t screenRefresh() {
+    return sendSingleParam(qService::IQService::SCREEN_REFRESH, 1);
+}
+
+inline android::status_t setExtOrientation(uint32_t orientation) {
+    return sendSingleParam(qService::IQService::EXTERNAL_ORIENTATION,
+            orientation);
+}
+
+inline android::status_t setBufferMirrorMode(uint32_t enable) {
+    return sendSingleParam(qService::IQService::BUFFER_MIRRORMODE, enable);
+}
+
+#endif /* end of include guard: QSERVICEUTILS_H */