Merge "hwc: Allow for yuv content to go through ppp on 8x10"
diff --git a/common.mk b/common.mk
index ded2e75..b48a38c 100644
--- a/common.mk
+++ b/common.mk
@@ -27,7 +27,7 @@
     common_flags += -D__ARM_HAVE_NEON
 endif
 
-ifeq ($(call is-board-platform-in-list, msm8974 msm8226), true)
+ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610), true)
     common_flags += -DVENUS_COLOR_FORMAT
     common_flags += -DMDSS_TARGET
 endif
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index b804c21..6973704 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -105,7 +105,7 @@
 
 // The following defines can be changed as required i.e. as we encounter
 // complex use cases.
-#define MAX_RGB_SURFACES 12        // Max. RGB layers currently supported per draw
+#define MAX_RGB_SURFACES 32       // Max. RGB layers currently supported per draw
 #define MAX_YUV_2_PLANE_SURFACES 4// Max. 2-plane YUV layers currently supported per draw
 #define MAX_YUV_3_PLANE_SURFACES 1// Max. 3-plane YUV layers currently supported per draw
 // +1 for the destination surface. We cannot have multiple destination surfaces.
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 3e92f53..73e145f 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -746,6 +746,11 @@
             height = 1024;
             fps = 60;
             break;
+        case HDMI_VFRMT_1024x768p60_4_3:
+            width = 1024;
+            height = 768;
+            fps = 60;
+            break;
         case HDMI_VFRMT_1920x1080p24_16_9:
             width = 1920;
             height = 1080;
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 123be3f..46acd56 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -105,6 +105,15 @@
     int stride = ALIGN(width, 32);
     // Currently surface padding is only computed for RGB* surfaces.
     if (format < 0x7) {
+        // Don't add any additional padding if debug.gralloc.map_fb_memory
+        // is enabled
+        char property[PROPERTY_VALUE_MAX];
+        if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
+           (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+           (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+              return stride;
+        }
+
         int bpp = 4;
         switch(format)
         {
@@ -173,6 +182,12 @@
 IonController::IonController()
 {
     mIonAlloc = new IonAlloc();
+    mUseTZProtection = false;
+    char property[PROPERTY_VALUE_MAX];
+    if ((property_get("persist.gralloc.cp.level3", property, NULL) <= 0) ||
+                            (atoi(property) != 1)) {
+        mUseTZProtection = true;
+    }
 }
 
 int IonController::allocate(alloc_data& data, int usage)
@@ -192,26 +207,31 @@
     if(usage & GRALLOC_USAGE_PRIVATE_IOMMU_HEAP)
         ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
 
-    //MM Heap is exclusively a secure heap.
-    if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) {
-        //XXX: Right now the MM heap is the only secure heap we have. When we
-        //have other secure heaps, we can change this.
-        if(usage & GRALLOC_USAGE_PROTECTED) {
+    if(usage & GRALLOC_USAGE_PROTECTED) {
+        if ((mUseTZProtection) && (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)) {
             ionFlags |= ION_HEAP(ION_CP_MM_HEAP_ID);
             ionFlags |= ION_SECURE;
-        }
-        else {
-            ALOGW("GRALLOC_USAGE_PRIVATE_MM_HEAP \
-                  cannot be used as an insecure heap!\
-                  trying to use IOMMU instead !!");
+        } else {
+            // for targets/OEMs which do not need HW level protection
+            // do not set ion secure flag & MM heap. Fallback to IOMMU heap.
             ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
         }
+    } else if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) {
+        //MM Heap is exclusively a secure heap.
+        //If it is used for non secure cases, fallback to IOMMU heap
+        ALOGW("GRALLOC_USAGE_PRIVATE_MM_HEAP \
+                                cannot be used as an insecure heap!\
+                                trying to use IOMMU instead !!");
+        ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
     }
 
+    if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP)
+        ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID);
+
     if(usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP)
         ionFlags |= ION_HEAP(ION_ADSP_HEAP_ID);
 
-    if(usage & GRALLOC_USAGE_PROTECTED)
+    if(ionFlags & ION_SECURE)
          data.allocType |= private_handle_t::PRIV_FLAGS_SECURE_BUFFER;
 
     // if no flags are set, default to
diff --git a/libgralloc/alloc_controller.h b/libgralloc/alloc_controller.h
index 5fe81fa..8954d39 100644
--- a/libgralloc/alloc_controller.h
+++ b/libgralloc/alloc_controller.h
@@ -65,6 +65,7 @@
 
     private:
     IonAlloc* mIonAlloc;
+    bool mUseTZProtection;
 
 };
 } //end namespace gralloc
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 703a2e6..0e7576e 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -103,6 +103,23 @@
             }
         }
 
+        if (bufferType == BUFFER_TYPE_VIDEO) {
+            if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+                if ((qdutils::MDPVersion::getInstance().getMDPVersion() <
+                     qdutils::MDSS_V5)) { //A-Family
+                    flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
+                } else {
+                    if (usage & (GRALLOC_USAGE_HW_TEXTURE |
+                                 GRALLOC_USAGE_HW_VIDEO_ENCODER))
+                        flags |= private_handle_t::PRIV_FLAGS_ITU_R_709;
+                    else if (usage & GRALLOC_USAGE_HW_CAMERA_ZSL)
+                        flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
+                }
+            } else {
+                flags |= private_handle_t::PRIV_FLAGS_ITU_R_601;
+            }
+        }
+
         if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER ) {
             flags |= private_handle_t::PRIV_FLAGS_VIDEO_ENCODER;
         }
diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp
index 3bb5533..2567300 100644
--- a/libgralloc/gralloc.cpp
+++ b/libgralloc/gralloc.cpp
@@ -80,7 +80,6 @@
     lock: gralloc_lock,
     unlock: gralloc_unlock,
     perform: gralloc_perform,
-    reserved_proc: {0},
       },
 framebuffer: 0,
 fbFormat: 0,
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 511e81f..3187648 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -54,6 +54,9 @@
      * cannot be used with noncontiguous heaps */
     GRALLOC_USAGE_PRIVATE_UNCACHED        =       0x02000000,
 
+    /* Buffer content should be displayed on an primary display only */
+    GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY   =       0x04000000,
+
     /* Buffer content should be displayed on an external display only */
     GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY   =       0x08000000,
 
@@ -65,12 +68,8 @@
     /* Close Caption displayed on an external display only */
     GRALLOC_USAGE_PRIVATE_EXTERNAL_CC     =       0x00200000,
 
-    /* Use this flag to request content protected buffers. Please note
-     * that this flag is different from the GRALLOC_USAGE_PROTECTED flag
-     * which can be used for buffers that are not secured for DRM
-     * but still need to be protected from screen captures
-     */
-    GRALLOC_USAGE_PRIVATE_CP_BUFFER       =       0x00400000,
+    /* CAMERA heap is a carveout heap for camera, is not secured*/
+    GRALLOC_USAGE_PRIVATE_CAMERA_HEAP     =       0x00400000,
 };
 
 enum {
@@ -159,6 +158,9 @@
             PRIV_FLAGS_CAMERA_READ        = 0x00040000,
             PRIV_FLAGS_HW_COMPOSER        = 0x00080000,
             PRIV_FLAGS_HW_TEXTURE         = 0x00100000,
+            PRIV_FLAGS_ITU_R_601          = 0x00200000,
+            PRIV_FLAGS_ITU_R_601_FR       = 0x00400000,
+            PRIV_FLAGS_ITU_R_709          = 0x00800000,
         };
 
         // file-descriptors
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index be3d21f..e812c01 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -155,7 +155,9 @@
 
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list, int dpy) {
+
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    Locker::Autolock _l(ctx->mExtLock);
 
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive &&
@@ -168,6 +170,10 @@
                 ctx->mExtDispConfiguring = false;
                 setListStats(ctx, list, dpy);
                 int fbZOrder = ctx->mMDPComp[dpy]->prepare(ctx, list);
+                if(ctx->deviceOrientation &&
+                    ctx->listStats[dpy].isDisplayAnimating) {
+                    fbZOrder = 0;
+                }
                 if(fbZOrder >= 0)
                     ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZOrder);
 
@@ -177,6 +183,14 @@
                 if((fbZOrder >= 0) && ctx->mCopyBit[dpy])
                     ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
                 */
+                if(ctx->listStats[dpy].isDisplayAnimating) {
+                    // Mark all app layers as HWC_OVERLAY for external during
+                    // animation, so that SF doesnt draw it on FB
+                    for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
+                        hwc_layer_1_t *layer = &list->hwLayers[i];
+                        layer->compositionType = HWC_OVERLAY;
+                    }
+                }
             }
         } else {
             // External Display is in Pause state.
@@ -227,23 +241,30 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    pthread_mutex_lock(&ctx->vstate.lock);
+    Locker::Autolock _l(ctx->mBlankLock);
     switch(event) {
         case HWC_EVENT_VSYNC:
             if (ctx->vstate.enable == enable)
                 break;
             ret = hwc_vsync_control(ctx, dpy, enable);
-            if(ret == 0) {
+            if(ret == 0)
                 ctx->vstate.enable = !!enable;
-                pthread_cond_signal(&ctx->vstate.cond);
-            }
             ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s",
                       (enable)?"ENABLED":"DISABLED");
             break;
+#ifdef QCOM_BSP
+        case  HWC_EVENT_ORIENTATION:
+            if(dpy == HWC_DISPLAY_PRIMARY) {
+                // store the primary display orientation
+                // will be used in hwc_video::configure to disable
+                // rotation animation on external display
+                ctx->deviceOrientation = enable;
+            }
+            break;
+#endif
         default:
             ret = -EINVAL;
     }
-    pthread_mutex_unlock(&ctx->vstate.lock);
     return ret;
 }
 
@@ -382,7 +403,7 @@
 
         if (display_commit(ctx, dpy) < 0) {
             ALOGE("%s: display commit fail!", __FUNCTION__);
-            return -1;
+            ret = -1;
         }
     }
 
@@ -395,7 +416,7 @@
 {
     ATRACE_CALL();
     int ret = 0;
-    Locker::Autolock _l(ctx->mExtSetLock);
+    Locker::Autolock _l(ctx->mExtLock);
 
     if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
         !ctx->dpyAttr[dpy].isPause &&
@@ -419,12 +440,18 @@
             ret = -1;
         }
 
