Merge "libexternal: set hw.hdmiON system property"
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 669ea08..57c6bae 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -62,8 +62,7 @@
         return false;
     if(triedSystem)
         return false;
-    if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED |
-                GRALLOC_USAGE_PRIVATE_CP_BUFFER))
+    if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED))
         return false;
     if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY))
         return false;
@@ -124,7 +123,7 @@
     if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP)
         ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID);
 
-    if(usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER)
+    if(usage & GRALLOC_USAGE_PROTECTED)
         ionFlags |= ION_SECURE;
 
     // if no flags are set, default to
diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp
index 5293ca9..961d2b6 100644
--- a/libgralloc/framebuffer.cpp
+++ b/libgralloc/framebuffer.cpp
@@ -84,20 +84,6 @@
     return 0;
 }
 
-static int fb_setUpdateRect(struct framebuffer_device_t* dev,
-                            int l, int t, int w, int h)
-{
-    if (((w|h) <= 0) || ((l|t)<0))
-        return -EINVAL;
-    fb_context_t* ctx = (fb_context_t*)dev;
-    private_module_t* m = reinterpret_cast<private_module_t*>(
-        dev->common.module);
-    m->info.reserved[0] = 0x54445055; // "UPDT";
-    m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
-    m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
-    return 0;
-}
-
 static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
 {
 
@@ -421,11 +407,7 @@
             const_cast<int&>(dev->device.maxSwapInterval) =
                                                         PRIV_MAX_SWAP_INTERVAL;
             const_cast<int&>(dev->device.numFramebuffers) = m->numBuffers;
-            if (m->finfo.reserved[0] == 0x5444 &&
-                m->finfo.reserved[1] == 0x5055) {
-                dev->device.setUpdateRect = fb_setUpdateRect;
-                ALOGD("UPDATE_ON_DEMAND supported");
-            }
+            dev->device.setUpdateRect = 0;
 
             *device = &dev->device.common;
         }
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 0d070f0..291f564 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -252,8 +252,7 @@
     // All buffers marked as protected or for external
     // display need to go to overlay
     if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) ||
