Merge "hwc: No idle fallback for single layers"
diff --git a/Android.mk b/Android.mk
index 772b66e..d8b168d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,5 @@
 display-hals := libgralloc libgenlock libcopybit liblight
-display-hals += libhwcomposer liboverlay libqdutils libexternal libqservice
+display-hals += libhwcomposer liboverlay libqdutils libhdmi libqservice
 display-hals += libmemtrack
 ifeq ($(call is-vendor-board-platform,QCOM),true)
     include $(call all-named-subdir-makefiles,$(display-hals))
diff --git a/common.mk b/common.mk
index 14d8ded..ae6c95a 100644
--- a/common.mk
+++ b/common.mk
@@ -4,7 +4,7 @@
 common_includes += $(LOCAL_PATH)/../libcopybit
 common_includes += $(LOCAL_PATH)/../libqdutils
 common_includes += $(LOCAL_PATH)/../libhwcomposer
-common_includes += $(LOCAL_PATH)/../libexternal
+common_includes += $(LOCAL_PATH)/../libhdmi
 common_includes += $(LOCAL_PATH)/../libqservice
 
 ifeq ($(TARGET_USES_POST_PROCESSING),true)
diff --git a/libexternal/Android.mk b/libhdmi/Android.mk
similarity index 67%
rename from libexternal/Android.mk
rename to libhdmi/Android.mk
index 05e42d4..89ba4a9 100644
--- a/libexternal/Android.mk
+++ b/libhdmi/Android.mk
@@ -2,12 +2,12 @@
 include $(LOCAL_PATH)/../common.mk
 include $(CLEAR_VARS)
 
-LOCAL_MODULE                  := libexternal
+LOCAL_MODULE                  := libhdmi
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
 LOCAL_SHARED_LIBRARIES        := $(common_libs) liboverlay libqdutils
-LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdexternal\"
+LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdhdmi\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
-LOCAL_SRC_FILES               := external.cpp
+LOCAL_SRC_FILES               := hdmi.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libexternal/external.cpp b/libhdmi/hdmi.cpp
similarity index 87%
rename from libexternal/external.cpp
rename to libhdmi/hdmi.cpp
index 28cf590..4fb7cfa 100644
--- a/libexternal/external.cpp
+++ b/libhdmi/hdmi.cpp
@@ -26,7 +26,7 @@
 #include <sys/ioctl.h>
 #include <cutils/properties.h>
 #include "hwc_utils.h"
-#include "external.h"
+#include "hdmi.h"
 #include "overlayUtils.h"
 #include "overlay.h"
 #include "qd_utils.h"
@@ -64,26 +64,37 @@
     EDIDData(HDMI_VFRMT_720x480p60_16_9, 720, 480, 60, 8),
     EDIDData(HDMI_VFRMT_720x576p50_4_3, 720, 576, 50, 9),
     EDIDData(HDMI_VFRMT_720x576p50_16_9, 720, 576, 50, 10),
-    EDIDData(HDMI_VFRMT_1024x768p60_4_3, 1024, 768, 60, 11),
-    EDIDData(HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, 60, 12),
-    EDIDData(HDMI_VFRMT_1280x720p50_16_9, 1280, 720, 50, 13),
-    EDIDData(HDMI_VFRMT_1280x720p60_16_9, 1280, 720, 60, 14),
-    EDIDData(HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, 24, 15),
-    EDIDData(HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, 25, 16),
-    EDIDData(HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, 30, 17),
-    EDIDData(HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, 50, 18),
-    EDIDData(HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, 60, 19),
-    EDIDData(HDMI_VFRMT_2560x1600p60_16_9, 2560, 1600, 60, 20),
-    EDIDData(HDMI_VFRMT_3840x2160p24_16_9, 3840, 2160, 24, 21),
-    EDIDData(HDMI_VFRMT_3840x2160p25_16_9, 3840, 2160, 25, 22),
-    EDIDData(HDMI_VFRMT_3840x2160p30_16_9, 3840, 2160, 30, 23),
-    EDIDData(HDMI_VFRMT_4096x2160p24_16_9, 4096, 2160, 24, 24),
+    EDIDData(HDMI_VFRMT_800x600p60_4_3, 800, 600, 60, 11),
+    EDIDData(HDMI_VFRMT_848x480p60_16_9, 848, 480, 60, 12),
+    EDIDData(HDMI_VFRMT_1024x768p60_4_3, 1024, 768, 60, 13),
+    EDIDData(HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, 60, 14),
+    EDIDData(HDMI_VFRMT_1280x720p50_16_9, 1280, 720, 50, 15),
+    EDIDData(HDMI_VFRMT_1280x720p60_16_9, 1280, 720, 60, 16),
+    EDIDData(HDMI_VFRMT_1280x800p60_16_10, 1280, 800, 60, 17),
+    EDIDData(HDMI_VFRMT_1280x960p60_4_3, 1280, 960, 60, 18),
+    EDIDData(HDMI_VFRMT_1360x768p60_16_9, 1360, 768, 60, 19),
+    EDIDData(HDMI_VFRMT_1366x768p60_16_10, 1366, 768, 60, 20),
+    EDIDData(HDMI_VFRMT_1440x900p60_16_10, 1440, 900, 60, 21),
+    EDIDData(HDMI_VFRMT_1400x1050p60_4_3, 1400, 1050, 60, 22),
+    EDIDData(HDMI_VFRMT_1680x1050p60_16_10, 1680, 1050, 60, 23),
+    EDIDData(HDMI_VFRMT_1600x1200p60_4_3, 1600, 1200, 60, 24),
+    EDIDData(HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, 24, 25),
+    EDIDData(HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, 25, 26),
+    EDIDData(HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, 30, 27),
+    EDIDData(HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, 50, 28),
+    EDIDData(HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, 60, 29),
+    EDIDData(HDMI_VFRMT_1920x1200p60_16_10, 1920, 1200, 60, 30),
+    EDIDData(HDMI_VFRMT_2560x1600p60_16_9, 2560, 1600, 60, 31),
+    EDIDData(HDMI_VFRMT_3840x2160p24_16_9, 3840, 2160, 24, 32),
+    EDIDData(HDMI_VFRMT_3840x2160p25_16_9, 3840, 2160, 25, 33),
+    EDIDData(HDMI_VFRMT_3840x2160p30_16_9, 3840, 2160, 30, 34),
+    EDIDData(HDMI_VFRMT_4096x2160p24_16_9, 4096, 2160, 24, 35),
 };
 
 // Number of modes in gEDIDData
 const int gEDIDCount = (sizeof(gEDIDData)/sizeof(gEDIDData)[0]);
 