+        int extOnlyLayerIndex =
+            ctx->listStats[dpy].extOnlyLayerIndex;
+
         private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
-        if(copybitDone) {
+        if(extOnlyLayerIndex!= -1) {
+            hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+            hnd = (private_handle_t *)extLayer->handle;
+        } else if(copybitDone) {
             hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
         }
 
-        if(hnd) {
+        if(hnd && !isYuvBuffer(hnd)) {
             if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
                 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
@@ -469,6 +496,7 @@
     // This is only indicative of how many times SurfaceFlinger posts
     // frames to the display.
     CALC_FPS();
+    MDPComp::resetIdleFallBack();
     return ret;
 }
 
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 160e6da..1f724de 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -113,7 +113,9 @@
     //Calculates total rendering area for RGB layers
     unsigned int renderArea = 0;
     unsigned int w=0, h=0;
-    for (unsigned int i=0; i<list->numHwLayers; i++) {
+    // Skipping last layer since FrameBuffer layer should not affect
+    // which composition to choose
+    for (unsigned int i=0; i<list->numHwLayers -1; i++) {
          private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
          if (hnd) {
              if (BUFFER_TYPE_UI == hnd->bufferType) {
@@ -151,6 +153,11 @@
         return false;
     }
 
+    if (ctx->listStats[dpy].numAppLayers > MAX_NUM_LAYERS) {
+        // Reached max layers supported by HWC.
+        return false;
+    }
+
     bool useCopybitForYUV = canUseCopybitForYUV(ctx);
     bool useCopybitForRGB = canUseCopybitForRGB(ctx, list, dpy);
     LayerProp *layerProp = ctx->layerProp[dpy];
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index bfa33ca..ba46bf5 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -19,12 +19,17 @@
  */
 
 #define DEBUG_FBUPDATE 0
+#include <cutils/properties.h>
 #include <gralloc_priv.h>
+#include <overlayRotator.h>
 #include "hwc_fbupdate.h"
 #include "mdp_version.h"
+#include "external.h"
 
 using namespace qdutils;
 
+using overlay::Rotator;
+
 namespace qhwc {
 
 namespace ovutils = overlay::utils;
@@ -38,6 +43,7 @@
 
 inline void IFBUpdate::reset() {
     mModeOn = false;
+    mRot = NULL;
 }
 
 //================= Low res====================================
@@ -65,6 +71,12 @@
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
+        int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
+        // ext only layer present..
+        if(extOnlyLayerIndex != -1) {
+            layer = &list->hwLayers[extOnlyLayerIndex];
+            layer->compositionType = HWC_OVERLAY;
+        }
         overlay::Overlay& ov = *(ctx->mOverlay);
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         ovutils::Whf info(hnd->width, hnd->height,
@@ -81,42 +93,76 @@
         mDest = dest;
 
         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
-
+        ovutils::eIsFg isFg = ovutils::IS_FG_OFF;
         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
 
-        ovutils::PipeArgs parg(mdpFlags,
-                               info,
-                               zOrder,
-                               ovutils::IS_FG_OFF,
-                               ovutils::ROT_FLAGS_NONE);
-        ov.setSource(parg, dest);
-
-        hwc_rect_t sourceCrop;
-        getNonWormholeRegion(list, sourceCrop);
-        // x,y,w,h
-        ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
-                           sourceCrop.right - sourceCrop.left,
-                           sourceCrop.bottom - sourceCrop.top);
-        ov.setCrop(dcrop, dest);
-
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t displayFrame = layer->displayFrame;
         int transform = layer->transform;
-        ovutils::eTransform orient =
-            static_cast<ovutils::eTransform>(transform);
-        ov.setTransform(orient, dest);
+        int fbWidth  = ctx->dpyAttr[mDpy].xres;
+        int fbHeight = ctx->dpyAttr[mDpy].yres;
+        int rotFlags = ovutils::ROT_FLAGS_NONE;
 
-        hwc_rect_t displayFrame = sourceCrop;
+        ovutils::eTransform orient =
+                    static_cast<ovutils::eTransform>(transform);
+        if(mDpy && ctx->mExtOrientation) {
+            // If there is a external orientation set, use that
+            transform = ctx->mExtOrientation;
+            orient = static_cast<ovutils::eTransform >(ctx->mExtOrientation);
+        }
+
+        // Do not use getNonWormholeRegion() function to calculate the
+        // sourceCrop during animation on external display and
+        // Dont do wormhole calculation when extorientation is set on External
+        if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+            sourceCrop = layer->displayFrame;
+            displayFrame = sourceCrop;
+        } else if((!mDpy || (mDpy && !ctx->mExtOrientation))
+                               && extOnlyLayerIndex == -1) {
+            getNonWormholeRegion(list, sourceCrop);
+            displayFrame = sourceCrop;
+        }
         ovutils::Dim dpos(displayFrame.left,
                           displayFrame.top,
                           displayFrame.right - displayFrame.left,
                           displayFrame.bottom - displayFrame.top);
         // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
-        if(mDpy)
+        if(mDpy && !ctx->mExtOrientation)
             getActionSafePosition(ctx, mDpy, dpos.x, dpos.y, dpos.w, dpos.h);
-        ov.setPosition(dpos, dest);
 
+        if(mDpy) {
+            getAspectRatioPosition(ctx, mDpy, ctx->mExtOrientation, dpos.x,
+                                    dpos.y, dpos.w, dpos.h);
+            // Convert dim to hwc_rect_t
+            displayFrame.left = dpos.x;
+            displayFrame.top = dpos.y;
+            displayFrame.right = dpos.w + displayFrame.left;
+            displayFrame.bottom = dpos.h + displayFrame.top;
+        }
+        setMdpFlags(layer, mdpFlags, 0, transform);
+        // For External use rotator if there is a rotation value set
+        if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
+            mRot = ctx->mRotMgr->getNext();
+            if(mRot == NULL) return -1;
+            //Configure rotator for pre-rotation
+            if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
+                ALOGE("%s: configRotator Failed!", __FUNCTION__);
+                mRot = NULL;
+                return -1;
+            }
+            info.format = (mRot)->getDstFormat();
+            updateSource(orient, info, sourceCrop);
+            rotFlags |= ovutils::ROT_PREROTATED;
+        }
+        //For the mdp, since either we are pre-rotating or MDP does flips
+        orient = ovutils::OVERLAY_TRANSFORM_0;
+        transform = 0;
+        ovutils::PipeArgs parg(mdpFlags, info, zOrder, isFg,
+                                static_cast<ovutils::eRotFlags>(rotFlags));
         ret = true;
-        if (!ov.commit(dest)) {
-            ALOGE("%s: commit fails", __FUNCTION__);
+        if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
+                    NULL, mDest) < 0) {
+            ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
             ret = false;
         }
     }
@@ -131,7 +177,15 @@
     bool ret = true;
     overlay::Overlay& ov = *(ctx->mOverlay);
     ovutils::eDest dest = mDest;
-    if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
+    int fd = hnd->fd;
+    uint32_t offset = hnd->offset;
+    if(mRot) {
+        if(!mRot->queueBuffer(fd, offset))
+            return false;
+        fd = mRot->getDstMemId();
+        offset = mRot->getDstOffset();
+    }
+    if (!ov.queueBuffer(fd, offset, dest)) {
         ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
         ret = false;
     }
@@ -145,6 +199,7 @@
     IFBUpdate::reset();
     mDestLeft = ovutils::OV_INVALID;
     mDestRight = ovutils::OV_INVALID;
+    mRot = NULL;
 }
 
 bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
@@ -165,6 +220,12 @@
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
+        int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
+        // ext only layer present..
+        if(extOnlyLayerIndex != -1) {
+            layer = &list->hwLayers[extOnlyLayerIndex];
+            layer->compositionType = HWC_OVERLAY;
+        }
         overlay::Overlay& ov = *(ctx->mOverlay);
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         ovutils::Whf info(hnd->width, hnd->height,
@@ -208,8 +269,17 @@
                                 ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargR, destR);
 
-        hwc_rect_t sourceCrop;
-        getNonWormholeRegion(list, sourceCrop);
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t displayFrame = layer->displayFrame;
+        // Do not use getNonWormholeRegion() function to calculate the
+        // sourceCrop during animation on external display.
+        if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+            sourceCrop = layer->displayFrame;
+            displayFrame = sourceCrop;
+        } else if(extOnlyLayerIndex == -1) {
+            getNonWormholeRegion(list, sourceCrop);
+            displayFrame = sourceCrop;
+        }
         ovutils::Dim dcropL(sourceCrop.left, sourceCrop.top,
                             (sourceCrop.right - sourceCrop.left) / 2,
                             sourceCrop.bottom - sourceCrop.top);
@@ -227,11 +297,11 @@
         ov.setTransform(orient, destL);
         ov.setTransform(orient, destR);
 
-        hwc_rect_t displayFrame = sourceCrop;
         const int halfWidth = (displayFrame.right - displayFrame.left) / 2;
         const int height = displayFrame.bottom - displayFrame.top;
 
-        ovutils::Dim dposL(MAX_DISPLAY_DIM - halfWidth,
+        const int halfDpy = ctx->dpyAttr[mDpy].xres / 2;
+        ovutils::Dim dposL(halfDpy - halfWidth,
                            displayFrame.top,
                            halfWidth,
                            height);
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 4291a50..5cf75f7 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -25,6 +25,10 @@
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
+namespace overlay {
+    class Rotator;
+}
+
 namespace qhwc {
 namespace ovutils = overlay::utils;
 
@@ -46,6 +50,7 @@
 protected:
     const int mDpy; // display to update
     bool mModeOn; // if prepare happened
+    overlay::Rotator *mRot;
 };
 
 //Low resolution (<= 2048) panel handler.
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index eb46304..0911248 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 
+#include <math.h>
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
 #include "external.h"
@@ -83,11 +84,6 @@
         return false;
     }
 
-    if(!setupBasePipe(ctx)) {
-        ALOGE("%s: Failed to setup primary base pipe", __FUNCTION__);
-        return false;
-    }
-
     char property[PROPERTY_VALUE_MAX];
 
     sEnabled = false;