-        (usage & GRALLOC_USAGE_PROTECTED) ||
-        (usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER)) {
+        (usage & GRALLOC_USAGE_PROTECTED)) {
         bufferType = BUFFER_TYPE_VIDEO;
     }
 
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index ba84580..84b1100 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -125,7 +125,6 @@
         hwc_display_contents_1_t *list) {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     const int dpy = HWC_DISPLAY_PRIMARY;
-
     if (LIKELY(list && list->numHwLayers > 1) &&
         ctx->dpyAttr[dpy].isActive) {
 
@@ -306,14 +305,14 @@
     int ret = 0;
     const int dpy = HWC_DISPLAY_PRIMARY;
 
-    if (LIKELY(list && list->numHwLayers > 1) &&
-        ctx->dpyAttr[dpy].isActive) {
+    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) {
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         int fd = -1; //FenceFD from the Copybit(valid in async mode)
         if(ctx->mCopyBit[dpy])
             ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
-        hwc_sync(ctx, list, dpy, fd);
+        if(list->numHwLayers > 1)
+            hwc_sync(ctx, list, dpy, fd);
         if (!VideoOverlay::draw(ctx, list, dpy)) {
             ALOGE("%s: VideoOverlay::draw fail!", __FUNCTION__);
             ret = -1;
@@ -327,7 +326,8 @@
         //always. Last layer is always FB
         private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
         if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET && hnd) {
-            if(!(fbLayer->flags & HWC_SKIP_LAYER)) {
+            if(!(fbLayer->flags & HWC_SKIP_LAYER) &&
+                (list->numHwLayers > 1)) {
                 if (!ctx->mFBUpdate[dpy]->draw(ctx, fbLayer)) {
                     ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                     ret = -1;
@@ -349,8 +349,7 @@
 
     Locker::Autolock _l(ctx->mExtSetLock);
 
-    if (LIKELY(list && list->numHwLayers > 1) &&
-        ctx->dpyAttr[dpy].isActive &&
+    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
         ctx->dpyAttr[dpy].connected) {
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
@@ -358,7 +357,8 @@
         if(ctx->mCopyBit[dpy])
             ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
 
-        hwc_sync(ctx, list, dpy, fd);
+        if(list->numHwLayers > 1)
+            hwc_sync(ctx, list, dpy, fd);
 
         if (!VideoOverlay::draw(ctx, list, dpy)) {
             ALOGE("%s: VideoOverlay::draw fail!", __FUNCTION__);
@@ -367,7 +367,8 @@
 
         private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
         if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET &&
-                !(fbLayer->flags & HWC_SKIP_LAYER) && hnd) {
+                !(fbLayer->flags & HWC_SKIP_LAYER) && hnd &&
+                (list->numHwLayers > 1)) {
             if (!ctx->mFBUpdate[dpy]->draw(ctx, fbLayer)) {
                 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ecbf813..e0331ad 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -89,7 +89,7 @@
                 info,
                 ovutils::ZORDER_0,
                 ovutils::IS_FG_SET,
-                ovutils::ROT_FLAG_DISABLED);
+                ovutils::ROT_FLAGS_NONE);
         ov.setSource(parg, dest);
 
         hwc_rect_t sourceCrop = layer->sourceCrop;
@@ -193,7 +193,7 @@
                 info,
                 ovutils::ZORDER_0,
                 ovutils::IS_FG_SET,
-                ovutils::ROT_FLAG_DISABLED);
+                ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargL, destL);
 
         ovutils::eMdpFlags mdpFlagsR = mdpFlagsL;
@@ -202,7 +202,7 @@
                 info,
                 ovutils::ZORDER_0,
                 ovutils::IS_FG_SET,
-                ovutils::ROT_FLAG_DISABLED);
+                ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargR, destR);
 
         hwc_rect_t sourceCrop = layer->sourceCrop;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 2e58b93..bbea007 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -20,6 +20,7 @@
 #include <sys/ioctl.h>
 #include "external.h"
 #include "qdMetaData.h"
+#include "mdp_version.h"
 
 namespace qhwc {
 
@@ -325,11 +326,17 @@
         orient = static_cast<ovutils::eTransform>(layer->transform);
     }
 
+    ovutils::eRotFlags rotFlags = ovutils::ROT_FLAGS_NONE;
+    if(isYuvBuffer(hnd) && (ctx->mMDP.version >= qdutils::MDP_V4_2 &&
+                           ctx->mMDP.version < qdutils::MDSS_V5)) {
+        rotFlags = ovutils::ROT_DOWNSCALE_ENABLED;
+    }
+
     ovutils::PipeArgs parg(mdpFlags,
             info,
             zOrder,
             ovutils::IS_FG_OFF,
-            ovutils::ROT_FLAG_DISABLED);
+            rotFlags);
 
     ov.setSource(parg, dest);
 
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 9cc5c24..7a3adbb 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -226,6 +226,12 @@
     return false;
 }
 
+bool isSecureModePolicy(int mdpVersion) {
+    if (mdpVersion < qdutils::MDSS_V5)
+        return true;
+    else
+        return false;
+}
 
 //Crops source buffer against destination and FB boundaries
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 0005582..5316347 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -130,6 +130,7 @@
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
         const int fbWidth, const int fbHeight, int orient);
 bool isSecuring(hwc_context_t* ctx);
+bool isSecureModePolicy(int mdpVersion);
 bool isExternalActive(hwc_context_t* ctx);
 
 //Helper function to dump logs
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index 16d0c89..41d4365 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -20,6 +20,7 @@
 #include "hwc_video.h"
 #include "hwc_utils.h"
 #include "qdMetaData.h"
+#include "mdp_version.h"
 
 namespace qhwc {
 
@@ -52,19 +53,20 @@
 
     //index guaranteed to be not -1 at this point
     hwc_layer_1_t *layer = &list->hwLayers[yuvIndex];
-
-    private_handle_t *hnd = (private_handle_t *)layer->handle;
-    if(ctx->mSecureMode) {
-        if (! isSecureBuffer(hnd)) {
-            ALOGD_IF(VIDEO_DEBUG, "%s: Handle non-secure video layer"
-                     "during secure playback gracefully", __FUNCTION__);
-            return false;
-        }
-    } else {
-        if (isSecureBuffer(hnd)) {
-            ALOGD_IF(VIDEO_DEBUG, "%s: Handle secure video layer"
-                     "during non-secure playback gracefully", __FUNCTION__);
-            return false;
+    if (isSecureModePolicy(ctx->mMDP.version)) {
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        if(ctx->mSecureMode) {
+            if (! isSecureBuffer(hnd)) {
+                ALOGD_IF(VIDEO_DEBUG, "%s: Handle non-secure video layer"
+                         "during secure playback gracefully", __FUNCTION__);
+                return false;
+            }
+        } else {
+            if (isSecureBuffer(hnd)) {
+                ALOGD_IF(VIDEO_DEBUG, "%s: Handle secure video layer"
+                         "during non-secure playback gracefully", __FUNCTION__);
+                return false;
+            }
         }
     }
     if(configure(ctx, dpy, layer)) {
@@ -118,11 +120,17 @@
         isFgFlag = ovutils::IS_FG_SET;
     }
 
+    ovutils::eRotFlags rotFlags = ovutils::ROT_FLAGS_NONE;
+    if(ctx->mMDP.version >= qdutils::MDP_V4_2 &&
+                ctx->mMDP.version < qdutils::MDSS_V5) {
+        rotFlags = ovutils::ROT_DOWNSCALE_ENABLED;
+    }
+
     ovutils::PipeArgs parg(mdpFlags,
             info,
             ovutils::ZORDER_1,
             isFgFlag,
-            ovutils::ROT_FLAG_DISABLED);
+            rotFlags);
 
     ov.setSource(parg, dest);
 
diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h
index 255ffd7..1f4a0be 100644
--- a/liboverlay/mdpWrapper.h
+++ b/liboverlay/mdpWrapper.h
@@ -243,9 +243,9 @@
     }
 }
 inline void dump(const char* const s, const msm_rotator_img_info& rot) {
-    ALOGE("%s msm_rotator_img_info sessid=%u dstx=%d dsty=%d rot=%d, ena=%d",
+    ALOGE("%s msm_rotator_img_info sessid=%u dstx=%d dsty=%d rot=%d, ena=%d scale=%d",
             s, rot.session_id, rot.dst_x, rot.dst_y,
-            rot.rotations, rot.enable);
+            rot.rotations, rot.enable, rot.downscale_ratio);
     dump("src", rot.src);
     dump("dst", rot.dst);
     dump("src_rect", rot.src_rect);
diff --git a/liboverlay/overlayCtrl.cpp b/liboverlay/overlayCtrl.cpp
index ac4a296..03d2564 100644
--- a/liboverlay/overlayCtrl.cpp
+++ b/liboverlay/overlayCtrl.cpp
@@ -57,15 +57,19 @@
     return true;
 }
 
-bool Ctrl::setTransform(const utils::eTransform& orient, const bool& rotUsed)
+bool Ctrl::setTransform(const utils::eTransform& orient)
 {
-    if(!mMdp.setTransform(orient, rotUsed)) {
+    if(!mMdp.setTransform(orient)) {
         ALOGE("Ctrl setTransform failed for Mdp");
         return false;
     }
     return true;
 }
 
+void Ctrl::setRotatorUsed(const bool& rotUsed) {
+    mMdp.setRotatorUsed(rotUsed);
+}
+
 bool Ctrl::setCrop(const utils::Dim& d)
 {
     if(!mMdp.setCrop(d)) {
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index f4c95f9..58f46b3 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -62,7 +62,9 @@
     /* set crop info and pass it down to mdp */
     bool setCrop(const utils::Dim& d);
     /* set orientation */
-    bool setTransform(const utils::eTransform& p, const bool&);
+    bool setTransform(const utils::eTransform& p);
+    /* set whether rotator can be used */
+    void setRotatorUsed(const bool& rotUsed);
     /* set mdp position using dim */
     bool setPosition(const utils::Dim& dim);
     /* mdp set overlay/commit changes */
@@ -82,6 +84,16 @@
     /* dump the state of the object */
     void dump() const;
 
+    /* Perform transformation calculations */
+    void doTransform();
+
+    /* Performs downscale calculations */
+    void doDownscale(int dscale_factor);
+
+    /* Get downscale factor */
+    int getDownscalefactor();
+
+
 private:
     /* Retrieve screen info from underlying mdp */
     bool getScreenInfo(utils::ScreenInfo& info);
@@ -183,6 +195,18 @@
     return mMdp.getSrcRectDim();
 }
 
+inline void Ctrl::doTransform() {
+    return mMdp.doTransform();
+}
+
+inline void Ctrl::doDownscale(int dscale_factor) {
+    mMdp.doDownscale(dscale_factor);
+}
+
+inline int Ctrl::getDownscalefactor() {
+    return mMdp.getDownscalefactor();
+}
+
 inline Data::Data() {
     mMdp.reset();
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 48630a5..12ff8a9 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -111,19 +111,22 @@
     return true;
 }
 
-bool MdpCtrl::setTransform(const utils::eTransform& orient,
-        const bool& rotUsed) {
+bool MdpCtrl::setTransform(const utils::eTransform& orient) {
     int rot = utils::getMdpOrient(orient);
     setUserData(rot);
     //getMdpOrient will switch the flips if the source is 90 rotated.
     //Clients in Android dont factor in 90 rotation while deciding the flip.
     mOrientation = static_cast<utils::eTransform>(rot);
 
-    //Rotator can be requested by client even if layer has 0 orientation.
-    mRotUsed = rotUsed;
     return true;
 }
 
+void MdpCtrl::setRotatorUsed(const bool& rotUsed) {
+    //rotUsed dictates whether rotator hardware can be used.
+    //It is set if transformation or downscaling is required.
+    mRotUsed = rotUsed;
+}
+
 void MdpCtrl::doTransform() {
     adjustSrcWhf(mRotUsed);
     setRotationFlags();
@@ -140,9 +143,52 @@
     }
 }
 
+int MdpCtrl::getDownscalefactor() {
+    int dscale_factor = utils::ROT_DS_NONE;
+    int src_w = mOVInfo.src_rect.w;
+    int src_h = mOVInfo.src_rect.h;
+    int dst_w = mOVInfo.dst_rect.w;
+    int dst_h = mOVInfo.dst_rect.h;
+    // We need this check to engage the rotator whenever possible to assist MDP
+    // in performing video downscale.
+    // This saves bandwidth and avoids causing the driver to make too many panel
+    // -mode switches between BLT (writeback) and non-BLT (Direct) modes.
+    // Use-case: Video playback [with downscaling and rotation].
+
+    if (dst_w && dst_h)
+    {
+        uint32_t dscale = (src_w * src_h) / (dst_w * dst_h);
+
+        if(dscale < 2) {
+            // Down-scale to > 50% of orig.
+            dscale_factor = utils::ROT_DS_NONE;
+        } else if(dscale < 4) {
+            // Down-scale to between > 25% to <= 50% of orig.
+            dscale_factor = utils::ROT_DS_HALF;
+        } else if(dscale < 8) {
+            // Down-scale to between > 12.5% to <= 25% of orig.
+            dscale_factor = utils::ROT_DS_FOURTH;
+        } else {
+            // Down-scale to <= 12.5% of orig.
+            dscale_factor = utils::ROT_DS_EIGHTH;
+        }
+    }
+
+    return dscale_factor;
+}
+
+void MdpCtrl::doDownscale(int dscale_factor) {
+
+    if( dscale_factor ) {
+        mOVInfo.src_rect.x >>= dscale_factor;
+        mOVInfo.src_rect.y >>= dscale_factor;
+        mOVInfo.src_rect.w >>= dscale_factor;
+        mOVInfo.src_rect.h >>= dscale_factor;
+    }
+}
+
 bool MdpCtrl::set() {
     //deferred calcs, so APIs could be called in any order.
-    doTransform();
     utils::Whf whf = getSrcWhf();
     if(utils::isYuv(whf.format)) {
         normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index 4128068..24aa3c1 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -130,7 +130,10 @@
      */
     bool setCrop(const utils::Dim& d);
 
-    bool setTransform(const utils::eTransform& orient, const bool& rotUsed);
+    bool setTransform(const utils::eTransform& orient);
+
+    /* set whether rotator can be used */
+    void setRotatorUsed(const bool& rotUsed);
 
     /* given a dim and w/h, set overlay dim */
     bool setPosition(const utils::Dim& dim, int w, int h);
@@ -141,10 +144,18 @@
     /* dump state of the object */
     void dump() const;
 
+    /* Perform transformation calculations */
+    void doTransform();
+
+    /* Performs downscale calculations */
+    void doDownscale(int dscale_factor);
+
+    /* Get downscale factor */
+    int getDownscalefactor();
+
 private:
 
     /* helper functions for overlayTransform */
-    void doTransform();
     void overlayTransFlipH();
     void overlayTransFlipV();
     void overlayTransRot90();
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
index f96ddb7..5052bc8 100644
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -53,6 +53,20 @@
     mRotDataInfo.src.flags |= MDP_MEMORY_ID_TYPE_FB;
 }
 
+void MdpRot::setDownscale(int ds) {
+    if (mRotImgInfo.src.format == MDP_Y_CR_CB_GH2V2 &&
+                            (mRotImgInfo.src_rect.h & 0xF)) {
+        mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
+    } else if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
+        // Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
+        // This is an undocumented MDP Rotator constraint.
+        // Note that src_rect.h is already ensured to be 32 pixel height aligned
+        // for MDP_Y_CRCB_H2V2_TILE and MDP_Y_CBCR_H2V2_TILE formats.
+        mRotImgInfo.src_rect.h = utils::alignup(mRotImgInfo.src_rect.h, 16);
+    }
+    mRotImgInfo.downscale_ratio = ds;
+}
+
 void MdpRot::save() {
     mLSRotImgInfo = mRotImgInfo;
 }
@@ -103,7 +117,7 @@
         mRotImgInfo.secure = 1;
 }
 
-void MdpRot::setTransform(const utils::eTransform& rot, const bool& rotUsed)
+void MdpRot::setTransform(const utils::eTransform& rot)
 {
     int r = utils::getMdpOrient(rot);
     setRotations(r);
@@ -111,7 +125,9 @@
     //Clients in Android dont factor in 90 rotation while deciding the flip.
     mOrientation = static_cast<utils::eTransform>(r);
     ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
+}
 
+void MdpRot::setRotatorUsed(const bool& rotUsed) {
     setDisable();
     if(rotUsed) {
         setEnable();
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 071e9f2..c00e732 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -31,6 +31,7 @@
 #endif
 
 #define SIZE_1M 0x00100000
+#define MDSS_ROT_MASK (MDP_ROT_90 | MDP_FLIP_UD | MDP_FLIP_LR)
 
 namespace ovutils = overlay::utils;
 
@@ -94,11 +95,14 @@
     mBufSize = awhf.size;
 }
 
+void MdssRot::setDownscale(int ds) {
+}
+
 void MdssRot::setFlags(const utils::eMdpFlags& flags) {
     mRotInfo.flags |= flags;
 }
 
-void MdssRot::setTransform(const utils::eTransform& rot, const bool& rotUsed)
+void MdssRot::setTransform(const utils::eTransform& rot)
 {
     int flags = utils::getMdpOrient(rot);
     if (flags != -1)
@@ -107,7 +111,9 @@
     //Clients in Android dont factor in 90 rotation while deciding the flip.
     mOrientation = static_cast<utils::eTransform>(flags);
     ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, flags);
+}
 
+void MdssRot::setRotatorUsed(const bool& rotUsed) {
     setDisable();
     if(rotUsed) {
         setEnable();
@@ -129,8 +135,8 @@
         return false;
     }
     mRotData.id = mRotInfo.id;
-    //reset flags to avoid stale orientation values
-    mRotInfo.flags = 0;
+    // reset rotation flags to avoid stale orientation values
+    mRotInfo.flags &= ~MDSS_ROT_MASK;
     return true;
 }
 
diff --git a/liboverlay/overlayMem.h b/liboverlay/overlayMem.h
index e81c2dc..ff8afcd 100644
--- a/liboverlay/overlayMem.h
+++ b/liboverlay/overlayMem.h
@@ -120,7 +120,7 @@
     int allocFlags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
     if(isSecure) {
         allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP;
-        allocFlags |= GRALLOC_USAGE_PRIVATE_CP_BUFFER;
+        allocFlags |= GRALLOC_USAGE_PROTECTED;
         allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
     }
 
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index ca71402..118f71f 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -47,11 +47,12 @@
     virtual bool close() = 0;
     virtual void setSource(const utils::Whf& wfh) = 0;
     virtual void setFlags(const utils::eMdpFlags& flags) = 0;
-    virtual void setTransform(const utils::eTransform& rot,
-            const bool& rotUsed) = 0;
+    virtual void setTransform(const utils::eTransform& rot) = 0;
+    virtual void setRotatorUsed(const bool& rotUsed) = 0;
     virtual bool commit() = 0;
     virtual void setRotations(uint32_t r) = 0;
     virtual void setSrcFB() = 0;
+    virtual void setDownscale(int ds) = 0;
     virtual int getDstMemId() const = 0;
     virtual uint32_t getDstOffset() const = 0;
     virtual void setEnable() = 0;
@@ -116,11 +117,12 @@
     virtual bool close();
     virtual void setSource(const utils::Whf& wfh);
     virtual void setFlags(const utils::eMdpFlags& flags);
-    virtual void setTransform(const utils::eTransform& rot,
-            const bool& rotUsed);
+    virtual void setTransform(const utils::eTransform& rot);
+    virtual void setRotatorUsed(const bool& rotUsed);
     virtual bool commit();
     virtual void setRotations(uint32_t r);
     virtual void setSrcFB();
+    virtual void setDownscale(int ds);
     virtual int getDstMemId() const;
     virtual uint32_t getDstOffset() const;
     virtual void setEnable();
@@ -176,11 +178,12 @@
     virtual bool close();
     virtual void setSource(const utils::Whf& wfh);
     virtual void setFlags(const utils::eMdpFlags& flags);
-    virtual void setTransform(const utils::eTransform& rot,
-            const bool& rotUsed);
+    virtual void setTransform(const utils::eTransform& rot);
+    virtual void setRotatorUsed(const bool& rotUsed);
     virtual bool commit();
     virtual void setRotations(uint32_t r);
     virtual void setSrcFB();
+    virtual void setDownscale(int ds);
     virtual int getDstMemId() const;
     virtual uint32_t getDstOffset() const;
     virtual void setEnable();
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index cbacf3e..cbacf7f 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -276,9 +276,21 @@
  * ROT_FLAG_DISABLED: Rotator not used unless required.
  * ROT_FLAG_ENABLED: Rotator used even if not required.
  * */
-enum eRotFlags {
-    ROT_FLAG_DISABLED = 0,
-    ROT_FLAG_ENABLED = 1 // needed in rot
+ enum eRotFlags {
+    ROT_FLAGS_NONE = 0,
+    //Use rotator for 0 rotation. It is used anyway for others.
+    ROT_0_ENABLED = 1 << 0,
+    //Enable rotator downscale optimization for hardware bugs not handled in
+    //driver. If downscale optimizatation is required,
+    //then rotator will be used even if its 0 rotation case.
+    ROT_DOWNSCALE_ENABLED = 1 << 1,
+};
+
+enum eRotDownscale {
+    ROT_DS_NONE = 0,
+    ROT_DS_HALF = 1,
+    ROT_DS_FOURTH = 2,
+    ROT_DS_EIGHTH = 3,
 };
 
 /* The values for is_fg flag for control alpha and transp
@@ -372,7 +384,7 @@
     PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE),
         zorder(Z_SYSTEM_ALLOC),
         isFg(IS_FG_OFF),
-        rotFlags(ROT_FLAG_DISABLED){
+        rotFlags(ROT_FLAGS_NONE){
     }
 
     PipeArgs(eMdpFlags f, Whf _whf,
@@ -447,6 +459,11 @@
     return a ? ((((value - 1) / a) + 1) * a) : value;
 }
 
+inline int aligndown(int value, int a) {
+    //if align = 0, return the value. Else, do alignment.
+    return a ? ((value) & ~(a-1)) : value;
+}
+
 // FIXME that align should replace the upper one.
 inline int align(int value, int a) {
     //if align = 0, return the value. Else, do alignment.
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 9f08c14..aaaa0f1 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -29,11 +29,12 @@
 
 #include "overlayGenPipe.h"
 #include "overlay.h"
+#include "mdp_version.h"
 
 namespace overlay {
 
 GenericPipe::GenericPipe(int dpy) : mFbNum(dpy), mRot(0), mRotUsed(false),
-        pipeState(CLOSED) {
+        mRotDownscaleOpt(false), pipeState(CLOSED) {
     init();
 }
 
@@ -45,6 +46,7 @@
 {
     ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
     mRotUsed = false;
+    mRotDownscaleOpt = false;
     if(mFbNum)
         mFbNum = Overlay::getInstance()->getExtFbNum();
 
@@ -101,7 +103,9 @@
     newargs.whf = whf;
 
     //Cache if user wants 0-rotation
-    mRotUsed = newargs.rotFlags & utils::ROT_FLAG_ENABLED;
+    mRotUsed = newargs.rotFlags & utils::ROT_0_ENABLED;
+    mRotDownscaleOpt = newargs.rotFlags & utils::ROT_DOWNSCALE_ENABLED;
+
     mRot->setSource(newargs.whf);
     mRot->setFlags(newargs.mdpFlags);
     return mCtrlData.ctrl.setSource(newargs);
@@ -118,9 +122,9 @@
     //Rotation could be enabled by user for zero-rot or the layer could have
     //some transform. Mark rotation enabled in either case.
     mRotUsed |= (orient != utils::OVERLAY_TRANSFORM_0);
-    mRot->setTransform(orient, mRotUsed);
+    mRot->setTransform(orient);
 
-    return mCtrlData.ctrl.setTransform(orient, mRotUsed);
+    return mCtrlData.ctrl.setTransform(orient);
 }
 
 bool GenericPipe::setPosition(const utils::Dim& d)
@@ -128,10 +132,31 @@
     return mCtrlData.ctrl.setPosition(d);
 }
 
+void GenericPipe::setRotatorUsed(const bool& rotUsed) {
+    mRot->setRotatorUsed(rotUsed);
+    mCtrlData.ctrl.setRotatorUsed(rotUsed);
+}
+
 bool GenericPipe::commit() {
     bool ret = false;
-    //If wanting to use rotator, start it.
+    int downscale_factor = utils::ROT_DS_NONE;
+
+    if(mRotDownscaleOpt) {
+        /* Can go ahead with calculation of downscale_factor since
+         * we consider area when calculating it */
+        downscale_factor = mCtrlData.ctrl.getDownscalefactor();
+        if(downscale_factor)
+            mRotUsed = true;
+    }
+
+    setRotatorUsed(mRotUsed);
+    mCtrlData.ctrl.doTransform();
+
+    mCtrlData.ctrl.doDownscale(downscale_factor);
+    mRot->setDownscale(downscale_factor);
+
     if(mRotUsed) {
+        //If wanting to use rotator, start it.
         if(!mRot->commit()) {
             ALOGE("GenPipe Rotator commit failed");
             //If rot commit fails, flush rotator session, memory, fd and create
@@ -224,4 +249,5 @@
     return true;
 }
 
+
 } //namespace overlay
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index d0bb3a8..604529a 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -88,6 +88,9 @@
     /* set Closed pipe */
     bool setClosed();
 
+    /* Set whether rotator can be used */
+    void setRotatorUsed(const bool& rotUsed);
+
     int mFbNum;
 
     /* Ctrl/Data aggregator */
@@ -98,6 +101,10 @@
     //Whether rotator is used for 0-rot or otherwise
     bool mRotUsed;
 
+    //Whether we will do downscale opt. This is just a request. If the frame is
+    //not a candidate, we might not do it.
+    bool mRotDownscaleOpt;
+
     /* Pipe open or closed */
     enum ePipeState {
         CLOSED,