-int ExternalDisplay::configure() {
+int HDMIDisplay::configure() {
     if(!openFrameBuffer()) {
         ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
         return -1;
@@ -113,12 +124,12 @@
     return 0;
 }
 
-void ExternalDisplay::getAttributes(uint32_t& width, uint32_t& height) {
+void HDMIDisplay::getAttributes(uint32_t& width, uint32_t& height) {
     uint32_t fps = 0;
     getAttrForMode(width, height, fps);
 }
 
-int ExternalDisplay::teardown() {
+int HDMIDisplay::teardown() {
     closeFrameBuffer();
     resetInfo();
     // unset system property
@@ -126,7 +137,7 @@
     return 0;
 }
 
-ExternalDisplay::ExternalDisplay():mFd(-1),
+HDMIDisplay::HDMIDisplay():mFd(-1),
     mCurrentMode(-1), mModeCount(0), mPrimaryWidth(0), mPrimaryHeight(0),
     mUnderscanSupported(false)
 {
@@ -166,7 +177,7 @@
  * to the sysfs node, so that the driver can get that information
  * Used to show QCOM 8974 instead of Input 1 for example
  */
-void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
+void HDMIDisplay::setSPDInfo(const char* node, const char* property) {
     char info[PROPERTY_VALUE_MAX];
     ssize_t err = -1;
     int spdFile = openDeviceNode(node, O_RDWR);
@@ -189,12 +200,12 @@
     }
 }
 
-void ExternalDisplay::setHPD(uint32_t value) {
+void HDMIDisplay::setHPD(uint32_t value) {
     ALOGD_IF(DEBUG,"HPD enabled=%d", value);
     writeHPDOption(value);
 }
 
-void ExternalDisplay::setActionSafeDimension(int w, int h) {
+void HDMIDisplay::setActionSafeDimension(int w, int h) {
     ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
     char actionsafeWidth[PROPERTY_VALUE_MAX];
     char actionsafeHeight[PROPERTY_VALUE_MAX];
@@ -204,12 +215,12 @@
     property_set("persist.sys.actionsafe.height", actionsafeHeight);
 }
 
-int ExternalDisplay::getModeCount() const {
+int HDMIDisplay::getModeCount() const {
     ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
     return mModeCount;
 }
 
-void ExternalDisplay::readCEUnderscanInfo()
+void HDMIDisplay::readCEUnderscanInfo()
 {
     int hdmiScanInfoFile = -1;
     ssize_t len = -1;
@@ -258,8 +269,8 @@
 
     if (ce_info_str) {
         // ce_info contains the underscan information
-        if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
-            ce_info == EXT_SCAN_BOTH_SUPPORTED)
+        if (ce_info == HDMI_SCAN_ALWAYS_UNDERSCANED ||
+            ce_info == HDMI_SCAN_BOTH_SUPPORTED)
             // if TV supported underscan, then driver will always underscan
             // hence no need to apply action safe rectangle
             mUnderscanSupported = true;
@@ -273,7 +284,7 @@
     return;
 }
 
-ExternalDisplay::~ExternalDisplay()
+HDMIDisplay::~HDMIDisplay()
 {
     delete [] supported_video_mode_lut;
     closeFrameBuffer();
@@ -309,7 +320,7 @@
     info.upper_margin = mode->back_porch_v;
 }
 
-int ExternalDisplay::parseResolution(char* edidStr)
+int HDMIDisplay::parseResolution(char* edidStr)
 {
     char delim = ',';
     int count = 0;
@@ -330,7 +341,7 @@
     return count;
 }
 
-bool ExternalDisplay::readResolution()
+bool HDMIDisplay::readResolution()
 {
     ssize_t len = -1;
     char edidStr[128] = {'\0'};
@@ -364,7 +375,7 @@
     return (len > 0);
 }
 
-bool ExternalDisplay::openFrameBuffer()
+bool HDMIDisplay::openFrameBuffer()
 {
     if (mFd == -1) {
         char strDevPath[MAX_SYSFS_FILE_PATH];
@@ -376,7 +387,7 @@
     return (mFd > 0);
 }
 
-bool ExternalDisplay::closeFrameBuffer()
+bool HDMIDisplay::closeFrameBuffer()
 {
     int ret = 0;
     if(mFd >= 0) {
@@ -387,7 +398,7 @@
 }
 
 // clears the vinfo, edid, best modes
-void ExternalDisplay::resetInfo()
+void HDMIDisplay::resetInfo()
 {
     memset(&mVInfo, 0, sizeof(mVInfo));
     memset(mEDIDModes, 0, sizeof(mEDIDModes));
@@ -403,7 +414,7 @@
     property_set("hw.underscan_supported", prop);
 }
 
-int ExternalDisplay::getModeOrder(int mode)
+int HDMIDisplay::getModeOrder(int mode)
 {
     for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) {
         if (gEDIDData[dataIndex].mMode == mode) {
@@ -415,7 +426,7 @@
 }
 
 /// Returns the user mode set(if any) using adb shell
-int ExternalDisplay::getUserMode() {
+int HDMIDisplay::getUserMode() {
     /* Based on the property set the resolution */
     char property_value[PROPERTY_VALUE_MAX];
     property_get("hw.hdmi.resolution", property_value, "-1");
@@ -429,7 +440,7 @@
 }
 
 // Get the best mode for the current HD TV
-int ExternalDisplay::getBestMode() {
+int HDMIDisplay::getBestMode() {
     int bestOrder = 0;
     int bestMode = HDMI_VFRMT_640x480p60_4_3;
     // for all the edid read, get the best mode
@@ -444,7 +455,7 @@
     return bestMode;
 }
 
-inline bool ExternalDisplay::isValidMode(int ID)
+inline bool HDMIDisplay::isValidMode(int ID)
 {
     bool valid = false;
     for (int i = 0; i < mModeCount; i++) {
@@ -457,7 +468,7 @@
 }
 
 // returns true if the mode(ID) is interlaced mode format
-bool ExternalDisplay::isInterlacedMode(int ID) {
+bool HDMIDisplay::isInterlacedMode(int ID) {
     bool interlaced = false;
     switch(ID) {
         case HDMI_VFRMT_1440x480i60_4_3:
@@ -476,7 +487,7 @@
 
 // Does a put_vscreen info on the HDMI interface which will update
 // the configuration (resolution, timing info) to match mCurrentMode
-void ExternalDisplay::activateDisplay()
+void HDMIDisplay::activateDisplay()
 {
     int ret = 0;
     ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
@@ -526,7 +537,7 @@
     }
 }
 
-bool ExternalDisplay::writeHPDOption(int userOption) const
+bool HDMIDisplay::writeHPDOption(int userOption) const
 {
     bool ret = true;
     if(mFbNum != -1) {
@@ -550,7 +561,7 @@
 }
 
 
-void ExternalDisplay::setAttributes() {
+void HDMIDisplay::setAttributes() {
     uint32_t fps = 0;
     // Always set dpyAttr res to mVInfo res
     getAttrForMode(mXres, mYres, fps);
@@ -619,7 +630,7 @@
     ALOGD_IF(DEBUG, "%s xres=%d, yres=%d", __FUNCTION__, mXres, mYres);
 }
 
-void ExternalDisplay::getAttrForMode(uint32_t& width, uint32_t& height,
+void HDMIDisplay::getAttrForMode(uint32_t& width, uint32_t& height,
         uint32_t& fps) {
     for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) {
         if (gEDIDData[dataIndex].mMode == mCurrentMode) {
@@ -633,7 +644,7 @@
 }
 
 /* returns the fd related to the node specified*/
-int ExternalDisplay::openDeviceNode(const char* node, int fileMode) const {
+int HDMIDisplay::openDeviceNode(const char* node, int fileMode) const {
     char sysFsFilePath[MAX_SYSFS_FILE_PATH];
     memset(sysFsFilePath, 0, sizeof(sysFsFilePath));
     snprintf(sysFsFilePath , sizeof(sysFsFilePath),
@@ -649,12 +660,12 @@
     return fd;
 }
 
-bool ExternalDisplay::isHDMIPrimaryDisplay() {
+bool HDMIDisplay::isHDMIPrimaryDisplay() {
     int hdmiNode = qdutils::getHDMINode();
     return (hdmiNode == HWC_DISPLAY_PRIMARY);
 }
 
-int ExternalDisplay::getConnectedState() {
+int HDMIDisplay::getConnectedState() {
     int ret = -1;
     int mFbNum = qdutils::getHDMINode();
     int connectedNode = openDeviceNode("connected", O_RDONLY);
@@ -679,7 +690,7 @@
     return ret;
 }
 
-void ExternalDisplay::setPrimaryAttributes(uint32_t primaryWidth,
+void HDMIDisplay::setPrimaryAttributes(uint32_t primaryWidth,
         uint32_t primaryHeight) {
     mPrimaryHeight = primaryHeight;
     mPrimaryWidth = primaryWidth;
diff --git a/libexternal/external.h b/libhdmi/hdmi.h
similarity index 90%
rename from libexternal/external.h
rename to libhdmi/hdmi.h
index fa98de9..605d9be 100644
--- a/libexternal/external.h
+++ b/libhdmi/hdmi.h
@@ -18,8 +18,8 @@
  * limitations under the License.
  */
 
-#ifndef HWC_EXTERNAL_DISPLAY_H
-#define HWC_EXTERNAL_DISPLAY_H
+#ifndef HWC_HDMI_DISPLAY_H
+#define HWC_HDMI_DISPLAY_H
 
 #include <linux/fb.h>
 
@@ -28,11 +28,11 @@
 namespace qhwc {
 
 //Type of scanning of EDID(Video Capability Data Block)
-enum external_scansupport_type {
-    EXT_SCAN_NOT_SUPPORTED      = 0,
-    EXT_SCAN_ALWAYS_OVERSCANED  = 1,
-    EXT_SCAN_ALWAYS_UNDERSCANED = 2,
-    EXT_SCAN_BOTH_SUPPORTED     = 3
+enum hdmi_scansupport_type {
+    HDMI_SCAN_NOT_SUPPORTED      = 0,
+    HDMI_SCAN_ALWAYS_OVERSCANED  = 1,
+    HDMI_SCAN_ALWAYS_UNDERSCANED = 2,
+    HDMI_SCAN_BOTH_SUPPORTED     = 3
 };
 
 // Structure to store EDID related data
@@ -45,11 +45,11 @@
     { }
 };
 
-class ExternalDisplay
+class HDMIDisplay
 {
 public:
-    ExternalDisplay();
-    ~ExternalDisplay();
+    HDMIDisplay();
+    ~HDMIDisplay();
     void setHPD(uint32_t startEnd);
     void setActionSafeDimension(int w, int h);
     bool isCEUnderscanSupported() { return mUnderscanSupported; }
@@ -107,4 +107,4 @@
 
 }; //qhwc
 // ---------------------------------------------------------------------------
-#endif //HWC_EXTERNAL_DISPLAY_H
+#endif //HWC_HDMI_DISPLAY_H
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 8e3fc8e..df3e464 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -9,7 +9,7 @@
                                  $(TOP)/external/skia/include/core \
                                  $(TOP)/external/skia/include/images
 LOCAL_SHARED_LIBRARIES        := $(common_libs) libEGL liboverlay \
-                                 libexternal libqdutils libhardware_legacy \
+                                 libhdmi libqdutils libhardware_legacy \
                                  libdl libmemalloc libqservice libsync \
                                  libbinder libmedia
 
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index ae1389d..288b2e0 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -34,7 +34,7 @@
 #include "hwc_fbupdate.h"
 #include "hwc_mdpcomp.h"
 #include "hwc_dump_layers.h"
-#include "external.h"
+#include "hdmi.h"
 #include "hwc_copybit.h"
 #include "hwc_ad.h"
 #include "profiler.h"
@@ -442,7 +442,7 @@
         if(mode == HWC_POWER_MODE_NORMAL) {
             // Enable HPD here, as during bootup POWER_MODE_NORMAL is set
             // when SF is completely initialized
-            ctx->mExtDisplay->setHPD(1);
+            ctx->mHDMIDisplay->setHPD(1);
         }
 
         ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 679e6d6..7e96d97 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -34,7 +34,6 @@
 #include <mdp_version.h>
 #include "hwc_ad.h"
 #include "hwc_utils.h"
-#include "external.h"
 
 #define DEBUG 0
 using namespace overlay;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 7839139..43ae916 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -25,7 +25,6 @@
 #include <overlayRotator.h>
 #include "hwc_fbupdate.h"
 #include "mdp_version.h"
-#include "external.h"
 
 using namespace qdutils;
 using namespace overlay;
@@ -514,12 +513,13 @@
            based on an empirically derived value of panel height.
     */
 
-    bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+    const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
             qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+    const uint32_t lSplit = getLeftSplit(ctx, mDpy);
+    const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
 
-    if(((sourceCrop.right - sourceCrop.left) >
-            (int)qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
-            primarySplitAlways) {
+    if((cropWidth > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
+            (primarySplitAlways and cropWidth > lSplit)) {
         destR = ov.getPipe(pipeSpecs);
         if(destR == ovutils::OV_INVALID) {
             ALOGE("%s: No pipes available to configure fb for dpy %d's right"
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index f2cff45..bf764e6 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -19,7 +19,7 @@
 #include <math.h>
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
-#include "external.h"
+#include "hdmi.h"
 #include "qdMetaData.h"
 #include "mdp_version.h"
 #include "hwc_fbupdate.h"
@@ -36,7 +36,7 @@
 
 //==============MDPComp========================================================
 
-IdleInvalidator *MDPComp::idleInvalidator = NULL;
+IdleInvalidator *MDPComp::sIdleInvalidator = NULL;
 bool MDPComp::sIdleFallBack = false;
 bool MDPComp::sHandleTimeout = false;
 bool MDPComp::sDebugLogs = false;
@@ -110,7 +110,7 @@
         return false;
     }
 
-    char property[PROPERTY_VALUE_MAX];
+    char property[PROPERTY_VALUE_MAX] = {0};
 
     sEnabled = false;
     if((property_get("persist.hwc.mdpcomp.enable", property, NULL) > 0) &&
@@ -134,23 +134,10 @@
     }
 
     if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
-        // Idle invalidation is not necessary on command mode panels
-        long idle_timeout = DEFAULT_IDLE_TIME;
-        if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
-            if(atoi(property) != 0)
-                idle_timeout = atoi(property);
-        }
-
-        //create Idle Invalidator only when not disabled through property
-        if(idle_timeout != -1)
-            idleInvalidator = IdleInvalidator::getInstance();
-
-        if(idleInvalidator == NULL) {
-            ALOGE("%s: failed to instantiate idleInvalidator object",
-                  __FUNCTION__);
-        } else {
-            idleInvalidator->init(timeout_handler, ctx,
-                                  (unsigned int)idle_timeout);
+        sIdleInvalidator = IdleInvalidator::getInstance();
+        if(sIdleInvalidator->init(timeout_handler, ctx) < 0) {
+            delete sIdleInvalidator;
+            sIdleInvalidator = NULL;
         }
     }
 
@@ -206,6 +193,25 @@
     ctx->proc->invalidate(ctx->proc);
 }
 
+void MDPComp::setIdleTimeout(const uint32_t& timeout) {
+    enum { ONE_REFRESH_PERIOD_MS = 17, ONE_BILLION_MS = 1000000000 };
+
+    if(sIdleInvalidator) {
+        if(timeout <= ONE_REFRESH_PERIOD_MS) {
+            //If the specified timeout is < 1 draw cycle worth, "virtually"
+            //disable idle timeout. The ideal way for clients to disable
+            //timeout is to set it to 0
+            sIdleInvalidator->setIdleTimeout(ONE_BILLION_MS);
+            ALOGI("Disabled idle timeout");
+            return;
+        }
+        sIdleInvalidator->setIdleTimeout(timeout);
+        ALOGI("Idle timeout set to %u", timeout);
+    } else {
+        ALOGW("Cannot set idle timeout, IdleInvalidator not enabled");
+    }
+}
+
 void MDPComp::setMDPCompLayerFlags(hwc_context_t *ctx,
                                    hwc_display_contents_1_t* list) {
     LayerProp *layerProp = ctx->layerProp[mDpy];
@@ -358,7 +364,7 @@
      * 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))
+    if(mdpHw.hasMinCropWidthLimitation() and (crop_w < 5 or crop_h < 5))
         return false;
 
     if((w_scale > 1.0f) || (h_scale > 1.0f)) {
@@ -2057,7 +2063,7 @@
     }
 
     // Set the Handle timeout to true for MDP or MIXED composition.
-    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
         sHandleTimeout = true;
     }
 
@@ -2312,7 +2318,7 @@
     }
 
     // Set the Handle timeout to true for MDP or MIXED composition.
-    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
         sHandleTimeout = true;
     }
 
@@ -2471,7 +2477,8 @@
             mdpHw.isSrcSplitAlways();
     int lSplit = getLeftSplit(ctx, mDpy);
     int dstWidth = dst.right - dst.left;
-    int cropWidth = crop.right - crop.left;
+    int cropWidth = has90Transform(layer) ? crop.bottom - crop.top :
+            crop.right - crop.left;
 
     //TODO Even if a 4k video is going to be rot-downscaled to dimensions under
     //pipe line length, we are still using 2 pipes. This is fine just because
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index e43c4f4..268e9aa 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -25,7 +25,6 @@
 #include <cutils/properties.h>
 #include <overlay.h>
 
-#define DEFAULT_IDLE_TIME 70
 #define MAX_PIPES_PER_MIXER 4
 
 namespace overlay {
@@ -57,6 +56,7 @@
     static void resetIdleFallBack() { sIdleFallBack = false; }
     static bool isIdleFallback() { return sIdleFallBack; }
     static void dynamicDebug(bool enable){ sDebugLogs = enable; }
+    static void setIdleTimeout(const uint32_t& timeout);
 
 protected:
     enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -255,7 +255,7 @@
     static bool sHandleTimeout;
     static int sMaxPipesPerMixer;
     static bool sSrcSplitEnabled;
-    static IdleInvalidator *idleInvalidator;
+    static IdleInvalidator *sIdleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
     //Enable 4kx2k yuv layer split
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 8490058..6bde3d2 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -245,6 +245,13 @@
     }
 }
 
+static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) {
+    uint32_t timeout = (uint32_t)inParcel->readInt32();
+    ALOGD("%s :%u ms", __FUNCTION__, timeout);
+    Locker::Autolock _sl(ctx->mDrawLock);
+    MDPComp::setIdleTimeout(timeout);
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -290,6 +297,9 @@
         case IQService::DYNAMIC_DEBUG:
             toggleDynamicDebug(mHwcContext, inParcel);
             break;
+        case IQService::SET_IDLE_TIMEOUT:
+            setIdleTimeout(mHwcContext, inParcel);
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 821bfa9..65e041b 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -30,7 +30,7 @@
 #include "hwc_mdpcomp.h"
 #include "hwc_copybit.h"
 #include "comptype.h"
-#include "external.h"
+#include "hdmi.h"
 #include "hwc_virtual.h"
 #include "mdp_version.h"
 using namespace overlay;
@@ -109,7 +109,7 @@
 
             Locker::Autolock _l(ctx->mDrawLock);
             destroyCompositionResources(ctx, dpy);
-            ctx->mExtDisplay->teardown();
+            ctx->mHDMIDisplay->teardown();
             resetDisplayInfo(ctx, dpy);
 
             /* We need to send hotplug to SF only when we are disconnecting
@@ -163,8 +163,8 @@
                         "uevent thread", __FUNCTION__);
                 ctx->mWfdSyncLock.unlock();
             }
-            ctx->mExtDisplay->configure();
-            ctx->mExtDisplay->activateDisplay();
+            ctx->mHDMIDisplay->configure();
+            ctx->mHDMIDisplay->activateDisplay();
 
             Locker::Autolock _l(ctx->mDrawLock);
             updateDisplayInfo(ctx, dpy);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 44725de..7cf390e 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -37,12 +37,13 @@
 #include "mdp_version.h"
 #include "hwc_copybit.h"
 #include "hwc_dump_layers.h"
-#include "external.h"
+#include "hdmi.h"
 #include "hwc_qclient.h"
 #include "QService.h"
 #include "comptype.h"
 #include "hwc_virtual.h"
 #include "qd_utils.h"
+#include <sys/sysinfo.h>
 
 using namespace qClient;
 using namespace qService;
@@ -73,6 +74,11 @@
 #endif
 #endif
 
+#define PROP_DEFAULT_APPBUFFER  "ro.sf.default_app_buffer"
+#define MAX_RAM_SIZE  512*1024*1024
+#define qHD_WIDTH 540
+
+
 namespace qhwc {
 
 //Std refresh rates for digital videos- 24p, 30p and 48p
@@ -112,21 +118,21 @@
     }
 }
 
-// Initialize external display attributes based on
-// external display class state
+// Initialize hdmi display attributes based on
+// hdmi display class state
 void updateDisplayInfo(hwc_context_t* ctx, int dpy) {
-    ctx->dpyAttr[dpy].fd = ctx->mExtDisplay->getFd();
-    ctx->dpyAttr[dpy].xres = ctx->mExtDisplay->getWidth();
-    ctx->dpyAttr[dpy].yres = ctx->mExtDisplay->getHeight();
-    ctx->dpyAttr[dpy].mMDPScalingMode = ctx->mExtDisplay->getMDPScalingMode();
-    ctx->dpyAttr[dpy].vsync_period = ctx->mExtDisplay->getVsyncPeriod();
+    ctx->dpyAttr[dpy].fd = ctx->mHDMIDisplay->getFd();
+    ctx->dpyAttr[dpy].xres = ctx->mHDMIDisplay->getWidth();
+    ctx->dpyAttr[dpy].yres = ctx->mHDMIDisplay->getHeight();
+    ctx->dpyAttr[dpy].mMDPScalingMode = ctx->mHDMIDisplay->getMDPScalingMode();
+    ctx->dpyAttr[dpy].vsync_period = ctx->mHDMIDisplay->getVsyncPeriod();
     ctx->mViewFrame[dpy].left = 0;
     ctx->mViewFrame[dpy].top = 0;
     ctx->mViewFrame[dpy].right = ctx->dpyAttr[dpy].xres;
     ctx->mViewFrame[dpy].bottom = ctx->dpyAttr[dpy].yres;
 }
 
-// Reset external display attributes and list stats structures
+// Reset hdmi display attributes and list stats structures
 void resetDisplayInfo(hwc_context_t* ctx, int dpy) {
     memset(&(ctx->dpyAttr[dpy]), 0, sizeof(ctx->dpyAttr[dpy]));
     memset(&(ctx->listStats[dpy]), 0, sizeof(ctx->listStats[dpy]));
@@ -232,6 +238,25 @@
     return 0;
 }
 
+static void changeDefaultAppBufferCount() {
+    struct sysinfo info;
+    unsigned long int ramSize = 0;
+    if (!sysinfo(&info)) {
+           ramSize = info.totalram ;
+    }
+    int fb_fd = -1;
+    struct fb_var_screeninfo sInfo ={0};
+    fb_fd = open("/dev/graphics/fb0", O_RDONLY);
+    if (fb_fd >=0) {
+        ioctl(fb_fd, FBIOGET_VSCREENINFO, &sInfo);
+        close(fb_fd);
+    }
+    if ((ramSize && ramSize < MAX_RAM_SIZE) &&
+         (sInfo.xres &&  sInfo.xres <= qHD_WIDTH )) {
+                  property_set(PROP_DEFAULT_APPBUFFER, "2");
+    }
+}
+
 void initContext(hwc_context_t *ctx)
 {
     openFramebufferDevice(ctx);
@@ -243,6 +268,10 @@
     ctx->mOverlay = overlay::Overlay::getInstance();
     ctx->mRotMgr = RotMgr::getInstance();
 
+    //default_app_buffer for ferrum
+    if (ctx->mMDP.version ==  qdutils::MDP_V3_0_5) {
+       changeDefaultAppBufferCount();
+    }
     // Initialize composition objects for the primary display
     initCompositionResources(ctx, HWC_DISPLAY_PRIMARY);
 
@@ -260,12 +289,12 @@
                                                          HWC_DISPLAY_PRIMARY);
     }
 
-    ctx->mExtDisplay = new ExternalDisplay();
-    // Send the primary resolution to the external display class
+    ctx->mHDMIDisplay = new HDMIDisplay();
+    // Send the primary resolution to the hdmi display class
     // to be used for MDP scaling functionality
     uint32_t priW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
     uint32_t priH = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
-    ctx->mExtDisplay->setPrimaryAttributes(priW, priH);
+    ctx->mHDMIDisplay->setPrimaryAttributes(priW, priH);
     ctx->mHWCVirtual = new HWCVirtualVDS();
     ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
     ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = false;
@@ -366,9 +395,9 @@
         ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1;
     }
 
-    if(ctx->mExtDisplay) {
-        delete ctx->mExtDisplay;
-        ctx->mExtDisplay = NULL;
+    if(ctx->mHDMIDisplay) {
+        delete ctx->mHDMIDisplay;
+        ctx->mHDMIDisplay = NULL;
     }
 
     for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
@@ -478,7 +507,7 @@
     if(ctx->dpyAttr[dpy].mMDPScalingMode) {
         // if MDP scaling mode is enabled for external, need to query
         // the actual width and height, as that is the physical w & h
-         ctx->mExtDisplay->getAttributes(fbWidth, fbHeight);
+         ctx->mHDMIDisplay->getAttributes(fbWidth, fbHeight);
     }
 
 
@@ -610,7 +639,7 @@
     if(ctx->dpyAttr[dpy].mMDPScalingMode) {
         uint32_t extW = 0, extH = 0;
         if(dpy == HWC_DISPLAY_EXTERNAL) {
-            ctx->mExtDisplay->getAttributes(extW, extH);
+            ctx->mHDMIDisplay->getAttributes(extW, extH);
         } else if(dpy == HWC_DISPLAY_VIRTUAL) {
             extW = ctx->mHWCVirtual->getScalingWidth();
             extH = ctx->mHWCVirtual->getScalingHeight();
@@ -696,7 +725,7 @@
                 float fbHeight = (float)ctx->dpyAttr[dpy].yres;
                 // query MDP configured attributes
                 if(dpy == HWC_DISPLAY_EXTERNAL) {
-                    ctx->mExtDisplay->getAttributes(extW, extH);
+                    ctx->mHDMIDisplay->getAttributes(extW, extH);
                 } else if(dpy == HWC_DISPLAY_VIRTUAL) {
                     extW = ctx->mHWCVirtual->getScalingWidth();
                     extH = ctx->mHWCVirtual->getScalingHeight();
@@ -1114,7 +1143,7 @@
     // Disable Actionsafe for non HDMI displays.
     if(!(dpy == HWC_DISPLAY_EXTERNAL) ||
         qdutils::MDPVersion::getInstance().is8x74v2() ||
-        ctx->mExtDisplay->isCEUnderscanSupported()) {
+        ctx->mHDMIDisplay->isCEUnderscanSupported()) {
         return false;
     }
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 041ca74..cae22f1 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -62,7 +62,7 @@
 namespace qhwc {
 //fwrd decl
 class QueuedBufferStore;
-class ExternalDisplay;
+class HDMIDisplay;
 class VirtualDisplay;
 class IFBUpdate;
 class IVideoOverlay;
@@ -545,8 +545,9 @@
 
     //Primary and external FB updater
     qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
-    // External display related information
-    qhwc::ExternalDisplay *mExtDisplay;
+    // HDMI display related object. Used to configure/teardown
+    // HDMI when it is connected as primary or external.
+    qhwc::HDMIDisplay *mHDMIDisplay;
     qhwc::MDPInfo mMDP;
     qhwc::VsyncState vstate;
     qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index 66988f7..07d1e4e 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -29,7 +29,6 @@
 #include "hwc_utils.h"
 #include "qd_utils.h"
 #include "string.h"
-#include "external.h"
 #include "overlay.h"
 #define __STDC_FORMAT_MACROS 1
 #include <inttypes.h>
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index 86191e9..5850ce5 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -47,10 +47,13 @@
     ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
 }
 
-int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data,
-                         unsigned int idleSleepTime) {
-    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s idleSleepTime %d",
-        __FUNCTION__, idleSleepTime);
+IdleInvalidator::~IdleInvalidator() {
+    if(mTimeoutEventFd >= 0) {
+        close(mTimeoutEventFd);
+    }
+}
+
+int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) {
     mHandler = reg_handler;
     mHwcContext = user_data;
 
@@ -62,34 +65,47 @@
         return -1;
     }
 
-    // Open a sysfs node to send the timeout value to driver.
-    int fd = open(IDLE_TIME_PATH, O_WRONLY);
-    if (fd < 0) {
-        ALOGE ("%s:not able to open %s node %s",
-                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+    enum {DEFAULT_IDLE_TIME = 70}; //ms
+    if(not setIdleTimeout(DEFAULT_IDLE_TIME)) {
         close(mTimeoutEventFd);
         mTimeoutEventFd = -1;
         return -1;
     }
-    char strSleepTime[64];
-    snprintf(strSleepTime, sizeof(strSleepTime), "%d", idleSleepTime);
-    // Notify driver about the timeout value
-    ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
-    if(len < -1) {
-        ALOGE ("%s:not able to write into %s node %s",
-                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
-        close(mTimeoutEventFd);
-        mTimeoutEventFd = -1;
-        close(fd);
-        return -1;
-    }
-    close(fd);
 
     //Triggers the threadLoop to run, if not already running.
     run(threadName, android::PRIORITY_LOWEST);
     return 0;
 }
 
+bool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) {
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d",
+            __FUNCTION__, timeout);
+
+    // Open a sysfs node to send the timeout value to driver.
+    int fd = open(IDLE_TIME_PATH, O_WRONLY);
+
+    if (fd < 0) {
+        ALOGE ("%s:Unable to open %s node %s",
+                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+        return false;
+    }
+
+    char strSleepTime[64];
+    snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout);
+
+    // Notify driver about the timeout value
+    ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
+    if(len < -1) {
+        ALOGE ("%s:Unable to write into %s node %s",
+                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+        close(fd);
+        return false;
+    }
+
+    close(fd);
+    return true;
+}
+
 bool IdleInvalidator::threadLoop() {
     ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
     struct pollfd pFd;
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index a881c4b..52334a0 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -37,16 +37,18 @@
 typedef void (*InvalidatorHandler)(void*);
 
 class IdleInvalidator : public android::Thread {
+    IdleInvalidator();
     void *mHwcContext;
     int mTimeoutEventFd;
     static InvalidatorHandler mHandler;
     static android::sp<IdleInvalidator> sInstance;
 
-    public:
-    IdleInvalidator();
+public:
+    ~IdleInvalidator();
     /* init timer obj */
-    int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
-             idleSleepTime);
+    int init(InvalidatorHandler reg_handler, void* user_data);
+    bool setIdleTimeout(const uint32_t& timeout);
+
     /*Overrides*/
     virtual bool        threadLoop();
     virtual int         readyToRun();
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index b0a8d7d..088f82b 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -411,6 +411,10 @@
 }
 
 
+bool MDPVersion::hasMinCropWidthLimitation() const {
+    return mMdpRev <= MDSS_MDP_HW_REV_102;
+}
+
 bool MDPVersion::supportsDecimation() {
     return mFeatures & MDP_DECIMATION_EN;
 }
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index d26c55c..3c7f6a3 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -138,6 +138,7 @@
     uint32_t getMinFpsSupported() { return mPanelInfo.mMinFps; }
     uint32_t getMaxFpsSupported() { return mPanelInfo.mMaxFps; }
     uint32_t getMaxMixerWidth() const { return mMaxMixerWidth; }
+    bool hasMinCropWidthLimitation() const;
     bool isSrcSplit() const;
     bool isSrcSplitAlways() const;
     bool isRGBScalarSupported() const;
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 30c064e..3be20f1 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -53,6 +53,7 @@
         SET_WFD_STATUS,          // Set if wfd connection is on/off
         SET_VIEW_FRAME,          // Set view frame of display
         DYNAMIC_DEBUG,           // Enable more logging on the fly
+        SET_IDLE_TIMEOUT,        // Set idle timeout for GPU fallback
         COMMAND_LIST_END = 400,
     };