@@ -95,6 +91,10 @@
        (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
         (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
         sEnabled = true;
+        if(!setupBasePipe(ctx)) {
+            ALOGE("%s: Failed to setup primary base pipe", __FUNCTION__);
+            return false;
+        }
     }
 
     sDebugLogs = false;
@@ -222,7 +222,7 @@
     layerCount = numLayers;
     fbCount = numLayers;
     mdpCount = 0;
-    needsRedraw = false;
+    needsRedraw = true;
     fbZ = 0;
 }
 
@@ -263,8 +263,8 @@
     fbZ = curFrame.fbZ;
 }
 
-bool MDPComp::isWidthValid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
-
+bool MDPComp::isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer) {
+    const int dpy = HWC_DISPLAY_PRIMARY;
     private_handle_t *hnd = (private_handle_t *)layer->handle;
 
     if(!hnd) {
@@ -275,32 +275,49 @@
     int hw_w = ctx->dpyAttr[mDpy].xres;
     int hw_h = ctx->dpyAttr[mDpy].yres;
 
-    hwc_rect_t sourceCrop = layer->sourceCrop;
-    hwc_rect_t displayFrame = layer->displayFrame;
-
-    hwc_rect_t crop =  sourceCrop;
-    int crop_w = crop.right - crop.left;
-    int crop_h = crop.bottom - crop.top;
-
-    hwc_rect_t dst = displayFrame;
-    int dst_w = dst.right - dst.left;
-    int dst_h = dst.bottom - dst.top;
+    hwc_rect_t crop = layer->sourceCrop;
+    hwc_rect_t dst = layer->displayFrame;
 
     if(dst.left < 0 || dst.top < 0 || dst.right > hw_w || dst.bottom > hw_h) {
-        hwc_rect_t scissor = {0, 0, hw_w, hw_h };
-        qhwc::calculate_crop_rects(crop, dst, scissor, layer->transform);
-        crop_w = crop.right - crop.left;
-        crop_h = crop.bottom - crop.top;
+       hwc_rect_t scissor = {0, 0, hw_w, hw_h };
+       qhwc::calculate_crop_rects(crop, dst, scissor, layer->transform);
     }
 
+    int crop_w = crop.right - crop.left;
+    int crop_h = crop.bottom - crop.top;
+    int dst_w = dst.right - dst.left;
+    int dst_h = dst.bottom - dst.top;
+    float w_dscale = ceilf((float)crop_w / (float)dst_w);
+    float h_dscale = ceilf((float)crop_h / (float)dst_h);
+
     /* Workaround for MDP HW limitation in DSI command mode panels where
      * FPS will not go beyond 30 if buffers on RGB pipes are of width or height
      * less than 5 pixels
-     * */
-
+     * There also is a HW limilation in MDP, minimum block size is 2x2
+     * Fallback to GPU if height is less than 2.
+     */
     if((crop_w < 5)||(crop_h < 5))
         return false;
 
+    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)
+                return false;
+        }
+    } else { //A-family
+        if(w_dscale > downscale || h_dscale > downscale)
+            return false;
+    }
+
     return true;
 }
 
@@ -345,20 +362,11 @@
         ALOGD_IF( isDebug(),"%s: External Display connection is pending",
                   __FUNCTION__);
         ret = false;
-    } else if(ctx->listStats[mDpy].needsAlphaScale
-       && ctx->mMDP.version < qdutils::MDSS_V5) {
-        ALOGD_IF(isDebug(), "%s: frame needs alpha downscaling",__FUNCTION__);
-        ret = false;
     } else if(ctx->isPaddingRound) {
         ctx->isPaddingRound = false;
         ALOGD_IF(isDebug(), "%s: padding round",__FUNCTION__);
         ret = false;
-    } else if(sIdleFallBack) {
-        sIdleFallBack = false;
-        ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__);
-        ret = false;
     }
-
     return ret;
 }
 
@@ -369,6 +377,11 @@
 
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
 
+    if(sIdleFallBack) {
+        ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy);
+        return false;
+    }
+
     if(mDpy > HWC_DISPLAY_PRIMARY){
         ALOGD_IF(isDebug(), "%s: Cannot support External display(s)",
                  __FUNCTION__);
@@ -382,6 +395,12 @@
         return false;
     }
 
+    if(ctx->listStats[mDpy].needsAlphaScale
+       && ctx->mMDP.version < qdutils::MDSS_V5) {
+        ALOGD_IF(isDebug(), "%s: frame needs alpha downscaling",__FUNCTION__);
+        return false;
+    }
+
     //MDP composition is not efficient if layer needs rotator.
     for(int i = 0; i < numAppLayers; ++i) {
         // As MDP h/w supports flip operation, use MDP comp only for
@@ -389,13 +408,14 @@
         hwc_layer_1_t* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
 
-        if(layer->transform & HWC_TRANSFORM_ROT_90 && !isYuvBuffer(hnd)) {
+        if((layer->transform & HWC_TRANSFORM_ROT_90) && !isYuvBuffer(hnd)) {
             ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
             return false;
         }
 
-        if(!isYuvBuffer(hnd) && !isWidthValid(ctx,layer)) {
-            ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",__FUNCTION__);
+        if(!isValidDimension(ctx,layer)) {
+            ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
+                __FUNCTION__);
             return false;
         }
     }
@@ -467,13 +487,16 @@
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
     mCurrentFrame.reset(numAppLayers);
     updateYUV(ctx, list);
-    int mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount;
+    int mdpCount = mCurrentFrame.mdpCount;
     int fbNeeded = int(mCurrentFrame.fbCount != 0);
 
     if(!isYuvPresent(ctx, mDpy)) {
         return false;
     }
 
+    if(!mdpCount)
+        return false;
+
     if(mdpCount > (sMaxPipesPerMixer - fbNeeded)) {
         ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
         return false;
@@ -492,9 +515,10 @@
 
 /* Checks for conditions where YUV layers cannot be bypassed */
 bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
+    bool extAnimBlockFeature = mDpy && ctx->listStats[mDpy].isDisplayAnimating;
 
-    if(isSkipLayer(layer)) {
-        ALOGE("%s: Unable to bypass skipped YUV", __FUNCTION__);
+    if(isSkipLayer(layer) && !extAnimBlockFeature) {
+        ALOGD_IF(isDebug(), "%s: Video marked SKIP dpy %d", __FUNCTION__, mDpy);
         return false;
     }
 
@@ -503,24 +527,12 @@
         return false;
     }
 
-    if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
-        const uint32_t downscale =
-                qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
-        hwc_rect_t crop = layer->sourceCrop;
-        hwc_rect_t dst = layer->displayFrame;
-        int cWidth = crop.right - crop.left;
-        int cHeight = crop.bottom - crop.top;
-        int dWidth = dst.right - dst.left;
-        int dHeight = dst.bottom - dst.top;
-
-        if(layer->transform & HAL_TRANSFORM_ROT_90) {
-            swap(cWidth, cHeight);
-        }
-
-        if(cWidth > MAX_DISPLAY_DIM || (cWidth/dWidth) > downscale ||
-                    (cHeight/dHeight) > downscale)
-            return false;
+    if(!isValidDimension(ctx, layer)) {
+        ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
+            __FUNCTION__);
+        return false;
     }
+
     return true;
 }
 
@@ -616,6 +628,15 @@
 void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
 
     int nYuvCount = ctx->listStats[mDpy].yuvCount;
+    if(!nYuvCount && mDpy) {
+        //Reset "No animation on external display" related  parameters.
+        ctx->mPrevCropVideo.left = ctx->mPrevCropVideo.top =
+            ctx->mPrevCropVideo.right = ctx->mPrevCropVideo.bottom = 0;
+        ctx->mPrevDestVideo.left = ctx->mPrevDestVideo.top =
+            ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
+        ctx->mPrevTransformVideo = 0;
+        return;
+     }
     for(int index = 0;index < nYuvCount; index++){
         int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
         hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
@@ -713,12 +734,23 @@
 
     //Check whether layers marked for MDP Composition is actually doable.
     if(isFullFrameDoable(ctx, list)){
-        if(mCurrentFrame.mdpCount) {
-            mCurrentFrame.map();
-            //Acquire and Program MDP pipes
-            if(!programMDP(ctx, list)) {
-                mCurrentFrame.reset(numLayers);
-                mCachedFrame.cacheAll(list);
+        mCurrentFrame.map();
+        //Acquire and Program MDP pipes
+        if(!programMDP(ctx, list)) {
+            mCurrentFrame.reset(numLayers);
+            mCachedFrame.cacheAll(list);
+        } else { //Success
+            //Any change in composition types needs an FB refresh
+            mCurrentFrame.needsRedraw = false;
+            if(mCurrentFrame.fbCount &&
+                    ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
+                     (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
+                     (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
+                     (!mCurrentFrame.mdpCount) ||
+                     (list->flags & HWC_GEOMETRY_CHANGED) ||
+                     isSkipPresent(ctx, mDpy) ||
+                     (mDpy > HWC_DISPLAY_PRIMARY))) {
+                mCurrentFrame.needsRedraw = true;
             }
         }
     } else if(isOnlyVideoDoable(ctx, list)) {
@@ -740,18 +772,6 @@
         mCachedFrame.cacheAll(list);
     }
 
-    /* Any change in composition types needs an FB refresh*/
-    if(mCurrentFrame.fbCount &&
-            ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
-            (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
-            (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
-            (!mCurrentFrame.mdpCount) ||
-            (list->flags & HWC_GEOMETRY_CHANGED) ||
-            isSkipPresent(ctx, mDpy) ||
-            (mDpy > HWC_DISPLAY_PRIMARY))) {
-        mCurrentFrame.needsRedraw = true;
-    }
-
     //UpdateLayerFlags
     setMDPCompLayerFlags(ctx, list);
     mCachedFrame.updateCounts(mCurrentFrame);
@@ -793,52 +813,23 @@
 }
 
 bool MDPCompLowRes::allocLayerPipes(hwc_context_t *ctx,
-                                    hwc_display_contents_1_t* list) {
-    if(isYuvPresent(ctx, mDpy)) {
-        int nYuvCount = ctx->listStats[mDpy].yuvCount;
+        hwc_display_contents_1_t* list) {
+    for(int index = 0; index < mCurrentFrame.layerCount; index++) {
 
-        for(int index = 0; index < nYuvCount ; index ++) {
-            int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
-
-            if(mCurrentFrame.isFBComposed[nYuvIndex])
-                continue;
-
-            hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
-
-            int mdpIndex = mCurrentFrame.layerToMDP[nYuvIndex];
-
-            PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
-            info.pipeInfo = new MdpPipeInfoLowRes;
-            info.rot = NULL;
-            MdpPipeInfoLowRes& pipe_info = *(MdpPipeInfoLowRes*)info.pipeInfo;
-
-            pipe_info.index = getMdpPipe(ctx, MDPCOMP_OV_VG);
-            if(pipe_info.index == ovutils::OV_INVALID) {
-                ALOGD_IF(isDebug(), "%s: Unable to get pipe for Videos",
-                         __FUNCTION__);
-                return false;
-            }
-        }
-    }
-
-    for(int index = 0 ; index < mCurrentFrame.layerCount; index++ ) {
         if(mCurrentFrame.isFBComposed[index]) continue;
+
         hwc_layer_1_t* layer = &list->hwLayers[index];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
-
-        if(isYuvBuffer(hnd))
-            continue;
-
         int mdpIndex = mCurrentFrame.layerToMDP[index];
-
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
         info.pipeInfo = new MdpPipeInfoLowRes;
         info.rot = NULL;
         MdpPipeInfoLowRes& pipe_info = *(MdpPipeInfoLowRes*)info.pipeInfo;
-
         ePipeType type = MDPCOMP_OV_ANY;
 
-        if(!qhwc::needsScaling(layer)
+        if(isYuvBuffer(hnd)) {
+            type = MDPCOMP_OV_VG;
+        } else if(!qhwc::needsScaling(ctx, layer, mDpy)
             && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
             && ctx->mMDP.version >= qdutils::MDSS_V5) {
             type = MDPCOMP_OV_DMA;
@@ -846,7 +837,8 @@
 
         pipe_info.index = getMdpPipe(ctx, type);
         if(pipe_info.index == ovutils::OV_INVALID) {
-            ALOGD_IF(isDebug(), "%s: Unable to get pipe for UI", __FUNCTION__);
+            ALOGD_IF(isDebug(), "%s: Unable to get pipe type = %d",
+                __FUNCTION__, (int) type);
             return false;
         }
     }
@@ -866,7 +858,7 @@
     }
 
     /* reset Invalidator */
-    if(idleInvalidator && mCurrentFrame.mdpCount)
+    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
         idleInvalidator->markForSleep();
 
     overlay::Overlay& ov = *ctx->mOverlay;
@@ -972,55 +964,32 @@
 }
 
 bool MDPCompHighRes::allocLayerPipes(hwc_context_t *ctx,
-                                     hwc_display_contents_1_t* list) {
-    overlay::Overlay& ov = *ctx->mOverlay;
-    int layer_count = ctx->listStats[mDpy].numAppLayers;
+        hwc_display_contents_1_t* list) {
+    for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
 
-    if(isYuvPresent(ctx, mDpy)) {
-        int nYuvCount = ctx->listStats[mDpy].yuvCount;
+        if(mCurrentFrame.isFBComposed[index]) continue;
 
-        for(int index = 0; index < nYuvCount; index ++) {
-            int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
-            hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
-            PipeLayerPair& info = mCurrentFrame.mdpToLayer[nYuvIndex];
-            info.pipeInfo = new MdpPipeInfoHighRes;
-            info.rot = NULL;
-            MdpPipeInfoHighRes& pipe_info = *(MdpPipeInfoHighRes*)info.pipeInfo;
-            if(!acquireMDPPipes(ctx, layer, pipe_info,MDPCOMP_OV_VG)) {
-                ALOGD_IF(isDebug(),"%s: Unable to get pipe for videos",
-                         __FUNCTION__);
-                //TODO: windback pipebook data on fail
-                return false;
-            }
-            pipe_info.zOrder = nYuvIndex;
-        }
-    }
-
-    for(int index = 0 ; index < layer_count ; index++ ) {
         hwc_layer_1_t* layer = &list->hwLayers[index];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
-
-        if(isYuvBuffer(hnd))
-            continue;
-
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[index];
         info.pipeInfo = new MdpPipeInfoHighRes;
         info.rot = NULL;
         MdpPipeInfoHighRes& pipe_info = *(MdpPipeInfoHighRes*)info.pipeInfo;
-
         ePipeType type = MDPCOMP_OV_ANY;
 
-        if(!qhwc::needsScaling(layer)
+        if(isYuvBuffer(hnd)) {
+            type = MDPCOMP_OV_VG;
+        } else if(!qhwc::needsScaling(ctx, layer, mDpy)
             && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
-            && ctx->mMDP.version >= qdutils::MDSS_V5)
+            && ctx->mMDP.version >= qdutils::MDSS_V5) {
             type = MDPCOMP_OV_DMA;
+        }
 
         if(!acquireMDPPipes(ctx, layer, pipe_info, type)) {
-            ALOGD_IF(isDebug(), "%s: Unable to get pipe for UI", __FUNCTION__);
-            //TODO: windback pipebook data on fail
+            ALOGD_IF(isDebug(), "%s: Unable to get pipe for type = %d",
+                    __FUNCTION__, (int) type);
             return false;
         }
-        pipe_info.zOrder = index;
     }
     return true;
 }
@@ -1057,7 +1026,7 @@
     }
 
     /* reset Invalidator */
-    if(idleInvalidator && mCurrentFrame.mdpCount)
+    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
         idleInvalidator->markForSleep();
 
     overlay::Overlay& ov = *ctx->mOverlay;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 4aedd77..a0255b7 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -51,6 +51,7 @@
     static void timeout_handler(void *udata);
     /* Initialize MDP comp*/
     static bool init(hwc_context_t *ctx);
+    static void resetIdleFallBack() { sIdleFallBack = false; }
 
 protected:
     enum ePipeType {
@@ -150,8 +151,8 @@
     static bool isDebug() { return sDebugLogs ? true : false; };
     /* Is feature enabled */
     static bool isEnabled() { return sEnabled; };
-    /* checks for mdp comp width limitation */
-    bool isWidthValid(hwc_context_t *ctx, hwc_layer_1_t *layer);
+    /* checks for mdp comp dimension limitation */
+    bool isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer);
     /* tracks non updating layers*/
     void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list);
     /* optimize layers for mdp comp*/
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index edf579f..65667bd 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -107,4 +107,9 @@
 #endif
     return result;
 }
+
+void QClient::setExtOrientation(uint32_t orientation) {
+    mHwcContext->mExtOrientation = orientation;
+}
+
 }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 9cb2680..4cbabef 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -60,6 +60,7 @@
     void securing(uint32_t startEnd);
     void unsecuring(uint32_t startEnd);
     android::status_t screenRefresh();
+    void setExtOrientation(uint32_t orientation);
 
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index eb525a6..b314317 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -148,7 +148,7 @@
                 }else if(!strncmp(s1,"wfd",strlen(s1))) {
                     ctx->mExtDisplay->teardownWFDDisplay();
                 }
-                Locker::Autolock _l(ctx->mExtSetLock);
+                Locker::Autolock _l(ctx->mExtLock);
                 clear(ctx, dpy);
                 ALOGD("%s sending hotplug: connected = %d and dpy:%d",
                       __FUNCTION__, connected, dpy);
@@ -170,7 +170,7 @@
                         // teardown Active WFD Display
                         ctx->mExtDisplay->teardownWFDDisplay();
                         {
-                            Locker::Autolock _l(ctx->mExtSetLock);
+                            Locker::Autolock _l(ctx->mExtLock);
                             clear(ctx, dpy);
                             //send hotplug disconnect event
                             ALOGD_IF(UEVENT_DEBUG, "sending hotplug: disconnect"
@@ -195,7 +195,7 @@
                 ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
                         connected);
                 ctx->dpyAttr[dpy].connected = true;
-                Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
+                Locker::Autolock _l(ctx->mExtLock); //hwc comp could be on
                 ctx->proc->hotplug(ctx->proc, dpy, connected);
                 break;
             }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 8ea9767..b0ea0fc 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -109,6 +109,13 @@
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period = 1000000000l / fps;
 
+    //Unblank primary on first boot
+    if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
+        ALOGE("%s: Failed to unblank display", __FUNCTION__);
+        return -errno;
+    }
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive = true;
+
     return 0;
 }
 
@@ -151,11 +158,10 @@
     }
     MDPComp::init(ctx);
 
-    pthread_mutex_init(&(ctx->vstate.lock), NULL);
-    pthread_cond_init(&(ctx->vstate.cond), NULL);
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
     ctx->mExtDispConfiguring = false;
+    ctx->mExtOrientation = 0;
 
     //Right now hwc starts the service but anybody could do it, or it could be
     //independent process as well.
@@ -165,6 +171,14 @@
             defaultServiceManager()->getService(
             String16("display.qservice")))->connect(client);
 
+    // Initialize "No animation on external display" related  parameters.
+    ctx->deviceOrientation = 0;
+    ctx->mPrevCropVideo.left = ctx->mPrevCropVideo.top =
+        ctx->mPrevCropVideo.right = ctx->mPrevCropVideo.bottom = 0;
+    ctx->mPrevDestVideo.left = ctx->mPrevDestVideo.top =
+        ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
+    ctx->mPrevTransformVideo = 0;
+
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
 }
@@ -214,8 +228,6 @@
     }
 
 
-    pthread_mutex_destroy(&(ctx->vstate.lock));
-    pthread_cond_destroy(&(ctx->vstate.cond));
 }
 
 
@@ -276,15 +288,41 @@
     return;
 }
 
-bool needsScaling(hwc_layer_1_t const* layer) {
+/* Calculates the aspect ratio for external based on the primary */
+void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
+                        uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h) {
+    int fbWidth  = ctx->dpyAttr[dpy].xres;
+    int fbHeight = ctx->dpyAttr[dpy].yres;
+
+    switch(orientation) {
+        case HAL_TRANSFORM_ROT_90:
+        case HAL_TRANSFORM_ROT_270:
+            x = (fbWidth - (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres
+                        * fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres))/2;
+            y = 0;
+            w = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres *
+                    fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres);
+            h = fbHeight;
+            break;
+        default:
+            //Do nothing
+            break;
+     }
+    ALOGD_IF(HWC_UTILS_DEBUG, "%s: Position: x = %d, y = %d w = %d h = %d",
+                    __FUNCTION__, x, y, w ,h);
+}
+
+
+bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+        const int& dpy) {
     int dst_w, dst_h, src_w, src_h;
 
     hwc_rect_t displayFrame  = layer->displayFrame;
     hwc_rect_t sourceCrop = layer->sourceCrop;
+    trimLayer(ctx, dpy, layer->transform, sourceCrop, displayFrame);
 
     dst_w = displayFrame.right - displayFrame.left;
     dst_h = displayFrame.bottom - displayFrame.top;
-
     src_w = sourceCrop.right - sourceCrop.left;
     src_h = sourceCrop.bottom - sourceCrop.top;
 
@@ -294,8 +332,9 @@
     return false;
 }
 
-bool isAlphaScaled(hwc_layer_1_t const* layer) {
-    if(needsScaling(layer) && isAlphaPresent(layer)) {
+bool isAlphaScaled(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+        const int& dpy) {
+    if(needsScaling(ctx, layer, dpy) && isAlphaPresent(layer)) {
         return true;
     }
     return false;
@@ -325,6 +364,9 @@
     ctx->listStats[dpy].needsAlphaScale = false;
     ctx->listStats[dpy].preMultipliedAlpha = false;
     ctx->listStats[dpy].yuvCount = 0;
+    char property[PROPERTY_VALUE_MAX];
+    ctx->listStats[dpy].extOnlyLayerIndex = -1;
+    ctx->listStats[dpy].isDisplayAnimating = false;
 
     for (size_t i = 0; i < list->numHwLayers; i++) {
         hwc_layer_1_t const* layer = &list->hwLayers[i];
@@ -338,12 +380,15 @@
         //We disregard FB being skip for now! so the else if
         } else if (isSkipLayer(&list->hwLayers[i])) {
             ctx->listStats[dpy].skipCount++;
-        } else if (UNLIKELY(isYuvBuffer(hnd))) {
+        }
+
+        if (UNLIKELY(isYuvBuffer(hnd))) {
             int& yuvCount = ctx->listStats[dpy].yuvCount;
             ctx->listStats[dpy].yuvIndices[yuvCount] = i;
             yuvCount++;
 
-            if(layer->transform & HWC_TRANSFORM_ROT_90) {
+            if((layer->transform & HWC_TRANSFORM_ROT_90) &&
+                    canUseRotator(ctx)) {
                 if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
                     ctx->isPaddingRound = true;
                 }
@@ -354,12 +399,53 @@
             ctx->listStats[dpy].preMultipliedAlpha = true;
 
         if(!ctx->listStats[dpy].needsAlphaScale)
-            ctx->listStats[dpy].needsAlphaScale = isAlphaScaled(layer);
+            ctx->listStats[dpy].needsAlphaScale =
+                    isAlphaScaled(ctx, layer, dpy);
+
+        if(UNLIKELY(isExtOnly(hnd))){
+            ctx->listStats[dpy].extOnlyLayerIndex = i;
+        }
+#ifdef QCOM_BSP
+        if (layer->flags & HWC_SCREENSHOT_ANIMATOR_LAYER) {
+            ctx->listStats[dpy].isDisplayAnimating = true;
+        }
+#endif
+    }
+    if(ctx->listStats[dpy].yuvCount > 0) {
+        if (property_get("hw.cabl.yuv", property, NULL) > 0) {
+            if (atoi(property) != 1) {
+                property_set("hw.cabl.yuv", "1");
+            }
+        }
+    } else {
+        if (property_get("hw.cabl.yuv", property, NULL) > 0) {
+            if (atoi(property) != 0) {
+                property_set("hw.cabl.yuv", "0");
+            }
+        }
+    }
+    if(dpy) {
+        //uncomment the below code for testing purpose.
+        /* char value[PROPERTY_VALUE_MAX];
+        property_get("sys.ext_orientation", value, "0");
+        // Assuming the orientation value is in terms of HAL_TRANSFORM,
+        // This needs mapping to HAL, if its in different convention
+        ctx->mExtOrientation = atoi(value); */
+        // Assuming the orientation value is in terms of HAL_TRANSFORM,
+        // This needs mapping to HAL, if its in different convention
+        if(ctx->mExtOrientation) {
+            ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d",
+                     __FUNCTION__, ctx->mExtOrientation);
+            if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
+                ctx->isPaddingRound = true;
+            }
+            Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+        }
     }
 }
 
 
-static inline void calc_cut(float& leftCutRatio, float& topCutRatio,
+static void calc_cut(float& leftCutRatio, float& topCutRatio,
         float& rightCutRatio, float& bottomCutRatio, int orient) {
     if(orient & HAL_TRANSFORM_FLIP_H) {
         swap(leftCutRatio, rightCutRatio);
@@ -524,6 +610,9 @@
         if(atoi(property) == 0)
             swapzero = true;
     }
+    bool isExtAnimating = false;
+    if(dpy)
+       isExtAnimating = ctx->listStats[dpy].isDisplayAnimating;
 
     //Accumulate acquireFenceFds
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
@@ -572,7 +661,16 @@
             //Populate releaseFenceFds.
             if(UNLIKELY(swapzero))
                 list->hwLayers[i].releaseFenceFd = -1;
-            else
+            else if(isExtAnimating) {
+                // Release all the app layer fds immediately,
+                // if animation is in progress.
+                hwc_layer_1_t const* layer = &list->hwLayers[i];
+                private_handle_t *hnd = (private_handle_t *)layer->handle;
+                if(isYuvBuffer(hnd)) {
+                    list->hwLayers[i].releaseFenceFd = dup(releaseFd);
+                } else
+                    list->hwLayers[i].releaseFenceFd = -1;
+            } else
                 list->hwLayers[i].releaseFenceFd = dup(releaseFd);
         }
     }
@@ -584,6 +682,11 @@
 
     if (ctx->mCopyBit[dpy])
         ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+    // if external is animating, close the relaseFd
+    if(isExtAnimating) {
+        close(releaseFd);
+        releaseFd = -1;
+    }
     if(UNLIKELY(swapzero)){
         list->retireFenceFd = -1;
         close(releaseFd);
@@ -607,10 +710,9 @@
 
 void setMdpFlags(hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
-        int rotDownscale) {
+        int rotDownscale, int transform) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
-    const int& transform = layer->transform;
 
     if(layer->blending == HWC_BLENDING_PREMULT) {
         ovutils::setMdpFlags(mdpFlags,
@@ -636,12 +738,12 @@
 
     //No 90 component and no rot-downscale then flips done by MDP
     //If we use rot then it might as well do flips
-    if(!(layer->transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) {
-        if(layer->transform & HWC_TRANSFORM_FLIP_H) {
+    if(!(transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) {
+        if(transform & HWC_TRANSFORM_FLIP_H) {
             ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_H);
         }
 
-        if(layer->transform & HWC_TRANSFORM_FLIP_V) {
+        if(transform & HWC_TRANSFORM_FLIP_V) {
             ovutils::setMdpFlags(mdpFlags,  ovutils::OV_MDP_FLIP_V);
         }
     }
@@ -654,13 +756,29 @@
     }
 }
 
-static inline int configRotator(Rotator *rot, const Whf& whf,
-        const hwc_rect_t& crop, const eMdpFlags& mdpFlags,
+int configRotator(Rotator *rot, const Whf& whf,
+        hwc_rect_t& crop, const eMdpFlags& mdpFlags,
         const eTransform& orient, const int& downscale) {
-    Dim rotCrop(crop.left, crop.top, (crop.right - crop.left),
-        (crop.bottom - crop.top));
+
     rot->setSource(whf);
-    rot->setCrop(rotCrop);
+
+    if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
+        qdutils::MDSS_V5) {
+        uint32_t crop_w = (crop.right - crop.left);
+        uint32_t crop_h = (crop.bottom - crop.top);
+        if (ovutils::isYuv(whf.format)) {
+            ovutils::normalizeCrop((uint32_t&)crop.left, crop_w);
+            ovutils::normalizeCrop((uint32_t&)crop.top, crop_h);
+            // For interlaced, crop.h should be 4-aligned
+            if ((mdpFlags & ovutils::OV_MDP_DEINTERLACE) && (crop_h % 4))
+                crop_h = ovutils::aligndown(crop_h, 4);
+            crop.right = crop.left + crop_w;
+            crop.bottom = crop.top + crop_h;
+        }
+        Dim rotCrop(crop.left, crop.top, crop_w, crop_h);
+        rot->setCrop(rotCrop);
+    }
+
     rot->setFlags(mdpFlags);
     rot->setTransform(orient);
     rot->setDownscale(downscale);
@@ -668,7 +786,7 @@
     return 0;
 }
 
-static inline int configMdp(Overlay *ov, const PipeArgs& parg,
+int configMdp(Overlay *ov, const PipeArgs& parg,
         const eTransform& orient, const hwc_rect_t& crop,
         const hwc_rect_t& pos, const MetaData_t *metadata,
         const eDest& dest) {
@@ -694,7 +812,7 @@
     return 0;
 }
 
-static inline void updateSource(eTransform& orient, Whf& whf,
+void updateSource(eTransform& orient, Whf& whf,
         hwc_rect_t& crop) {
     Dim srcCrop(crop.left, crop.top,
             crop.right - crop.left,
@@ -720,8 +838,8 @@
 }
 
 int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
-        const int& dpy, eMdpFlags& mdpFlags, const eZorder& z,
-        const eIsFg& isFg, const eDest& dest, Rotator **rot) {
+        const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
+        eIsFg& isFg, const eDest& dest, Rotator **rot) {
 
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if(!hnd) {
@@ -740,6 +858,43 @@
     Whf whf(hnd->width, hnd->height,
             getMdpFormat(hnd->format), hnd->size);
 
+    if(dpy && isYuvBuffer(hnd)) {
+        if(!ctx->listStats[dpy].isDisplayAnimating) {
+            ctx->mPrevCropVideo = crop;
+            ctx->mPrevDestVideo = dst;
+            ctx->mPrevTransformVideo = transform;
+        } else {
+            // Restore the previous crop, dest rect and transform values, during
+            // animation to avoid displaying videos at random coordinates.
+            crop = ctx->mPrevCropVideo;
+            dst = ctx->mPrevDestVideo;
+            transform = ctx->mPrevTransformVideo;
+            orient = static_cast<eTransform>(transform);
+            //In you tube use case when a device rotated from landscape to
+            // portrait, set the isFg flag and zOrder to avoid displaying UI on
+            // hdmi during animation
+            if(ctx->deviceOrientation) {
+                isFg = ovutils::IS_FG_SET;
+                z = ZORDER_1;
+            }
+        }
+    }
+
+    uint32_t x = dst.left, y  = dst.right;
+    uint32_t w = dst.right - dst.left;
+    uint32_t h = dst.bottom - dst.top;
+
+    if(dpy && ctx->mExtOrientation) {
+        // Just need to set the position to portrait as the transformation
+        // will already be set to required orientation on TV
+        getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, x, y, w, h);
+        // Convert position to hwc_rect_t
+        dst.left = x;
+        dst.top = y;
+        dst.right = w + dst.left;
+        dst.bottom = h + dst.top;
+    }
+
     if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
        ctx->mMDP.version < qdutils::MDSS_V5) {
         downscale =  getDownscaleFactor(
@@ -752,16 +907,18 @@
         }
     }
 
-    setMdpFlags(layer, mdpFlags, downscale);
+    setMdpFlags(layer, mdpFlags, downscale, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
     if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
             ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
         *rot = ctx->mRotMgr->getNext();
         if(*rot == NULL) return -1;
+        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__);
+            ctx->mOverlay->clear(dpy);
             return -1;
         }
         whf.format = (*rot)->getDstFormat();
@@ -772,7 +929,6 @@
     //For the mdp, since either we are pre-rotating or MDP does flips
     orient = OVERLAY_TRANSFORM_0;
     transform = 0;
-
     PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(rotFlags));
     if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
         ALOGE("%s: commit failed for low res panel", __FUNCTION__);
@@ -782,8 +938,8 @@
 }
 
 int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
-        const int& dpy, eMdpFlags& mdpFlagsL, const eZorder& z,
-        const eIsFg& isFg, const eDest& lDest, const eDest& rDest,
+        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) {
@@ -805,7 +961,30 @@
     Whf whf(hnd->width, hnd->height,
             getMdpFormat(hnd->format), hnd->size);
 
-    setMdpFlags(layer, mdpFlagsL);
+    if(dpy && isYuvBuffer(hnd)) {
+        if(!ctx->listStats[dpy].isDisplayAnimating) {
+            ctx->mPrevCropVideo = crop;
+            ctx->mPrevDestVideo = dst;
+            ctx->mPrevTransformVideo = transform;
+        } else {
+            // Restore the previous crop, dest rect and transform values, during
+            // animation to avoid displaying videos at random coordinates.
+            crop = ctx->mPrevCropVideo;
+            dst = ctx->mPrevDestVideo;
+            transform = ctx->mPrevTransformVideo;
+            orient = static_cast<eTransform>(transform);
+            //In you tube use case when a device rotated from landscape to
+            // portrait, set the isFg flag and zOrder to avoid displaying UI on
+            // hdmi during animation
+            if(ctx->deviceOrientation) {
+                isFg = ovutils::IS_FG_SET;
+                z = ZORDER_1;
+            }
+        }
+    }
+
+
+    setMdpFlags(layer, mdpFlagsL, 0, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
     if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
@@ -814,6 +993,7 @@
         //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;
         }
         whf.format = (*rot)->getDstFormat();
@@ -844,7 +1024,7 @@
     //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_V) && lDest != OV_INVALID
-            && rDest != OV_INVALID && rot == NULL) {
+            && 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);
@@ -880,8 +1060,8 @@
     if(rDest != OV_INVALID) {
         PipeArgs pargR(mdpFlagsR, whf, z, isFg,
                 static_cast<eRotFlags>(rotFlags));
-        tmp_dstR.right = tmp_dstR.right - tmp_dstR.left;
-        tmp_dstR.left = 0;
+        tmp_dstR.right = tmp_dstR.right - hw_w/2;
+        tmp_dstR.left = tmp_dstR.left - hw_w/2;
         if(configMdp(ctx->mOverlay, pargR, orient,
                 tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
@@ -891,4 +1071,54 @@
 
     return 0;
 }
+
+bool canUseRotator(hwc_context_t *ctx) {
+    if(qdutils::MDPVersion::getInstance().is8x26() &&
+            ctx->mExtDisplay->isExternalConnected()) {
+        return false;
+    }
+    if(ctx->mMDP.version == qdutils::MDP_V3_0_4)
+        return false;
+    return true;
+}
+
+
+void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
+            const hwc_rect_t& dst, const int& transform,
+            ovutils::eMdpFlags& mdpFlags) {
+    //Target doesnt support Bwc
+    if(!qdutils::MDPVersion::getInstance().supportsBWC()) {
+        return;
+    }
+    //src width > MAX mixer supported dim
+    if((crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
+        return;
+    }
+    //External connected
+    if(ctx->mExtDisplay->isExternalConnected()) {
+        return;
+    }
+    //Decimation necessary, cannot use BWC. H/W requirement.
+    if(qdutils::MDPVersion::getInstance().supportsDecimation()) {
+        int src_w = crop.right - crop.left;
+        int src_h = crop.bottom - crop.top;
+        int dst_w = dst.right - dst.left;
+        int dst_h = dst.bottom - dst.top;
+        if(transform & HAL_TRANSFORM_ROT_90) {
+            swap(src_w, src_h);
+        }
+        float horDscale = 0.0f;
+        float verDscale = 0.0f;
+        ovutils::getDecimationFactor(src_w, src_h, dst_w, dst_h, horDscale,
+                verDscale);
+        if(horDscale || verDscale) return;
+    }
+    //Property
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.disable.bwc", value, "0");
+     if(atoi(value)) return;
+
+    ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDSS_MDP_BWC_EN);
+}
+
 };//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index e0fff77..729a649 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -91,8 +91,12 @@
     //Video specific
     int yuvCount;
     int yuvIndices[MAX_NUM_LAYERS];
+    int extOnlyLayerIndex;
     bool needsAlphaScale;
     bool preMultipliedAlpha;
+    // Notifies hwcomposer about the start and end of animation
+    // This will be set to true during animation, otherwise false.
+    bool isDisplayAnimating;
 };
 
 struct LayerProp {
@@ -100,6 +104,17 @@
     LayerProp():mFlags(0) {};
 };
 
+struct VsyncState {
+    bool enable;
+    bool fakevsync;
+};
+
+struct BwcPM {
+    static void setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
+            const hwc_rect_t& dst, const int& transform,
+            ovutils::eMdpFlags& mdpFlags);
+};
+
 // LayerProp::flag values
 enum {
     HWC_MDPCOMP = 0x00000001,
@@ -121,7 +136,7 @@
 bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
 bool isSecureModePolicy(int mdpVersion);
 bool isExternalActive(hwc_context_t* ctx);
-bool needsScaling(hwc_layer_1_t const* layer);
+bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer, const int& dpy);
 bool isAlphaPresent(hwc_layer_1_t const* layer);
 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
 
@@ -132,6 +147,10 @@
 void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
                                         uint32_t& y, uint32_t& w, uint32_t& h);
 
+
+void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
+                        uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h);
+
 //Close acquireFenceFds of all layers of incoming list
 void closeAcquireFds(hwc_display_contents_1_t* list);
 
@@ -146,20 +165,40 @@
 //Sets appropriate mdp flags for a layer.
 void setMdpFlags(hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
-        int rotDownscale = 0);
+        int rotDownscale, int transform);
+
+int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
+        hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
+        const ovutils::eTransform& orient, const int& downscale);
+
+int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg,
+        const ovutils::eTransform& orient, const hwc_rect_t& crop,
+        const hwc_rect_t& pos, const MetaData_t *metadata,
+        const ovutils::eDest& dest);
+
+void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
+        hwc_rect_t& crop);
 
 //Routine to configure low resolution panels (<= 2048 width)
 int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
-        ovutils::eMdpFlags& mdpFlags, const ovutils::eZorder& z,
-        const ovutils::eIsFg& isFg, const ovutils::eDest& dest,
+        ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+        ovutils::eIsFg& isFg, const ovutils::eDest& dest,
         overlay::Rotator **rot);
 
 //Routine to configure high resolution panels (> 2048 width)
 int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
-        ovutils::eMdpFlags& mdpFlags, const ovutils::eZorder& z,
-        const ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
+        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
+//extreme unavailability of pipes. This can also be done via hybrid calculations
+//also involving many more variables like number of write-back interfaces etc,
+//but the variety of scenarios is too high to warrant that.
+bool canUseRotator(hwc_context_t *ctx);
+
 // Inline utility functions
 static inline bool isSkipLayer(const hwc_layer_1_t* l) {
     return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
@@ -228,13 +267,6 @@
 
 }; //qhwc namespace
 
-struct vsync_state {
-    pthread_mutex_t lock;
-    pthread_cond_t  cond;
-    bool enable;
-    bool fakevsync;
-};
-
 // -----------------------------------------------------------------------------
 // HWC context
 // This structure contains overall state
@@ -255,12 +287,21 @@
     // External display related information
     qhwc::ExternalDisplay *mExtDisplay;
     qhwc::MDPInfo mMDP;
+    qhwc::VsyncState vstate;
     qhwc::DisplayAttributes dpyAttr[MAX_DISPLAYS];
     qhwc::ListStats listStats[MAX_DISPLAYS];
     qhwc::LayerProp *layerProp[MAX_DISPLAYS];
     qhwc::MDPComp *mMDPComp[MAX_DISPLAYS];
     qhwc::HwcDebug *mHwcDebug[MAX_DISPLAYS];
 
+    // No animation on External display feature
+    // Notifies hwcomposer about the device orientation before animation.
+    int deviceOrientation;
+    // Stores the crop, dest rect and transform value of video before animation.
+    hwc_rect_t mPrevCropVideo;
+    hwc_rect_t mPrevDestVideo;
+    int mPrevTransformVideo;
+
     //Securing in progress indicator
     bool mSecuring;
     //External Display configuring progress indicator
@@ -269,12 +310,12 @@
     bool mSecureMode;
     //Lock to prevent set from being called while blanking
     mutable Locker mBlankLock;
-    //Lock to protect set when detaching external disp
-    mutable Locker mExtSetLock;
-    //Vsync
-    struct vsync_state vstate;
+    //Lock to protect prepare & set when detaching external disp
+    mutable Locker mExtLock;
     //Drawing round when we use GPU
     bool isPaddingRound;
+    // External Orientation
+    int mExtOrientation;
 };
 
 namespace qhwc {
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index b42043f..c0a33c1 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -60,7 +60,6 @@
                 android::PRIORITY_MORE_FAVORABLE);
 
     const int MAX_DATA = 64;
-    const int MAX_RETRY_COUNT = 100;
     static char vdata[MAX_DATA];
 
     uint64_t cur_timestamp=0;
@@ -86,6 +85,8 @@
        */
     fd_timestamp = open(vsync_timestamp_fb0, O_RDONLY);
     if (fd_timestamp < 0) {
+        // Make sure fb device is opened before starting this thread so this
+        // never happens.
         ALOGE ("FATAL:%s:not able to open file:%s, %s",  __FUNCTION__,
                (fb1_vsync) ? vsync_timestamp_fb1 : vsync_timestamp_fb0,
                strerror(errno));
@@ -93,46 +94,27 @@
     }
 
     do {
-        pthread_mutex_lock(&ctx->vstate.lock);
-        while (ctx->vstate.enable == false) {
-            pthread_cond_wait(&ctx->vstate.cond, &ctx->vstate.lock);
-        }
-        pthread_mutex_unlock(&ctx->vstate.lock);
-
-        if (!ctx->vstate.fakevsync) {
-            for(int i = 0; i < MAX_RETRY_COUNT; i++) {
-                len = pread(fd_timestamp, vdata, MAX_DATA, 0);
-                if(len < 0 && (errno == EAGAIN ||
-                               errno == EINTR  ||
-                               errno == EBUSY)) {
-                    ALOGW("%s: vsync read: %s, retry (%d/%d).",
-                          __FUNCTION__, strerror(errno), i, MAX_RETRY_COUNT);
-                    continue;
-                } else {
-                    break;
-                }
-            }
-
+        if (LIKELY(!ctx->vstate.fakevsync)) {
+            len = pread(fd_timestamp, vdata, MAX_DATA, 0);
             if (len < 0) {
-                ALOGE ("FATAL:%s:not able to read file:%s, %s", __FUNCTION__,
-                       vsync_timestamp_fb0, strerror(errno));
-                close (fd_timestamp);
-                ctx->vstate.fakevsync = true;
+                // If the read was just interrupted - it is not a fatal error
+                // In either case, just continue.
+                if (errno != EAGAIN &&
+                    errno != EINTR  &&
+                    errno != EBUSY) {
+                    ALOGE ("FATAL:%s:not able to read file:%s, %s",
+                           __FUNCTION__,
+                           vsync_timestamp_fb0, strerror(errno));
+                }
+                continue;
             }
-
             // extract timestamp
             const char *str = vdata;
             if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
                 cur_timestamp = strtoull(str + strlen("VSYNC="), NULL, 0);
-            } else {
-                ALOGE ("FATAL: %s: vsync timestamp not in correct format: [%s]",
-                       __FUNCTION__,
-                       str);
-                ctx->vstate.fakevsync = true;
             }
-
         } else {
-            usleep(16000);
+            usleep(16666);
             cur_timestamp = systemTime();
         }
         // send timestamp to HAL
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 8aca0f6..a15d0a8 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -143,11 +143,15 @@
         ret = true;
         PipeBook::setUse((int)dest);
     } else {
-        PipeBook::resetUse((int)dest);
         int dpy = mPipeBook[index].mDisplay;
         for(int i = 0; i < PipeBook::NUM_PIPES; i++)
-            if (mPipeBook[i].mDisplay == dpy)
+            if (mPipeBook[i].mDisplay == dpy) {
                 PipeBook::resetAllocation(i);
+                PipeBook::resetUse(i);
+                if(mPipeBook[i].valid()) {
+                    mPipeBook[i].mPipe->forceSet();
+                }
+            }
     }
     return ret;
 }
@@ -243,7 +247,7 @@
         }
     }
 
-    if (mdpVersion < qdutils::MDSS_V5) {
+    if (mdpVersion < qdutils::MDSS_V5 && mdpVersion != qdutils::MDP_V3_0_4) {
         msmfb_mixer_info_req  req;
         mdp_mixer_info *minfo = NULL;
         char name[64];
@@ -311,6 +315,19 @@
     strncat(buf, str_pipes, strlen(str_pipes));
 }
 
+void Overlay::clear(int dpy) {
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if (mPipeBook[i].mDisplay == dpy) {
+            // Mark as available for this round
+            PipeBook::resetUse(i);
+            PipeBook::resetAllocation(i);
+            if(mPipeBook[i].valid()) {
+                mPipeBook[i].mPipe->forceSet();
+            }
+        }
+    }
+}
+
 void Overlay::PipeBook::init() {
     mPipe = NULL;
     mDisplay = DPY_UNUSED;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index bf85b70..cfceaff 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -90,6 +90,8 @@
      * to populate.
      */
     void getDump(char *buf, size_t len);
+    /* Reset usage and allocation bits on all pipes for given display */
+    void clear(int dpy);
     static void setDMAMode(const int& mode);
     static int getDMAMode();
 
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 513ebb9..c3a7aa3 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -85,6 +85,7 @@
     void dump() const;
     /* Return the dump in the specified buffer */
     void getDump(char *buf, size_t len);
+    void forceSet();
 
 private:
     // mdp ctrl struct(info e.g.)
@@ -224,6 +225,10 @@
     mMdp.getDump(buf, len);
 }
 
+inline void Ctrl::forceSet() {
+    mMdp.forceSet();
+}
+
 inline Data::Data() {
     mMdp.reset();
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 4578115..71e7e5b 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -37,20 +37,6 @@
 namespace ovutils = overlay::utils;
 namespace overlay {
 
-//Helper to even out x,w and y,h pairs
-//x,y are always evened to ceil and w,h are evened to floor
-static void normalizeCrop(uint32_t& xy, uint32_t& wh) {
-    if(xy & 1) {
-        utils::even_ceil(xy);
-        if(wh & 1)
-            utils::even_floor(wh);
-        else
-            wh -= 2;
-    } else {
-        utils::even_floor(wh);
-    }
-}
-
 bool MdpCtrl::init(uint32_t fbnum) {
     // FD init
     if(!utils::openDev(mFd, fbnum,
@@ -68,6 +54,7 @@
     mLkgo.id = MSMFB_NEW_REQUEST;
     mOrientation = utils::OVERLAY_TRANSFORM_0;
     mDownscale = 0;
+    mForceSet = false;
 #ifdef USES_POST_PROCESSING
     mPPChanged = false;
     memset(&mParams, 0, sizeof(struct compute_params));
@@ -157,19 +144,11 @@
             minHorDeci = 2;
         }
 
-        float horDscale = ceilf((float)mOVInfo.src_rect.w /
-                (float)mOVInfo.dst_rect.w);
-        float verDscale = ceilf((float)mOVInfo.src_rect.h /
-                (float)mOVInfo.dst_rect.h);
+        float horDscale = 0.0f;
+        float verDscale = 0.0f;
 
-        //Next power of 2, if not already
-        horDscale = powf(2.0f, ceilf(log2f(horDscale)));
-        verDscale = powf(2.0f, ceilf(log2f(verDscale)));
-
-        //Since MDP can do 1/4 dscale and has better quality, split the task
-        //between decimator and MDP downscale
-        horDscale /= 4.0f;
-        verDscale /= 4.0f;
+        utils::getDecimationFactor(mOVInfo.src_rect.w, mOVInfo.src_rect.h,
+                mOVInfo.dst_rect.w, mOVInfo.dst_rect.h, horDscale, verDscale);
 
         if(horDscale < minHorDeci)
             horDscale = minHorDeci;
@@ -189,15 +168,21 @@
     doDownscale();
     utils::Whf whf = getSrcWhf();
     if(utils::isYuv(whf.format)) {
-        normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
-        normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
+        utils::normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
+        utils::normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
         if(mdpVersion < MDSS_V5) {
             utils::even_floor(mOVInfo.dst_rect.w);
             utils::even_floor(mOVInfo.dst_rect.h);
+        } else if (mOVInfo.flags & MDP_DEINTERLACE) {
+            // For interlaced, crop.h should be 4-aligned
+            if (!(mOVInfo.flags & MDP_SOURCE_ROTATED_90) &&
+                (mOVInfo.src_rect.h % 4))
+                mOVInfo.src_rect.h = utils::aligndown(mOVInfo.src_rect.h, 4);
         }
     }
 
-    if(this->ovChanged()) {
+    if(this->ovChanged() || mForceSet) {
+        mForceSet = false;
         if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
             ALOGE("MdpCtrl failed to setOverlay, restoring last known "
                   "good ov info");
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index f77ffae..056d982 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -81,6 +81,7 @@
     utils::Dim getSrcRectDim() const;
     /* setVisualParam */
     bool setVisualParams(const MetaData_t& data);
+    void forceSet();
 
 private:
     /* Perform transformation calculations */
@@ -125,6 +126,8 @@
     /* FD for the mdp fbnum */
     OvFD          mFd;
     int mDownscale;
+    bool mForceSet;
+
 #ifdef USES_POST_PROCESSING
     /* PP Compute Params */
     struct compute_params mParams;
@@ -319,6 +322,10 @@
         mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
 }
 
+inline void MdpCtrl::forceSet() {
+    mForceSet = true;
+}
+
 ///////    MdpCtrl3D //////
 
 inline MdpCtrl3D::MdpCtrl3D() { reset(); }
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 1fabdca..30d7ccd 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -20,6 +20,8 @@
 #include "overlayUtils.h"
 #include "overlayRotator.h"
 
+#define DEBUG_MDSS_ROT 0
+
 #ifdef VENUS_COLOR_FORMAT
 #include <media/msm_media_info.h>
 #else
@@ -94,7 +96,7 @@
 void MdssRot::setDownscale(int ds) {}
 
 void MdssRot::setFlags(const utils::eMdpFlags& flags) {
-    mRotInfo.flags |= flags;
+    mRotInfo.flags = flags;
 }
 
 void MdssRot::setTransform(const utils::eTransform& rot)
@@ -109,6 +111,7 @@
 }
 
 void MdssRot::doTransform() {
+    mRotInfo.flags |= mOrientation;
     if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
         utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
 }
@@ -252,7 +255,11 @@
     ovutils::Whf destWhf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h,
             mRotInfo.src.format); //mdss src and dst formats are same.
 
-    opBufSize = Rotator::calcOutputBufSize(destWhf);
+    if (mRotInfo.flags & ovutils::OV_MDSS_MDP_BWC_EN) {
+        opBufSize = calcCompressedBufSize();
+    } else {
+        opBufSize = Rotator::calcOutputBufSize(destWhf);
+    }
 
     if (mRotInfo.flags & utils::OV_MDP_SECURE_OVERLAY_SESSION)
         opBufSize = utils::align(opBufSize, SIZE_1M);
@@ -265,4 +272,23 @@
     ovutils::getDump(buf, len, "MdssRotData", mRotData);
 }
 
+// Calculate the compressed o/p buffer size for BWC
+uint32_t MdssRot::calcCompressedBufSize() {
+    uint32_t bufSize = 0;
+    int aWidth = ovutils::align(mRotInfo.src_rect.w, 64);
+    int aHeight = ovutils::align(mRotInfo.src_rect.h, 4);
+    int rau_cnt = aWidth/64;
+    int stride0 = (64 * 4 * rau_cnt) + rau_cnt/8;
+    int stride1 = (64 * 2 * rau_cnt) + rau_cnt/8;
+    int stride0_off = (aHeight/4);
+    int stride1_off = (aHeight/2);
+
+    //New o/p size for BWC
+    bufSize = (stride0 * stride0_off + stride1 * stride1_off) +
+                (rau_cnt * 2 * (stride0_off + stride1_off));
+    ALOGD_IF(DEBUG_MDSS_ROT, "%s: width = %d, height = %d raucount = %d"
+         "opBufSize = %d ", __FUNCTION__, aWidth, aHeight, rau_cnt, bufSize);
+    return bufSize;
+}
+
 } // namespace overlay
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index c02dfba..120721c 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -198,6 +198,8 @@
     /* Calculates the rotator's o/p buffer size post the transform calcs and
      * knowing the o/p format depending on whether fastYuv is enabled or not */
     uint32_t calcOutputBufSize();
+    // Calculate the compressed o/p buffer size for BWC
+    uint32_t calcCompressedBufSize();
 
     /* MdssRot info structure */
     mdp_overlay   mRotInfo;
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index e595cef..9bfa34e 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -244,6 +244,27 @@
     return dscale_factor;
 }
 
+//Since this is unavailable on Android, defining it in terms of base 10
+static inline float log2f(const float& x) {
+    return log(x) / log(2);
+}
+
+void getDecimationFactor(const int& src_w, const int& src_h,
+        const int& dst_w, const int& dst_h, float& horDscale,
+        float& verDscale) {
+    horDscale = ceilf((float)src_w / (float)dst_w);
+    verDscale = ceilf((float)src_h / (float)dst_h);
+
+    //Next power of 2, if not already
+    horDscale = powf(2.0f, ceilf(log2f(horDscale)));
+    verDscale = powf(2.0f, ceilf(log2f(verDscale)));
+
+    //Since MDP can do 1/4 dscale and has better quality, split the task
+    //between decimator and MDP downscale
+    horDscale /= 4.0f;
+    verDscale /= 4.0f;
+}
+
 static inline int compute(const uint32_t& x, const uint32_t& y,
         const uint32_t& z) {
     return x - ( y + z );
@@ -428,6 +449,20 @@
     getDump(buf, len, "\tdst", rot.dst);
 }
 
+//Helper to even out x,w and y,h pairs
+//x,y are always evened to ceil and w,h are evened to floor
+void normalizeCrop(uint32_t& xy, uint32_t& wh) {
+    if(xy & 1) {
+        even_ceil(xy);
+        if(wh & 1)
+            even_floor(wh);
+        else
+            wh -= 2;
+    } else {
+        even_floor(wh);
+    }
+}
+
 } // utils
 
 } // overlay
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index ceb238d..4bb2151 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -143,6 +143,7 @@
 bool enableBarrier (uint32_t orientation);
 uint32_t getS3DFormat(uint32_t fmt);
 bool isMdssRotator();
+void normalizeCrop(uint32_t& xy, uint32_t& wh);
 
 template <int CHAN>
 bool getPositionS3D(const Whf& whf, Dim& out);
@@ -262,6 +263,7 @@
     OV_MDP_FLIP_V = MDP_FLIP_UD,
     OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER,
     OV_MDP_PP_EN = MDP_OVERLAY_PP_CFG_EN,
+    OV_MDSS_MDP_BWC_EN = MDP_BWC_EN,
 };
 
 enum eZorder {
@@ -391,6 +393,9 @@
 int getHALFormat(int mdpFormat);
 int getDownscaleFactor(const int& src_w, const int& src_h,
         const int& dst_w, const int& dst_h);
+void getDecimationFactor(const int& src_w, const int& src_h,
+        const int& dst_w, const int& dst_h, float& horDscale,
+        float& verDscale);
 
 /* flip is upside down and such. V, H flip
  * rotation is 90, 180 etc
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 90697a7..f5d4475 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -236,5 +236,8 @@
     return true;
 }
 
+void GenericPipe::forceSet() {
+    mCtrlData.ctrl.forceSet();
+}
 
 } //namespace overlay
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 63ffd32..5463eb8 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -74,6 +74,10 @@
     void dump() const;
     /* Return the dump in the specified buffer */
     void getDump(char *buf, size_t len);
+    /* Marks the pipe for forcible setting of params
+     * even if they haven't changed
+     */
+    void forceSet();
 
 private:
     /* set Closed pipe */
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 8da293d..cac6b1d 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -85,21 +85,30 @@
                 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;
+                }
             }
 #endif
         } else {
             mdp_version = MDP_V_UNKNOWN;
         }
-        int len = strlen("msmfbXX_");
-        if (mdp_version == MDP_V3_0_3)
-            len++;
-        panel_type = fb_finfo.id[len];
+
+        /* Assumes panel type is 2nd element in '_' delimited id string */
+        char * ptype = strstr(fb_finfo.id, "_");
+        if (!ptype || (*(++ptype) == '\0')) {
+            ALOGE("Invalid framebuffer info string: %s", fb_finfo.id);
+            ptype = fb_finfo.id;
+        }
+        panel_type = *ptype;
 
     }
     close(fb_fd);
     mMDPVersion = mdp_version;
     mHasOverlay = false;
-    if((mMDPVersion >= MDP_V4_0) || (mMDPVersion == MDP_V_UNKNOWN))
+    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
@@ -117,5 +126,14 @@
     return mMDPDownscale;
 }
 
+bool MDPVersion::supportsBWC() {
+    // BWC - Bandwidth Compression
+    return (mFeatures & MDP_BWC_EN);
+}
+
+bool MDPVersion::is8x26() {
+    return mMdpRev == MDSS_MDP_HW_REV_101;
+}
+
 }; //namespace qdutils
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 2fca640..f7b16fa 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -43,6 +43,7 @@
     MDP_V2_2    = 220,
     MDP_V3_0    = 300,
     MDP_V3_0_3  = 303,
+    MDP_V3_0_4  = 304,
     MDP_V3_1    = 310,
     MDP_V4_0    = 400,
     MDP_V4_1    = 410,
@@ -52,6 +53,12 @@
     MDSS_V5     = 500,
 };
 
+enum mdp_rev {
+    MDSS_MDP_HW_REV_100 = 0x10000000,
+    MDSS_MDP_HW_REV_101 = 0x10010000, //8x26
+    MDSS_MDP_HW_REV_102 = 0x10020000,
+};
+
 enum {
     MAX_DISPLAY_DIM = 2048,
 };
@@ -82,6 +89,8 @@
     uint8_t getDMAPipes() { return mDMAPipes; }
     bool supportsDecimation();
     uint32_t getMaxMDPDownscale();
+    bool supportsBWC();
+    bool is8x26();
 private:
     int mMDPVersion;
     char mPanelType;
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index cc7e44a..1316e59 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -75,6 +75,9 @@
         case PP_PARAM_SHARP2:
             memcpy((void *)&data->Sharp2Data, param, sizeof(Sharp2Data_t));
             break;
+        case PP_PARAM_TIMESTAMP:
+            data->timestamp = *((int64_t *)param);
+            break;
         default:
             ALOGE("Unknown paramType %d", paramType);
             break;
diff --git a/libqdutils/qdMetaData.h b/libqdutils/qdMetaData.h
index bbca4b6..9f10cf8 100644
--- a/libqdutils/qdMetaData.h
+++ b/libqdutils/qdMetaData.h
@@ -60,6 +60,7 @@
     int32_t video_interface;
     IGCData_t igcData;
     Sharp2Data_t Sharp2Data;
+    int64_t timestamp;
 };
 
 typedef enum {
@@ -69,6 +70,7 @@
     PP_PARAM_VID_INTFC  = 0x0008,
     PP_PARAM_IGC        = 0x0010,
     PP_PARAM_SHARP2     = 0x0020,
+    PP_PARAM_TIMESTAMP  = 0x0040
 } DispParamType;
 
 int setMetaData(private_handle_t *handle, DispParamType paramType, void *param);
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index 53b05e3..af11f88 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -71,6 +71,13 @@
         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);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 79e831d..ff034be 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -41,6 +41,7 @@
         UNSECURING, // Hardware unsecuring start/end notification
         CONNECT,
         SCREEN_REFRESH,
+        EXTERNAL_ORIENTATION,
     };
     enum {
         END = 0,
@@ -50,6 +51,7 @@
     virtual void unsecuring(uint32_t startEnd) = 0;
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
     virtual android::status_t screenRefresh() = 0;
+    virtual void setExtOrientation(uint32_t orientation) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 54e285c..f780a75 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -71,6 +71,12 @@
     return result;
 }
 
+void QService::setExtOrientation(uint32_t orientation) {
+    if(mClient.get()) {
+        mClient->notifyCallback(EXTERNAL_ORIENTATION, orientation);
+    }
+}
+
 void QService::init()
 {
     if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index 268bf81..8eefa21 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -49,6 +49,7 @@
     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);
     static void init();
 private:
     QService();