Merge "hwc2: Check composition type in SetLayerBuffer"
diff --git a/Android.mk b/Android.mk
index 226e8a0..1a285bf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,7 +3,7 @@
 
 ifneq ($(TARGET_IS_HEADLESS), true)
     display-hals += libcopybit liblight libmemtrack hdmi_cec \
-                    $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper libdrmutils
+                    $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper libdrmutils libdisplayconfig
 endif
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
diff --git a/common.mk b/common.mk
index 88d1aee..18ee72f 100644
--- a/common.mk
+++ b/common.mk
@@ -3,7 +3,7 @@
 
 #Common C flags
 common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers
-common_flags += -Wconversion -Wall -Werror -std=c++11
+common_flags += -Wconversion -Wall -Werror -std=c++14
 ifeq ($(TARGET_IS_HEADLESS), true)
     common_flags += -DTARGET_HEADLESS
     LOCAL_CLANG := false
@@ -35,6 +35,10 @@
     common_flags += -DUSE_GRALLOC1
 endif
 
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+    common_flags += -DUSER_DEBUG
+endif
+
 common_includes := system/core/base/include
 CHECK_VERSION_LE = $(shell if [ $(1) -le $(2) ] ; then echo true ; else echo false ; fi)
 PLATFORM_SDK_NOUGAT = 25
diff --git a/libdisplayconfig/Android.mk b/libdisplayconfig/Android.mk
new file mode 100644
index 0000000..fae7f85
--- /dev/null
+++ b/libdisplayconfig/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE                  := libdisplayconfig
+LOCAL_MODULE_TAGS             := optional
+LOCAL_HEADER_LIBRARIES        := display_headers
+LOCAL_COPY_HEADERS            := DisplayConfig.h
+LOCAL_SRC_FILES               := DisplayConfig.cpp
+LOCAL_SHARED_LIBRARIES        := libhidlbase libhidltransport libutils \
+                                 vendor.display.config@1.0 android.hidl.base@1.0
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libdisplayconfig/DisplayConfig.cpp b/libdisplayconfig/DisplayConfig.cpp
new file mode 100644
index 0000000..c55715b
--- /dev/null
+++ b/libdisplayconfig/DisplayConfig.cpp
@@ -0,0 +1,363 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <vendor/display/config/1.0/IDisplayConfig.h>
+
+#include "DisplayConfig.h"
+
+namespace display {
+
+using vendor::display::config::V1_0::IDisplayConfig;
+
+//=============================================================================
+// The functions below run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
+
+IDisplayConfig::DisplayType MapDisplayType(int dpy) {
+    switch (dpy) {
+        case DISPLAY_PRIMARY:
+            return IDisplayConfig::DisplayType::DISPLAY_PRIMARY;
+
+        case DISPLAY_EXTERNAL:
+            return IDisplayConfig::DisplayType::DISPLAY_EXTERNAL;
+
+        case DISPLAY_VIRTUAL:
+            return IDisplayConfig::DisplayType::DISPLAY_VIRTUAL;
+
+        default:
+            break;
+    }
+
+    return IDisplayConfig::DisplayType::INVALID;
+}
+
+IDisplayConfig::DisplayExternalStatus MapExternalStatus(uint32_t status) {
+    switch (status) {
+        case EXTERNAL_OFFLINE:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE;
+
+        case EXTERNAL_ONLINE:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE;
+
+        case EXTERNAL_PAUSE:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE;
+
+        case EXTERNAL_RESUME:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME;
+
+        default:
+            break;
+    }
+
+    return IDisplayConfig::DisplayExternalStatus::INVALID;
+}
+
+IDisplayConfig::DisplayDynRefreshRateOp MapDynRefreshRateOp(uint32_t op) {
+    switch (op) {
+        case DISABLE_METADATA_DYN_REFRESH_RATE:
+            return IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE;
+
+        case ENABLE_METADATA_DYN_REFRESH_RATE:
+            return IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE;
+
+        case SET_BINDER_DYN_REFRESH_RATE:
+            return IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE;
+
+        default:
+            break;
+    }
+
+    return IDisplayConfig::DisplayDynRefreshRateOp::INVALID;
+}
+
+int MapDisplayPortType(IDisplayConfig::DisplayPortType panelType) {
+    switch (panelType) {
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT:
+            return DISPLAY_PORT_DEFAULT;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DSI:
+            return DISPLAY_PORT_DSI;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DTV:
+            return DISPLAY_PORT_DTV;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_WRITEBACK:
+            return DISPLAY_PORT_WRITEBACK;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_LVDS:
+            return DISPLAY_PORT_LVDS;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_EDP:
+            return DISPLAY_PORT_EDP;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DP:
+            return DISPLAY_PORT_DP;
+
+        default:
+            break;
+    }
+
+    return -1;
+}
+
+int isExternalConnected() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return 0;
+    }
+
+    int connected = 0;
+    intf->isDisplayConnected(IDisplayConfig::DisplayType::DISPLAY_EXTERNAL,
+        [&](const auto &tmpError, const auto &tmpStatus) {
+            if (tmpError) {
+                return;
+            }
+
+            connected = tmpStatus;
+        });
+
+    return connected;
+}
+
+int setSecondayDisplayStatus(int dpy, uint32_t status) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setSecondayDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
+}
+
+int configureDynRefeshRate(uint32_t op, uint32_t refreshRate) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->configureDynRefeshRate(MapDynRefreshRateOp(op), refreshRate);
+}
+
+int getConfigCount(int dpy) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    int count = 0;
+    intf->getActiveConfig(MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpCount) {
+            if (tmpError) {
+                return;
+            }
+
+            count = tmpCount;
+        });
+
+    return count;
+}
+
+int getActiveConfig(int dpy) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    int config = 0;
+    intf->getActiveConfig(MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpConfig) {
+            if (tmpError) {
+                return;
+            }
+
+            config = tmpConfig;
+        });
+
+    return config;
+}
+
+int setActiveConfig(int dpy, uint32_t config) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setActiveConfig(MapDisplayType(dpy), config);
+}
+
+DisplayAttributes getDisplayAttributes(uint32_t configIndex, int dpy) {
+    DisplayAttributes attributes;
+
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return attributes;
+    }
+
+    intf->getDisplayAttributes(configIndex, MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpAttributes) {
+            if (tmpError) {
+                return;
+            }
+
+            attributes.vsync_period = tmpAttributes.vsyncPeriod;
+            attributes.xres = tmpAttributes.xRes;
+            attributes.yres = tmpAttributes.yRes;
+            attributes.xdpi = tmpAttributes.xDpi;
+            attributes.ydpi = tmpAttributes.yDpi;
+            attributes.panel_type = MapDisplayPortType(tmpAttributes.panelType);
+            attributes.is_yuv = tmpAttributes.isYuv;
+        });
+
+    return attributes;
+}
+
+int setPanelBrightness(uint32_t level) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setPanelBrightness(level);
+}
+
+uint32_t getPanelBrightness() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return 0;
+    }
+
+    int level = 0;
+    intf->getPanelBrightness(
+        [&](const auto &tmpError, const auto &tmpLevel) {
+            if (tmpError) {
+                return;
+            }
+
+            level = tmpLevel;
+        });
+
+    return level;
+}
+
+int minHdcpEncryptionLevelChanged(int dpy, uint32_t min_enc_level) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->minHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
+}
+
+int refreshScreen() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->refreshScreen();
+}
+
+int controlPartialUpdate(int dpy, bool enable) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->controlPartialUpdate(MapDisplayType(dpy), enable);
+}
+
+int toggleScreenUpdate(uint32_t on) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->toggleScreenUpdate(on == 1);
+}
+
+int setIdleTimeout(uint32_t value) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setIdleTimeout(value);
+}
+
+int getHDRCapabilities(int dpy, DisplayHDRCapabilities *caps) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL || caps == NULL) {
+        return -1;
+    }
+
+    int error = -1;
+    intf->getHDRCapabilities(MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpCaps) {
+            error = tmpError;
+            if (error) {
+                return;
+            }
+
+            caps->supported_hdr_types = tmpCaps.supportedHdrTypes;
+            caps->max_luminance = tmpCaps.maxLuminance;
+            caps->max_avg_luminance = tmpCaps.maxAvgLuminance;
+            caps->min_luminance = tmpCaps.minLuminance;
+        });
+
+    return error;
+}
+
+int setCameraLaunchStatus(uint32_t on) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setCameraLaunchStatus(on);
+}
+
+bool displayBWTransactionPending() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return 0;
+    }
+
+    int status = 0;
+    intf->displayBWTransactionPending(
+        [&](const auto &tmpError, const auto &tmpStatus) {
+            if (tmpError) {
+                return;
+            }
+
+            status = tmpStatus;
+        });
+
+    return status;
+}
+
+} // namespace display
diff --git a/libdisplayconfig/DisplayConfig.h b/libdisplayconfig/DisplayConfig.h
new file mode 100644
index 0000000..69a542a
--- /dev/null
+++ b/libdisplayconfig/DisplayConfig.h
@@ -0,0 +1,110 @@
+/*
+ * Copyight (c) 2017 The Linux Foundation. All ights reserved.
+ *
+ * Redistibution and use in souce and binary forms, with or without
+ * modification, ae pemitted provided that the following conditions are
+ * met:
+ *    * Redistibutions of souce code must retain the above copyright
+ *      notice, this list of conditions and the following disclaime.
+ *    * Redistibutions in binay form must reproduce the above
+ *      copyight notice, this list of conditions and the following
+ *      disclaime in the documentation and/o other materials provided
+ *      with the distibution.
+ *    * Neither the name of The Linux Foundation. no the names of its
+ *      contibutos may be used to endorse or promote products derived
+ *      fom this softwae without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DISPLAY_CONFIG_H__
+#define __DISPLAY_CONFIG_H__
+
+#include <stdint.h>
+#include <vector>
+
+// This header is for clients to use to set/get global display configuration.
+
+namespace display {
+
+enum {
+    DISPLAY_PRIMARY = 0,
+    DISPLAY_EXTERNAL,
+    DISPLAY_VIRTUAL,
+};
+
+enum {
+    EXTERNAL_OFFLINE = 0,
+    EXTERNAL_ONLINE,
+    EXTERNAL_PAUSE,
+    EXTERNAL_RESUME,
+};
+
+enum {
+    DISABLE_METADATA_DYN_REFRESH_RATE = 0,
+    ENABLE_METADATA_DYN_REFRESH_RATE,
+    SET_BINDER_DYN_REFRESH_RATE,
+};
+
+enum {
+    DISPLAY_PORT_DEFAULT = 0,
+    DISPLAY_PORT_DSI,
+    DISPLAY_PORT_DTV,
+    DISPLAY_PORT_WRITEBACK,
+    DISPLAY_PORT_LVDS,
+    DISPLAY_PORT_EDP,
+    DISPLAY_PORT_DP,
+};
+
+struct DisplayAttributes {
+    uint32_t vsync_period = 0; //nanoseconds
+    uint32_t xres = 0;
+    uint32_t yres = 0;
+    float xdpi = 0.0f;
+    float ydpi = 0.0f;
+    int panel_type = DISPLAY_PORT_DEFAULT;
+    bool is_yuv = false;
+};
+
+struct DisplayHDRCapabilities {
+    std::vector<int32_t> supported_hdr_types;
+    float max_luminance = 0.0f;
+    float max_avg_luminance = 0.0f;
+    float min_luminance = 0.0f;
+};
+
+//=============================================================================
+// The functions below run in the client pocess and wherever necessary
+// do a binder call to HWC to get/set data.
+
+int isExternalConnected();
+int setSecondayDisplayStatus(int dpy, uint32_t status);
+int configureDynRefeshRate(uint32_t op, uint32_t refreshRate);
+int getConfigCount(int dpy);
+int getActiveConfig(int dpy);
+int setActiveConfig(int dpy, uint32_t config);
+DisplayAttributes getDisplayAttributes(uint32_t configIndex, int dpy);
+int setPanelBrightness(uint32_t level);
+uint32_t getPanelBrightness();
+int minHdcpEncryptionLevelChanged(int dpy, uint32_t min_enc_level);
+int refreshScreen();
+int controlPartialUpdate(int dpy, bool enable);
+int toggleScreenUpdate(uint32_t on);
+int setIdleTimeout(uint32_t value);
+int getHDRCapabilities(int dpy, DisplayHDRCapabilities *caps);
+int setCameraLaunchStatus(uint32_t on);
+bool displayBWTransactionPending();
+
+} // namespace display
+
+#endif  // __DISPLAY_CONFIG_H__
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 71767e7..97c8ad8 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -125,6 +125,12 @@
    */
   PLANE_SET_SCALER_CONFIG,
   /*
+   * Op: Sets plane rotation destination rect
+   * Arg: uint32_t - Plane ID
+   *      DRMRect - rotator dst Rectangle
+   */
+  PLANE_SET_ROTATION_DST_RECT,
+  /*
    * Op: Activate or deactivate a CRTC
    * Arg: uint32_t - CRTC ID
    *      uint32_t - 1 to enable, 0 to disable
@@ -149,19 +155,48 @@
    *      uint32_t - core_clk
    */
   CRTC_SET_CORE_CLK,
-   /*
-   * Op: Sets overall SDE core average bandwidth
+  /*
+   * Op: Sets MNOC bus average bandwidth
    * Arg: uint32_t - CRTC ID
    *      uint32_t - core_ab
    */
   CRTC_SET_CORE_AB,
    /*
-   * Op: Sets overall SDE core instantaneous bandwidth
+   * Op: Sets MNOC bus instantaneous bandwidth
    * Arg: uint32_t - CRTC ID
    *      uint32_t - core_ib
    */
   CRTC_SET_CORE_IB,
   /*
+   * Op: Sets LLCC Bus average bandwidth
+   * Arg: uint32_t - CRTC ID
+   *      uint32_t - llcc_ab
+   */
+  CRTC_SET_LLCC_AB,
+  /*
+   * Op: Sets LLCC Bus instantaneous bandwidth
+   * Arg: uint32_t - CRTC ID
+   *      uint32_t - llcc_ib
+   */
+  CRTC_SET_LLCC_IB,
+  /*
+   * Op: Sets DRAM bus average bandwidth
+   * Arg: uint32_t - CRTC ID
+   *      uint32_t - dram_ab
+   */
+  CRTC_SET_DRAM_AB,
+  /*
+   * Op: Sets DRAM bus instantaneous bandwidth
+   * Arg: uint32_t - CRTC ID
+   *      uint32_t - dram_ib
+   */
+  CRTC_SET_DRAM_IB,
+  /*
+   * Op: Sets rotator clock for inline rotation
+   * Arg: uint32_t - CRTC ID
+   *      uint32_t - rot_clk
+   */
+  CRTC_SET_ROT_CLK,  /*
    * Op: Returns release fence for this frame. Should be called after Commit() on
    * DRMAtomicReqInterface.
    * Arg: uint32_t - CRTC ID
@@ -315,17 +350,22 @@
   uint32_t max_horizontal_deci;
   uint32_t max_vertical_deci;
   uint64_t max_pipe_bandwidth;
+  uint32_t cache_size;  // cache size in bytes for inline rotation support.
 };
 
 // All DRM Planes as map<Plane_id , plane_type_info> listed from highest to lowest priority
 typedef std::vector<std::pair<uint32_t, DRMPlaneTypeInfo>>  DRMPlanesInfo;
 
 enum struct DRMTopology {
-  UNKNOWN,  // To be compat with driver defs in sde_kms.h
+  UNKNOWN,  // To be compat with driver defs in sde_rm.h
   SINGLE_LM,
+  SINGLE_LM_DSC,
   DUAL_LM,
-  PPSPLIT,
+  DUAL_LM_DSC,
   DUAL_LM_MERGE,
+  DUAL_LM_MERGE_DSC,
+  DUAL_LM_DSCMERGE,
+  PPSPLIT,
 };
 
 enum struct DRMPanelMode {
diff --git a/libgralloc1/Android.mk b/libgralloc1/Android.mk
index f4d4ba7..cdb651c 100644
--- a/libgralloc1/Android.mk
+++ b/libgralloc1/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
 LOCAL_HEADER_LIBRARIES        := display_headers
-LOCAL_SHARED_LIBRARIES        := $(common_libs) libqdutils libqdMetaData libdl
+LOCAL_SHARED_LIBRARIES        := $(common_libs) libqdMetaData libdl
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"grallocutils\" -Wno-sign-conversion
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
 LOCAL_SRC_FILES               := gr_utils.cpp gr_adreno_info.cpp
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index 7e0ba14..16f5635 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -214,7 +214,9 @@
   private_handle_t * handle = const_cast<private_handle_t *>(hnd);
   handle->fd = -1;
   handle->fd_metadata = -1;
-  delete handle;
+  if (!(handle->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED)) {
+      delete handle;
+  }
   return GRALLOC1_ERROR_NONE;
 }
 
@@ -277,10 +279,6 @@
 }
 
 gralloc1_error_t BufferManager::RetainBuffer(private_handle_t const *hnd) {
-  if (hnd->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED) {
-    return GRALLOC1_ERROR_NONE;
-  }
-
   ALOGD_IF(DEBUG, "Retain buffer handle:%p id: %" PRIu64, hnd, hnd->id);
   gralloc1_error_t err = GRALLOC1_ERROR_NONE;
   std::lock_guard<std::mutex> lock(buffer_lock_);
@@ -302,10 +300,6 @@
 }
 
 gralloc1_error_t BufferManager::ReleaseBuffer(private_handle_t const *hnd) {
-  if (hnd->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED) {
-    return GRALLOC1_ERROR_NONE;
-  }
-
   ALOGD_IF(DEBUG, "Release buffer handle:%p id: %" PRIu64, hnd, hnd->id);
   std::lock_guard<std::mutex> lock(buffer_lock_);
   auto buf = GetBufferFromHandleLocked(hnd);
@@ -497,14 +491,14 @@
   BufferInfo info = GetBufferInfo(descriptor);
   GetBufferSizeAndDimensions(info, &size, &alignedw, &alignedh);
   size = (bufferSize >= size) ? bufferSize : size;
-  size = size * layer_count;
 
   int err = 0;
   int flags = 0;
   auto page_size = UINT(getpagesize());
   AllocData data;
   data.align = GetDataAlignment(format, prod_usage, cons_usage);
-  data.size = ALIGN(size, data.align);
+  size = ALIGN(size, data.align) * layer_count;
+  data.size = size;
   data.handle = (uintptr_t) handle;
   data.uncached = allocator_->UseUncached(prod_usage, cons_usage);
 
@@ -630,9 +624,20 @@
       }
 
       BufferDim_t buffer_dim;
+      int interlaced = 0;
       if (getMetaData(hnd, GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
         *stride = buffer_dim.sliceWidth;
         *height = buffer_dim.sliceHeight;
+      } else if (getMetaData(hnd, GET_PP_PARAM_INTERLACED, &interlaced) == 0) {
+        if (interlaced && IsUBwcFormat(hnd->format)) {
+          unsigned int alignedw = 0, alignedh = 0;
+          // Get re-aligned height for single ubwc interlaced field and
+          // multiple by 2 to get frame height.
+          BufferInfo info(hnd->width, ((hnd->height+1)>>1), hnd->format);
+          GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
+          *stride = static_cast<int>(alignedw);
+          *height = static_cast<int>(alignedh * 2);
+        }
       } else {
         *stride = hnd->width;
         *height = hnd->height;
diff --git a/liblight/Android.mk b/liblight/Android.mk
index f627286..2f2e1ca 100644
--- a/liblight/Android.mk
+++ b/liblight/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_SRC_FILES := lights.c lights_prv.cpp
 LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SHARED_LIBRARIES := liblog libcutils libsdm-disp-apis
+LOCAL_SHARED_LIBRARIES := liblog libcutils libsdm-disp-vndapis
 LOCAL_CFLAGS := -DLOG_TAG=\"qdlights\"
 LOCAL_CLANG  := true
 LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 5e327d7..8985dd6 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Not a Contribution, Apache license notifications and license are
  * retained for attribution purposes only.
@@ -93,6 +93,7 @@
         DEBUG_DRIVER_CONFIG,
         DEBUG_ROTATOR,
         DEBUG_QDCM,
+        DEBUG_SCALAR,
     };
 
     enum {
diff --git a/sdm/include/core/sdm_types.h b/sdm/include/core/sdm_types.h
index fae1153..ce356bf 100644
--- a/sdm/include/core/sdm_types.h
+++ b/sdm/include/core/sdm_types.h
@@ -55,6 +55,7 @@
   kErrorShutDown,         //!< Driver is processing shutdown sequence
   kErrorPerfValidation,   //!< Bandwidth or Clock requirement validation failure.
   kErrorNoAppLayers,      //!< No App layer(s) in the draw cycle.
+  kErrorRotatorValidation,  //!< Rotator configuration validation failure.
 };
 
 /*! @brief This structure is defined for client and library compatibility check purpose only. This
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index cdfec2e..8cf1922 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -38,8 +38,6 @@
 
 const int kMaxSDELayers = 16;   // Maximum number of layers that can be handled by MDP5 hardware
                                 // in a given layer stack.
-const int kMaxBlitLayers = 32;   // Maximum number of layers that can be handled by MDP3 hardware
-                                // in a given layer stack.
 #define MAX_PLANES 4
 
 #define MAX_DETAIL_ENHANCE_CURVE 3
@@ -205,6 +203,7 @@
   uint32_t undersized_prefill_lines = 0;
   CompRatioMap comp_ratio_rt_map;
   CompRatioMap comp_ratio_nrt_map;
+  uint32_t cache_size = 0;  // cache size in bytes
 
   void Reset() { *this = HWResourceInfo(); }
 };
@@ -321,6 +320,12 @@
   }
 };
 
+enum HWRotatorMode {
+  kRotatorNone,
+  kRotatorOffline,
+  kRotatorInline
+};
+
 struct HWRotateInfo {
   int pipe_id = -1;  // Not actual pipe id, but the relative DMA id
   int writeback_id = -1;  // Writeback block id, but this is the same as DMA id
@@ -342,6 +347,7 @@
   float input_compression = 1.0f;
   float output_compression = 1.0f;
   bool is_buffer_cached = false;
+  HWRotatorMode mode = kRotatorNone;
 };
 
 struct HWScaleLutInfo {
@@ -499,13 +505,22 @@
   Handle pvt_data = NULL;   // Private data used by sdm extension only.
 };
 
+struct HWQosData {
+  uint64_t core_ab_bps = 0;
+  uint64_t core_ib_bps = 0;
+  uint64_t llcc_ab_bps = 0;
+  uint64_t llcc_ib_bps = 0;
+  uint64_t dram_ab_bps = 0;
+  uint64_t dram_ib_bps = 0;
+  uint32_t clock_hz = 0;
+  uint32_t rot_clock_hz = 0;
+};
+
 struct HWLayers {
   HWLayersInfo info;
   HWLayerConfig config[kMaxSDELayers];
   float output_compression = 1.0f;
-  uint64_t ab_bps = 0;
-  uint64_t ib_bps = 0;
-  uint32_t clock_hz = 0;
+  HWQosData qos_data = {};
   HWAVRInfo hw_avr_info = {};
 };
 
diff --git a/sdm/include/private/resource_interface.h b/sdm/include/private/resource_interface.h
index e140c33..f57d760 100644
--- a/sdm/include/private/resource_interface.h
+++ b/sdm/include/private/resource_interface.h
@@ -58,8 +58,9 @@
   virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst,
                                        bool rotate90, BufferLayout layout,
                                        bool use_rotator_downscale) = 0;
-  virtual DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
-                                              int x, int y) = 0;
+  virtual DisplayError ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers,
+                                                    int x, int y,
+                                                    DisplayConfigVariableInfo *fb_config) = 0;
   virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0;
   virtual DisplayError GetScaleLutConfig(HWScaleLutInfo *lut_info) = 0;
   virtual DisplayError SetDetailEnhancerData(Handle display_ctx,
diff --git a/sdm/include/utils/formats.h b/sdm/include/utils/formats.h
index dd819dc..2d43850 100644
--- a/sdm/include/utils/formats.h
+++ b/sdm/include/utils/formats.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2016 - 2017, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -34,10 +34,28 @@
 
 namespace sdm {
 
+struct FormatTileSize {
+  /*< Tile width in pixels. For YUV formats this will give only the
+      tile width for Y plane*/
+  uint32_t tile_width = 0;
+  /*< Tile height in pixels. For YUV formats this will give only the
+      tile height for Y plane*/
+  uint32_t tile_height = 0;
+
+  /*< Tile width in pixels. Only valid for YUV formats where this will
+      give tile width for UV plane*/
+  uint32_t uv_tile_width = 0;
+  /*< Tile height in pixels. Only valid for YUV formats where this will
+       give tile height for UV plane*/
+  uint32_t uv_tile_height = 0;
+};
+
 bool IsUBWCFormat(LayerBufferFormat format);
 bool Is10BitFormat(LayerBufferFormat format);
 const char *GetFormatString(const LayerBufferFormat &format);
 BufferLayout GetBufferLayout(LayerBufferFormat format);
+DisplayError GetBufferFormatTileSize(LayerBufferFormat format, FormatTileSize *tile_size);
+float GetBufferFormatBpp(LayerBufferFormat format);
 
 }  // namespace sdm
 
diff --git a/sdm/include/utils/rect.h b/sdm/include/utils/rect.h
index ea6edfb..303fc9f 100644
--- a/sdm/include/utils/rect.h
+++ b/sdm/include/utils/rect.h
@@ -60,6 +60,11 @@
   void TransformHV(const LayerRect &src_domain, const LayerRect &in_rect,
                    const LayerTransform &transform, LayerRect *out_rect);
   RectOrientation GetOrientation(const LayerRect &in_rect);
+  DisplayError GetCropAndDestination(const LayerRect &crop, const LayerRect &dst,
+                                     bool rotate90, float *crop_width, float *crop_height,
+                                     float *dst_width, float *dst_height);
+  DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst, bool rotate90,
+                              float *scale_x, float *scale_y);
 }  // namespace sdm
 
 #endif  // __RECT_H__
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
index c5002a9..991cfac 100644
--- a/sdm/libs/core/Android.mk
+++ b/sdm/libs/core/Android.mk
@@ -49,6 +49,7 @@
 ifneq ($(TARGET_IS_HEADLESS), true)
     LOCAL_SRC_FILES           += $(LOCAL_HW_INTF_PATH_2)/hw_info_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_device_drm.cpp \
+                                 $(LOCAL_HW_INTF_PATH_2)/hw_hdmi_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_events_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_scale_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_virtual_drm.cpp \
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index d18b5b8..f35c1c6 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -121,6 +121,7 @@
   registered_displays_[type] = 1;
   display_comp_ctx->is_primary_panel = hw_panel_info.is_primary_panel;
   display_comp_ctx->display_type = type;
+  display_comp_ctx->fb_config = fb_config;
   *display_ctx = display_comp_ctx;
   // New non-primary display device has been added, so move the composition mode to safe mode until
   // resources for the added display is configured properly.
@@ -207,6 +208,8 @@
     }
   }
 
+  // Update new resolution.
+  display_comp_ctx->fb_config = fb_config;
   return error;
 }
 
@@ -459,13 +462,13 @@
   return resource_intf_->ValidateScaling(crop, dst, rotate90, layout, true);
 }
 
-DisplayError CompManager::ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
+DisplayError CompManager::ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers,
                                                  int x, int y) {
   DisplayCompositionContext *display_comp_ctx =
                              reinterpret_cast<DisplayCompositionContext *>(display_ctx);
   Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
-
-  return resource_intf_->ValidateCursorPosition(display_resource_ctx, hw_layers, x, y);
+  return resource_intf_->ValidateAndSetCursorPosition(display_resource_ctx, hw_layers, x, y,
+                                                      &display_comp_ctx->fb_config);
 }
 
 DisplayError CompManager::SetMaxBandwidthMode(HWBwModes mode) {
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index c6b8972..6cc33cf 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -66,7 +66,7 @@
   DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages);
   void ControlPartialUpdate(Handle display_ctx, bool enable);
   DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90);
-  DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
+  DisplayError ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
   bool SetDisplayState(Handle display_ctx, DisplayState state, DisplayType display_type);
   DisplayError SetMaxBandwidthMode(HWBwModes mode);
   DisplayError GetScaleLutConfig(HWScaleLutInfo *lut_info);
@@ -97,6 +97,7 @@
     // panel parameters for now.
     bool is_primary_panel = false;
     PUConstraints pu_constraints = {};
+    DisplayConfigVariableInfo fb_config = {};
   };
 
   Locker locker_;
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 618dd2e..b76c3d1 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -590,21 +590,24 @@
     char idx[8] = { 0 };
     const char *comp_type = GetName(sdm_layer->composition);
     const char *buffer_format = GetFormatString(input_buffer->format);
-    const char *rotate_split[2] = { "Rot-1", "Rot-2" };
     const char *comp_split[2] = { "Comp-1", "Comp-2" };
 
     snprintf(idx, sizeof(idx), "%d", layer_index);
 
     for (uint32_t count = 0; count < hw_rotator_session.hw_block_count; count++) {
-      char writeback_id[8] = { 0 };
+      char writeback_id[8] = { "I" };
       HWRotateInfo &rotate = hw_rotator_session.hw_rotate_info[count];
       LayerRect &src_roi = rotate.src_roi;
       LayerRect &dst_roi = rotate.dst_roi;
+      const char *rotate_split[2] = { "Rot-1", "Rot-2" };
+      int pipe_id = 0;
 
-      snprintf(writeback_id, sizeof(writeback_id), "%d", rotate.writeback_id);
-
+      if (hw_rotator_session.mode == kRotatorOffline) {
+        snprintf(writeback_id, sizeof(writeback_id), "%d", rotate.writeback_id);
+        pipe_id = rotate.pipe_id;
+      }
       DumpImpl::AppendString(buffer, length, format, idx, comp_type, rotate_split[count],
-                             writeback_id, rotate.pipe_id, input_buffer->width,
+                             writeback_id, pipe_id, input_buffer->width,
                              input_buffer->height, buffer_format, INT(src_roi.left),
                              INT(src_roi.top), INT(src_roi.right), INT(src_roi.bottom),
                              INT(dst_roi.left), INT(dst_roi.top), INT(dst_roi.right),
@@ -633,8 +636,11 @@
         continue;
       }
 
-      LayerRect &src_roi = pipe.src_roi;
+      LayerRect src_roi = pipe.src_roi;
       LayerRect &dst_roi = pipe.dst_roi;
+      if (hw_rotator_session.mode == kRotatorInline) {
+        src_roi = hw_rotator_session.hw_rotate_info[count].dst_roi;
+      }
 
       snprintf(z_order, sizeof(z_order), "%d", pipe.z_order);
       snprintf(flags, sizeof(flags), "0x%08x", hw_layer.flags.flags);
@@ -954,7 +960,8 @@
     return kErrorNotSupported;
   }
 
-  DisplayError error = comp_manager_->ValidateCursorPosition(display_comp_ctx_, &hw_layers_, x, y);
+  DisplayError error = comp_manager_->ValidateAndSetCursorPosition(display_comp_ctx_, &hw_layers_,
+                                                                   x, y);
   if (error == kErrorNone) {
     return hw_intf_->SetCursorPosition(&hw_layers_, x, y);
   }
@@ -1325,10 +1332,6 @@
 
       sdm_layer->input_buffer.release_fence_fd = temp;
     }
-
-    // Reset the sync fence fds of HWLayer
-    hw_layer.input_buffer.acquire_fence_fd = -1;
-    hw_layer.input_buffer.release_fence_fd = -1;
   }
 
   return;
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
index b31ac94..a6c5c47 100644
--- a/sdm/libs/core/display_hdmi.cpp
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -87,7 +87,8 @@
   s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode>
                             (kS3dFormatFramePacking, kS3DModeFP));
 
-  error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_);
+  error = HWEventsInterface::Create(INT(display_type_), this, event_list_, hw_intf_,
+                                    &hw_events_intf_);
   if (error != kErrorNone) {
     DisplayBase::Deinit();
     HWInterface::Destroy(hw_intf_);
diff --git a/sdm/libs/core/display_hdmi.h b/sdm/libs/core/display_hdmi.h
index ca09ce3..dfee684 100644
--- a/sdm/libs/core/display_hdmi.h
+++ b/sdm/libs/core/display_hdmi.h
@@ -55,6 +55,7 @@
   virtual void ThermalEvent(int64_t thermal_level) { }
   virtual void CECMessage(char *message);
   virtual void IdlePowerCollapse() { }
+  virtual void PingPongTimeout() { }
 
  private:
   uint32_t GetBestConfig(HWS3DMode s3d_mode);
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index 53a4fd9..52b71c7 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -70,7 +70,8 @@
 
   avr_prop_disabled_ = Debug::IsAVRDisabled();
 
-  error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_);
+  error = HWEventsInterface::Create(INT(display_type_), this, event_list_, hw_intf_,
+                                    &hw_events_intf_);
   if (error != kErrorNone) {
     DLOGE("Failed to create hardware events interface. Error = %d", error);
     DisplayBase::Deinit();
@@ -89,32 +90,6 @@
   uint32_t new_mixer_height = 0;
   uint32_t display_width = display_attributes_.x_pixels;
   uint32_t display_height = display_attributes_.y_pixels;
-  bool needs_hv_flip = hw_panel_info_.panel_orientation.flip_horizontal &&
-                          hw_panel_info_.panel_orientation.flip_vertical;
-  LayerRect src_domain = {};
-  LayerTransform panel_transform = {};
-  DisplayConfigVariableInfo variable_info = {};
-
-  if (needs_hv_flip) {
-    DisplayBase::GetFrameBufferConfig(&variable_info);
-    src_domain.right = variable_info.x_pixels;
-    src_domain.bottom = variable_info.y_pixels;
-    panel_transform.flip_horizontal = hw_panel_info_.panel_orientation.flip_horizontal;
-    panel_transform.flip_vertical = hw_panel_info_.panel_orientation.flip_vertical;
-
-    for (Layer *layer : layer_stack->layers) {
-      // Modify destination based on panel flip
-      TransformHV(src_domain, layer->dst_rect, panel_transform, &layer->dst_rect);
-
-      if (layer->flags.solid_fill) {
-        continue;
-      }
-
-      layer->transform.flip_horizontal ^= (hw_panel_info_.panel_orientation.flip_horizontal);
-      layer->transform.flip_vertical ^= (hw_panel_info_.panel_orientation.flip_vertical);
-     // TODO(user): Check how to handle rotation, if panel has rotation.
-    }
-  }
 
   if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) {
     error = ReconfigureMixer(new_mixer_width, new_mixer_height);
@@ -310,6 +285,11 @@
   comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
 }
 
+void DisplayPrimary::PingPongTimeout() {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  hw_intf_->DumpDebugData();
+}
+
 void DisplayPrimary::ThermalEvent(int64_t thermal_level) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level);
diff --git a/sdm/libs/core/display_primary.h b/sdm/libs/core/display_primary.h
index 314964a..e5aeabc 100644
--- a/sdm/libs/core/display_primary.h
+++ b/sdm/libs/core/display_primary.h
@@ -61,12 +61,17 @@
   virtual void ThermalEvent(int64_t thermal_level);
   virtual void CECMessage(char *message) { }
   virtual void IdlePowerCollapse();
+  virtual void PingPongTimeout();
 
  private:
   bool NeedsAVREnable();
 
-  std::vector<HWEvent> event_list_ = { HWEvent::VSYNC, HWEvent::EXIT, HWEvent::IDLE_NOTIFY,
-      HWEvent::SHOW_BLANK_EVENT, HWEvent::THERMAL_LEVEL, HWEvent::IDLE_POWER_COLLAPSE };
+  std::vector<HWEvent> event_list_ = { HWEvent::VSYNC, HWEvent::EXIT,
+                                       HWEvent::IDLE_NOTIFY,
+                                       HWEvent::SHOW_BLANK_EVENT,
+                                       HWEvent::THERMAL_LEVEL,
+                                       HWEvent::IDLE_POWER_COLLAPSE,
+                                       HWEvent::PINGPONG_TIMEOUT };
   bool avr_prop_disabled_ = false;
   bool switch_to_cmd_ = false;
   bool handle_idle_timeout_ = false;
diff --git a/sdm/libs/core/drm/hw_color_manager_drm.cpp b/sdm/libs/core/drm/hw_color_manager_drm.cpp
index 640a843..3438e77 100644
--- a/sdm/libs/core/drm/hw_color_manager_drm.cpp
+++ b/sdm/libs/core/drm/hw_color_manager_drm.cpp
@@ -270,9 +270,14 @@
       return kErrorParameters;
   }
 
-  if (sde_gamut->map_en)
-    std::memcpy(mdp_gamut->scale_off, sde_gamut->scale_off_data,
-                sizeof(uint32_t) * GAMUT_3D_SCALE_OFF_SZ * GAMUT_3D_SCALE_OFF_TBL_NUM);
+  if (sde_gamut->map_en) {
+    std::memcpy(&mdp_gamut->scale_off[0][0], sde_gamut->scale_off_data[0],
+                sizeof(uint32_t) * GAMUT_3D_SCALE_OFF_SZ);
+    std::memcpy(&mdp_gamut->scale_off[1][0], sde_gamut->scale_off_data[1],
+                sizeof(uint32_t) * GAMUT_3D_SCALE_OFF_SZ);
+    std::memcpy(&mdp_gamut->scale_off[2][0], sde_gamut->scale_off_data[2],
+                sizeof(uint32_t) * GAMUT_3D_SCALE_OFF_SZ);
+  }
 
   for (uint32_t row = 0; row < GAMUT_3D_TBL_NUM; row++) {
     for (uint32_t col = 0; col < size; col++) {
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 1028663..9e99361 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -50,6 +50,7 @@
 #include <utils/sys.h>
 #include <drm/sde_drm.h>
 #include <private/color_params.h>
+#include <utils/rect.h>
 
 #include <algorithm>
 #include <string>
@@ -225,7 +226,7 @@
     HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
     HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[0];
 
-    if (hw_rotate_info->valid) {
+    if (hw_rotator_session->mode == kRotatorOffline && hw_rotate_info->valid) {
       input_buffer = &hw_rotator_session->output_buffer;
     }
 
@@ -355,6 +356,7 @@
 }
 
 DisplayError HWDeviceDRM::Deinit() {
+  PowerOff();
   delete hw_scale_;
   registry_.Clear();
   drm_mgr_intf_->DestroyAtomicReq(drm_atomic_intf_);
@@ -414,7 +416,9 @@
   display_attributes_.h_total = mode.htotal;
   uint32_t h_blanking = mode.htotal - mode.hdisplay;
   display_attributes_.is_device_split =
-      (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_MERGE);
+      (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_MERGE ||
+       topology == DRMTopology::DUAL_LM_MERGE_DSC || topology == DRMTopology::DUAL_LM_DSC ||
+       topology == DRMTopology::DUAL_LM_DSCMERGE);
   display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
 
   display_attributes_.x_dpi = (FLOAT(mode.hdisplay) * 25.4f) / FLOAT(mm_width);
@@ -574,6 +578,11 @@
 
 DisplayError HWDeviceDRM::PowerOn() {
   DTRACE_SCOPED();
+  if (!drm_atomic_intf_) {
+    DLOGE("DRM Atomic Interface is null!");
+    return kErrorUndefined;
+  }
+
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
   int ret = drm_atomic_intf_->Commit(false /* synchronous */);
@@ -585,6 +594,11 @@
 }
 
 DisplayError HWDeviceDRM::PowerOff() {
+  if (!drm_atomic_intf_) {
+    DLOGE("DRM Atomic Interface is null!");
+    return kErrorUndefined;
+  }
+
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::OFF);
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
   int ret = drm_atomic_intf_->Commit(false /* synchronous */);
@@ -617,6 +631,7 @@
 
   HWLayersInfo &hw_layer_info = hw_layers->info;
   uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size());
+  HWQosData &qos_data = hw_layers->qos_data;
 
   // TODO(user): Once destination scalar is enabled we can always send ROIs if driver allows
   if (hw_panel_info_.partial_update) {
@@ -652,15 +667,13 @@
     HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
     HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
     HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
-    bool needs_rotation = false;
 
     for (uint32_t count = 0; count < 2; count++) {
       HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe;
       HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
 
-      if (hw_rotate_info->valid) {
+      if (hw_rotator_session->mode == kRotatorOffline && hw_rotate_info->valid) {
         input_buffer = &hw_rotator_session->output_buffer;
-        needs_rotation = true;
       }
 
       uint32_t fb_id = registry_.GetFbId(input_buffer->planes[0].fd);
@@ -674,21 +687,17 @@
         DRMRect src = {};
         SetRect(pipe_info->src_roi, &src);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SRC_RECT, pipe_id, src);
+        DRMRect rot_dst = {0, 0, 0, 0};
+        if (hw_rotator_session->mode == kRotatorInline && hw_rotate_info->valid) {
+          SetRect(hw_rotate_info->dst_roi, &rot_dst);
+          drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION_DST_RECT, pipe_id, rot_dst);
+        }
         DRMRect dst = {};
         SetRect(pipe_info->dst_roi, &dst);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_DST_RECT, pipe_id, dst);
 
         uint32_t rot_bit_mask = 0;
-        // In case of rotation, rotator handles flips
-        if (!needs_rotation) {
-          if (layer.transform.flip_horizontal) {
-            rot_bit_mask |= UINT32(DRMRotation::FLIP_H);
-          }
-          if (layer.transform.flip_vertical) {
-            rot_bit_mask |= UINT32(DRMRotation::FLIP_V);
-          }
-        }
-
+        SetRotation(layer.transform, hw_rotator_session->mode, &rot_bit_mask);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION, pipe_id, rot_bit_mask);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_H_DECIMATION, pipe_id,
                                   pipe_info->horizontal_decimation);
@@ -715,12 +724,20 @@
       }
     }
 
-    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_CLK, token_.crtc_id, hw_layers->clock_hz);
-    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_AB, token_.crtc_id, hw_layers->ab_bps);
-    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_IB, token_.crtc_id, hw_layers->ib_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_CLK, token_.crtc_id, qos_data.clock_hz);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_AB, token_.crtc_id, qos_data.core_ab_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CORE_IB, token_.crtc_id, qos_data.core_ib_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_LLCC_AB, token_.crtc_id, qos_data.llcc_ab_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_LLCC_IB, token_.crtc_id, qos_data.llcc_ib_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DRAM_AB, token_.crtc_id, qos_data.dram_ab_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DRAM_IB, token_.crtc_id, qos_data.dram_ib_bps);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ROT_CLK, token_.crtc_id, qos_data.rot_clock_hz);
 
-    DLOGI_IF(kTagDriverConfig, "System: clock=%d Hz, ab=%llu Bps ib=%llu Bps", hw_layers->clock_hz,
-             hw_layers->ab_bps, hw_layers->ib_bps);
+    DLOGI_IF(kTagDriverConfig, "System Clock=%d Hz, Core: AB=%llu Bps, IB=%llu Bps, " \
+             "LLCC: AB=%llu Bps, IB=%llu Bps, DRAM AB=%llu Bps, IB=%llu Bps Rot Clock=%d",
+             qos_data.clock_hz, qos_data.core_ab_bps, qos_data.core_ib_bps, qos_data.llcc_ab_bps,
+             qos_data.llcc_ib_bps, qos_data.dram_ab_bps, qos_data.dram_ib_bps,
+             qos_data.rot_clock_hz);
   }
 }
 
@@ -828,7 +845,7 @@
   for (uint32_t i = 0; i < hw_layer_info.hw_layers.size(); i++) {
     Layer &layer = hw_layer_info.hw_layers.at(i);
     HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
-    if (hw_rotator_session->hw_block_count) {
+    if (hw_rotator_session->mode == kRotatorOffline) {
       hw_rotator_session->output_buffer.release_fence_fd = Sys::dup_(release_fence);
     } else {
       layer.input_buffer.release_fence_fd = Sys::dup_(release_fence);
@@ -874,6 +891,36 @@
   target->bottom = UINT32(source.bottom);
 }
 
+void HWDeviceDRM::SetRotation(LayerTransform transform, const HWRotatorMode &mode,
+                              uint32_t* rot_bit_mask) {
+  // In offline rotation case, rotator will handle flips set via offline rotator interface.
+  if (mode == kRotatorOffline) {
+    *rot_bit_mask = 0;
+    return;
+  }
+
+  // In no rotation case or inline rotation case, plane will handle flips
+  // In DRM framework rotation is applied in counter-clockwise direction.
+  if (transform.rotation == 90) {
+    // a) rotate 90 clockwise = rotate 270 counter-clockwise in DRM
+    // rotate 270 is translated as hflip + vflip + rotate90
+    // b) rotate 270 clockwise = rotate 90 counter-clockwise in DRM
+    // c) hflip + rotate 90 clockwise = vflip + rotate 90 counter-clockwise in DRM
+    // d) vflip + rotate 90 clockwise = hflip + rotate 90 counter-clockwise in DRM
+    *rot_bit_mask = UINT32(DRMRotation::ROT_90);
+    transform.flip_horizontal = !transform.flip_horizontal;
+    transform.flip_vertical = !transform.flip_vertical;
+  }
+
+  if (transform.flip_horizontal) {
+    *rot_bit_mask |= UINT32(DRMRotation::FLIP_H);
+  }
+
+  if (transform.flip_vertical) {
+    *rot_bit_mask |= UINT32(DRMRotation::FLIP_V);
+  }
+}
+
 bool HWDeviceDRM::EnableHotPlugDetection(int enable) {
   return true;
 }
@@ -1104,6 +1151,11 @@
   return kErrorNone;
 }
 
+void HWDeviceDRM::GetDRMDisplayToken(sde_drm::DRMDisplayToken *token) const {
+  token->conn_id = token_.conn_id;
+  token->crtc_id = token_.crtc_id;
+}
+
 void HWDeviceDRM::UpdateMixerAttributes() {
   mixer_attributes_.width = display_attributes_.x_pixels;
   mixer_attributes_.height = display_attributes_.y_pixels;
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index ad7a3e3..bbdd69d 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -54,6 +54,7 @@
   virtual ~HWDeviceDRM() {}
   virtual DisplayError Init();
   virtual DisplayError Deinit();
+  void GetDRMDisplayToken(sde_drm::DRMDisplayToken *token) const;
 
  protected:
   // From HWInterface
@@ -94,6 +95,7 @@
   virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes);
   virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
   virtual void InitializeConfigs();
+  virtual DisplayError DumpDebugData() { return kErrorNone; }
 
   enum {
     kHWEventVSync,
@@ -119,6 +121,7 @@
   void SetBlending(const LayerBlending &source, sde_drm::DRMBlendType *target);
   void SetSrcConfig(const LayerBuffer &input_buffer, uint32_t *config);
   void SetRect(const LayerRect &source, sde_drm::DRMRect *target);
+  void SetRotation(LayerTransform transform, const HWRotatorMode &mode, uint32_t* rot_bit_mask);
   DisplayError DefaultCommit(HWLayers *hw_layers);
   DisplayError AtomicCommit(HWLayers *hw_layers);
   void SetupAtomic(HWLayers *hw_layers, bool validate);
@@ -149,6 +152,7 @@
  protected:
   const char *device_name_ = {};
   bool deferred_initialize_ = false;
+  bool default_mode_ = false;
   sde_drm::DRMDisplayType disp_type_ = {};
   HWInfoInterface *hw_info_intf_ = {};
   BufferSyncHandler *buffer_sync_handler_ = {};
@@ -167,7 +171,6 @@
  private:
   bool synchronous_commit_ = false;
   HWMixerAttributes mixer_attributes_ = {};
-  bool default_mode_ = false;
   std::string interface_str_ = "DSI";
   HWScaleDRM *hw_scale_ = {};
 };
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index cea76fc..7487c8a 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -85,6 +85,7 @@
       case HWEvent::SHOW_BLANK_EVENT:
       case HWEvent::THERMAL_LEVEL:
       case HWEvent::IDLE_POWER_COLLAPSE:
+      case HWEvent::PINGPONG_TIMEOUT:
         break;
     }
   }
@@ -139,10 +140,16 @@
 }
 
 DisplayError HWEventsDRM::Init(int display_type, HWEventHandler *event_handler,
-                               const vector<HWEvent> &event_list) {
+                               const vector<HWEvent> &event_list,
+                               const HWInterface *hw_intf) {
   if (!event_handler)
     return kErrorParameters;
 
+  static_cast<const HWDeviceDRM *>(hw_intf)->GetDRMDisplayToken(&token_);
+
+  DLOGI("Setup event handler for display %d, CRTC %d, Connector %d",
+        display_type, token_.crtc_id, token_.conn_id);
+
   event_handler_ = event_handler;
   poll_fds_.resize(event_list.size());
   event_thread_name_ += " - " + std::to_string(display_type);
@@ -264,6 +271,7 @@
         case HWEvent::SHOW_BLANK_EVENT:
         case HWEvent::THERMAL_LEVEL:
         case HWEvent::IDLE_POWER_COLLAPSE:
+        case HWEvent::PINGPONG_TIMEOUT:
           if (poll_fd.fd >= 0 && (poll_fd.revents & POLLPRI) &&
               (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) {
             (this->*(event_data_list_[i]).event_parser)(data);
diff --git a/sdm/libs/core/drm/hw_events_drm.h b/sdm/libs/core/drm/hw_events_drm.h
index 41050c7..206751b 100644
--- a/sdm/libs/core/drm/hw_events_drm.h
+++ b/sdm/libs/core/drm/hw_events_drm.h
@@ -30,6 +30,7 @@
 #ifndef __HW_EVENTS_DRM_H__
 #define __HW_EVENTS_DRM_H__
 
+#include <drm_interface.h>
 #include <sys/poll.h>
 #include <map>
 #include <string>
@@ -38,6 +39,7 @@
 
 #include "hw_events_interface.h"
 #include "hw_interface.h"
+#include "hw_device_drm.h"
 
 namespace sdm {
 
@@ -46,7 +48,8 @@
 class HWEventsDRM : public HWEventsInterface {
  public:
   virtual DisplayError Init(int display_type, HWEventHandler *event_handler,
-                            const vector<HWEvent> &event_list);
+                            const vector<HWEvent> &event_list,
+                            const HWInterface *hw_intf);
   virtual DisplayError Deinit();
   virtual DisplayError SetEventState(HWEvent event, bool enable, void *aux = nullptr);
 
@@ -87,6 +90,7 @@
   bool exit_threads_ = false;
   uint32_t vsync_index_ = 0;
   bool vsync_enabled_ = true;
+  sde_drm::DRMDisplayToken token_ = {};
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_hdmi_drm.cpp b/sdm/libs/core/drm/hw_hdmi_drm.cpp
new file mode 100644
index 0000000..27419c7
--- /dev/null
+++ b/sdm/libs/core/drm/hw_hdmi_drm.cpp
@@ -0,0 +1,163 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <drm_lib_loader.h>
+#include <drm_master.h>
+#include <drm_res_mgr.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <utils/debug.h>
+#include <utils/sys.h>
+#include <utils/formats.h>
+
+#include <vector>
+#include <map>
+#include <utility>
+
+#include "hw_hdmi_drm.h"
+
+#define __CLASS__ "HWHDMIDRM"
+
+using drm_utils::DRMMaster;
+using drm_utils::DRMResMgr;
+using drm_utils::DRMLibLoader;
+using drm_utils::DRMBuffer;
+using sde_drm::GetDRMManager;
+using sde_drm::DestroyDRMManager;
+using sde_drm::DRMDisplayType;
+using sde_drm::DRMDisplayToken;
+using sde_drm::DRMConnectorInfo;
+using sde_drm::DRMPPFeatureInfo;
+using sde_drm::DRMOps;
+using sde_drm::DRMTopology;
+
+namespace sdm {
+
+HWHDMIDRM::HWHDMIDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
+                     HWInfoInterface *hw_info_intf)
+  : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf),
+  active_config_index_(0) {
+  HWDeviceDRM::device_type_ = kDeviceHDMI;
+  HWDeviceDRM::device_name_ = "HDMI Display Device";
+}
+
+// TODO(user) : split function in base class and avoid code duplicacy
+// by using base implementation for this basic stuff
+DisplayError HWHDMIDRM::Init() {
+  DisplayError error = kErrorNone;
+
+  default_mode_ = (DRMLibLoader::GetInstance()->IsLoaded() == false);
+
+  if (!default_mode_) {
+    DRMMaster *drm_master = {};
+    int dev_fd = -1;
+    DRMMaster::GetInstance(&drm_master);
+    drm_master->GetHandle(&dev_fd);
+    DRMLibLoader::GetInstance()->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_);
+    if (drm_mgr_intf_->RegisterDisplay(DRMDisplayType::TV, &token_)) {
+      DLOGE("RegisterDisplay failed");
+      return kErrorResources;
+    }
+
+    drm_mgr_intf_->CreateAtomicReq(token_, &drm_atomic_intf_);
+    drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+    InitializeConfigs();
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode_);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
+
+    if (drm_atomic_intf_->Commit(true /* synchronous */)) {
+      DLOGE("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id, token_.conn_id,
+            device_name_);
+      return kErrorResources;
+    }
+
+    // Reload connector info for updated info after 1st commit
+    drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+    DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_);
+  }
+
+  PopulateDisplayAttributes();
+  PopulateHWPanelInfo();
+  UpdateMixerAttributes();
+
+  return error;
+}
+
+DisplayError HWHDMIDRM::GetNumDisplayAttributes(uint32_t *count) {
+  *count = connector_info_.num_modes;
+  if (*count <= 0) {
+    return kErrorHardware;
+  }
+
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::GetActiveConfig(uint32_t *active_config_index) {
+  *active_config_index = active_config_index_;
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::SetDisplayAttributes(uint32_t index) {
+  DTRACE_SCOPED();
+
+  if (index >= connector_info_.num_modes) {
+    return kErrorNotSupported;
+  }
+
+  active_config_index_ = index;
+
+  // TODO(user): fix this hard coding
+  frame_rate_ = 60;
+
+  // Get the display attributes for current active config index
+  GetDisplayAttributes(active_config_index_, &display_attributes_);
+  UpdateMixerAttributes();
+
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::GetConfigIndex(uint32_t mode, uint32_t *index) {
+  *index = mode;
+
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::Validate(HWLayers *hw_layers) {
+  HWDeviceDRM::ResetDisplayParams();
+
+  return HWDeviceDRM::Validate(hw_layers);
+}
+
+DisplayError HWHDMIDRM::Commit(HWLayers *hw_layers) {
+  return HWDeviceDRM::Commit(hw_layers);
+}
+
+}  // namespace sdm
+
diff --git a/sdm/libs/core/drm/hw_hdmi_drm.h b/sdm/libs/core/drm/hw_hdmi_drm.h
new file mode 100644
index 0000000..7e11e5e
--- /dev/null
+++ b/sdm/libs/core/drm/hw_hdmi_drm.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification, are permitted
+* provided that the following conditions are met:
+*    * Redistributions of source code must retain the above copyright notice, this list of
+*      conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above copyright notice, this list of
+*      conditions and the following disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+*      endorse or promote products derived from this software without specific prior written
+*      permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_HDMI_DRM_H__
+#define __HW_HDMI_DRM_H__
+
+#include <map>
+#include <vector>
+
+#include "hw_device_drm.h"
+
+namespace sdm {
+
+using std::vector;
+
+class HWHDMIDRM : public HWDeviceDRM {
+ public:
+  explicit HWHDMIDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
+                     HWInfoInterface *hw_info_intf);
+
+ protected:
+  virtual DisplayError Init();
+  virtual DisplayError GetNumDisplayAttributes(uint32_t *count);
+  // Requirement to call this only after the first config has been explicitly set by client
+  virtual DisplayError GetActiveConfig(uint32_t *active_config);
+  virtual DisplayError SetDisplayAttributes(uint32_t index);
+  virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
+  virtual DisplayError Validate(HWLayers *hw_layers);
+  virtual DisplayError Commit(HWLayers *hw_layers);
+
+ private:
+  uint32_t active_config_index_;
+  uint32_t frame_rate_ = 0;
+};
+
+}  // namespace sdm
+
+#endif  // __HW_HDMI_DRM_H__
+
diff --git a/sdm/libs/core/drm/hw_info_drm.cpp b/sdm/libs/core/drm/hw_info_drm.cpp
index 6258d73..8843924 100644
--- a/sdm/libs/core/drm/hw_info_drm.cpp
+++ b/sdm/libs/core/drm/hw_info_drm.cpp
@@ -332,6 +332,7 @@
   hw_resource->max_scale_up = info.max_upscale;
   hw_resource->has_decimation = info.max_horizontal_deci > 1 && info.max_vertical_deci > 1;
   hw_resource->max_pipe_bw = info.max_pipe_bandwidth / kKiloUnit;
+  hw_resource->cache_size = info.cache_size;
 }
 
 void HWInfoDRM::PopulateSupportedFmts(HWSubBlockType sub_blk_type,
@@ -412,8 +413,7 @@
     case SDE_PIX_FMT_RGBX_1010102_UBWC: *sdm_format = kFormatRGBX1010102Ubwc;          break;
     case SDE_PIX_FMT_Y_CBCR_H2V2_P010:  *sdm_format = kFormatYCbCr420P010;             break;
     case SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC: *sdm_format = kFormatYCbCr420TP10Ubwc;     break;
-    /* TODO(user) : enable when defined in uapi
-      case SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC: *sdm_format = kFormatYCbCr420P010Ubwc;     break; */
+    case SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC: *sdm_format = kFormatYCbCr420P010Ubwc;     break;
     default: *sdm_format = kFormatInvalid;
   }
 }
diff --git a/sdm/libs/core/drm/hw_virtual_drm.cpp b/sdm/libs/core/drm/hw_virtual_drm.cpp
index 5fe1d86..dc2f06f 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.cpp
+++ b/sdm/libs/core/drm/hw_virtual_drm.cpp
@@ -41,7 +41,7 @@
 using sde_drm::DRMConnectorInfo;
 using sde_drm::DRMRect;
 using sde_drm::DRMOps;
-
+using sde_drm::DRMPowerMode;
 namespace sdm {
 
 HWVirtualDRM::HWVirtualDRM(BufferSyncHandler *buffer_sync_handler,
@@ -146,7 +146,6 @@
   return kErrorNone;
 }
 
-
 DisplayError HWVirtualDRM::SetDisplayAttributes(const HWDisplayAttributes &display_attributes) {
   if (display_attributes.x_pixels == 0 || display_attributes.y_pixels == 0) {
     return kErrorParameters;
@@ -165,6 +164,18 @@
   return kErrorNone;
 }
 
+DisplayError HWVirtualDRM::PowerOn() {
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
+  drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
+  return kErrorNone;
+}
+
+DisplayError HWVirtualDRM::PowerOff() {
+  drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::OFF);
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
+  return kErrorNone;
+}
+
 DisplayError HWVirtualDRM::GetPPFeaturesVersion(PPFeatureVersion *vers) {
   return kErrorNone;
 }
diff --git a/sdm/libs/core/drm/hw_virtual_drm.h b/sdm/libs/core/drm/hw_virtual_drm.h
index b63519a..afa5c71 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.h
+++ b/sdm/libs/core/drm/hw_virtual_drm.h
@@ -55,6 +55,8 @@
   virtual DisplayError Commit(HWLayers *hw_layers);
   virtual DisplayError GetPPFeaturesVersion(PPFeatureVersion *vers);
   virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info);
+  virtual DisplayError PowerOn();
+  virtual DisplayError PowerOff();
   void ConfigureWbConnectorFbId(uint32_t fb_id);
   void ConfigureWbConnectorDestRect();
   void DumpConfigs();
diff --git a/sdm/libs/core/fb/hw_device.cpp b/sdm/libs/core/fb/hw_device.cpp
index 773845b..ff19753 100644
--- a/sdm/libs/core/fb/hw_device.cpp
+++ b/sdm/libs/core/fb/hw_device.cpp
@@ -1141,8 +1141,8 @@
   async_layer.pipe_ndx = left_pipe->pipe_id;
   async_layer.src.x = UINT32(left_pipe->src_roi.left);
   async_layer.src.y = UINT32(left_pipe->src_roi.top);
-  async_layer.dst.x = UINT32(x);
-  async_layer.dst.y = UINT32(y);
+  async_layer.dst.x = UINT32(left_pipe->dst_roi.left);
+  async_layer.dst.y = UINT32(left_pipe->dst_roi.top);
 
   mdp_position_update pos_update = {};
   pos_update.input_layer_cnt = 1;
@@ -1359,5 +1359,33 @@
   return kErrorNone;
 }
 
+DisplayError HWDevice::DumpDebugData() {
+  DLOGW("Pingpong timeout occurred in the driver.");
+#ifdef USER_DEBUG
+  // Save the xlogs on ping pong time out
+  std::ofstream  dst("/data/vendor/display/mdp_xlog");
+  dst << "+++ MDP:XLOG +++" << std::endl;
+  std::ifstream  src("/sys/kernel/debug/mdp/xlog/dump");
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  dst << "+++ MDP:REG_XLOG +++" << std::endl;
+  src.open("/sys/kernel/debug/mdp/xlog/reg_xlog");
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  dst << "+++ MDP:DBGBUS_XLOG +++" << std::endl;
+  src.open("/sys/kernel/debug/mdp/xlog/dbgbus_xlog");
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  dst << "+++ MDP:VBIF_DBGBUS_XLOG +++" << std::endl;
+  src.open("/sys/kernel/debug/mdp/xlog/vbif_dbgbus_xlog");
+  dst << src.rdbuf() << std::endl;
+  src.close();
+#endif
+  return kErrorNone;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/fb/hw_device.h b/sdm/libs/core/fb/hw_device.h
index 2eea87b..2c0593a 100644
--- a/sdm/libs/core/fb/hw_device.h
+++ b/sdm/libs/core/fb/hw_device.h
@@ -97,6 +97,7 @@
   virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info);
   virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes);
   virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
+  virtual DisplayError DumpDebugData();
 
   enum {
     kHWEventVSync,
diff --git a/sdm/libs/core/fb/hw_events.cpp b/sdm/libs/core/fb/hw_events.cpp
index c0467f9..d944624 100644
--- a/sdm/libs/core/fb/hw_events.cpp
+++ b/sdm/libs/core/fb/hw_events.cpp
@@ -104,6 +104,9 @@
     case HWEvent::IDLE_POWER_COLLAPSE:
       event_data->event_parser = &HWEvents::HandleIdlePowerCollapse;
       break;
+    case HWEvent::PINGPONG_TIMEOUT:
+      event_data->event_parser = &HWEvents::HandlePingPongTimeout;
+      break;
     default:
       error = kErrorParameters;
       break;
@@ -123,7 +126,8 @@
 }
 
 DisplayError HWEvents::Init(int fb_num, HWEventHandler *event_handler,
-                            const vector<HWEvent> &event_list) {
+                            const vector<HWEvent> &event_list,
+                            const HWInterface *hw_intf) {
   if (!event_handler)
     return kErrorParameters;
 
@@ -132,10 +136,14 @@
   event_list_ = event_list;
   poll_fds_.resize(event_list_.size());
   event_thread_name_ += " - " + std::to_string(fb_num_);
-  map_event_to_node_ = {{HWEvent::VSYNC, "vsync_event"}, {HWEvent::EXIT, "thread_exit"},
-    {HWEvent::IDLE_NOTIFY, "idle_notify"}, {HWEvent::SHOW_BLANK_EVENT, "show_blank_event"},
-    {HWEvent::CEC_READ_MESSAGE, "cec/rd_msg"}, {HWEvent::THERMAL_LEVEL, "msm_fb_thermal_level"},
-    {HWEvent::IDLE_POWER_COLLAPSE, "idle_power_collapse"}};
+  map_event_to_node_ = {{HWEvent::VSYNC, "vsync_event"},
+                        {HWEvent::EXIT, "thread_exit"},
+                        {HWEvent::IDLE_NOTIFY, "idle_notify"},
+                        {HWEvent::SHOW_BLANK_EVENT, "show_blank_event"},
+                        {HWEvent::CEC_READ_MESSAGE, "cec/rd_msg"},
+                        {HWEvent::THERMAL_LEVEL, "msm_fb_thermal_level"},
+                        {HWEvent::IDLE_POWER_COLLAPSE, "idle_power_collapse"},
+                        {HWEvent::PINGPONG_TIMEOUT, "pingpong_timeout"}};
 
   PopulateHWEventData();
 
@@ -223,6 +231,10 @@
   event_handler_->IdleTimeout();
 }
 
+void HWEvents::HandlePingPongTimeout(char *data) {
+  event_handler_->PingPongTimeout();
+}
+
 void HWEvents::HandleThermal(char *data) {
   int64_t thermal_level = 0;
   if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) {
diff --git a/sdm/libs/core/fb/hw_events.h b/sdm/libs/core/fb/hw_events.h
index 3d9cec8..8ffd6d5 100644
--- a/sdm/libs/core/fb/hw_events.h
+++ b/sdm/libs/core/fb/hw_events.h
@@ -42,7 +42,8 @@
 class HWEvents : public HWEventsInterface {
  public:
   virtual DisplayError Init(int fb_num, HWEventHandler *event_handler,
-                            const vector<HWEvent> &event_list);
+                            const vector<HWEvent> &event_list,
+                            const HWInterface *hw_intf);
   virtual DisplayError Deinit();
   virtual DisplayError SetEventState(HWEvent event, bool enable, void *aux = nullptr) {
     return kErrorNotSupported;
@@ -67,6 +68,7 @@
   void HandleCECMessage(char *data);
   void HandleThreadExit(char *data) { }
   void HandleIdlePowerCollapse(char *data);
+  void HandlePingPongTimeout(char *data);
   void PopulateHWEventData();
   DisplayError SetEventParser(HWEvent event_type, HWEventData *event_data);
   pollfd InitializePollFd(HWEventData *event_data);
diff --git a/sdm/libs/core/hw_events_interface.cpp b/sdm/libs/core/hw_events_interface.cpp
index ed62b86..5817cdb 100644
--- a/sdm/libs/core/hw_events_interface.cpp
+++ b/sdm/libs/core/hw_events_interface.cpp
@@ -42,7 +42,7 @@
 
 DisplayError HWEventsInterface::Create(int display_type, HWEventHandler *event_handler,
                                        const std::vector<HWEvent> &event_list,
-                                       HWEventsInterface **intf) {
+                                       const HWInterface *hw_intf, HWEventsInterface **intf) {
   DisplayError error = kErrorNone;
   HWEventsInterface *hw_events = nullptr;
   if (GetDriverType() == DriverType::FB) {
@@ -53,7 +53,7 @@
 #endif
   }
 
-  error = hw_events->Init(display_type, event_handler, event_list);
+  error = hw_events->Init(display_type, event_handler, event_list, hw_intf);
   if (error != kErrorNone) {
     delete hw_events;
   } else {
diff --git a/sdm/libs/core/hw_events_interface.h b/sdm/libs/core/hw_events_interface.h
index 482e077..090ff71 100644
--- a/sdm/libs/core/hw_events_interface.h
+++ b/sdm/libs/core/hw_events_interface.h
@@ -33,6 +33,7 @@
 namespace sdm {
 
 class HWEventHandler;
+class HWInterface;
 
 enum HWEvent {
   VSYNC = 0,
@@ -42,17 +43,20 @@
   SHOW_BLANK_EVENT,
   THERMAL_LEVEL,
   IDLE_POWER_COLLAPSE,
+  PINGPONG_TIMEOUT,
 };
 
 class HWEventsInterface {
  public:
   virtual DisplayError Init(int display_type, HWEventHandler *event_handler,
-                            const std::vector<HWEvent> &event_list) = 0;
+                            const std::vector<HWEvent> &event_list,
+                            const HWInterface *hw_intf) = 0;
   virtual DisplayError Deinit() = 0;
   virtual DisplayError SetEventState(HWEvent event, bool enable, void *aux = nullptr) = 0;
 
   static DisplayError Create(int display_type, HWEventHandler *event_handler,
-                             const std::vector<HWEvent> &event_list, HWEventsInterface **intf);
+                             const std::vector<HWEvent> &event_list,
+                             const HWInterface *hw_intf, HWEventsInterface **intf);
   static DisplayError Destroy(HWEventsInterface *intf);
 
  protected:
diff --git a/sdm/libs/core/hw_interface.cpp b/sdm/libs/core/hw_interface.cpp
index a7bcabd..f05aa0c 100644
--- a/sdm/libs/core/hw_interface.cpp
+++ b/sdm/libs/core/hw_interface.cpp
@@ -38,6 +38,7 @@
 #ifdef COMPILE_DRM
 #include "drm/hw_device_drm.h"
 #include "drm/hw_virtual_drm.h"
+#include "drm/hw_hdmi_drm.h"
 #endif
 
 #define __CLASS__ "HWInterface"
@@ -65,7 +66,9 @@
       if (driver_type == DriverType::FB) {
         hw = new HWHDMI(buffer_sync_handler, hw_info_intf);
       } else {
-        return kErrorNotSupported;
+#ifdef COMPILE_DRM
+        hw = new HWHDMIDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
+#endif
       }
       break;
     case kVirtual:
diff --git a/sdm/libs/core/hw_interface.h b/sdm/libs/core/hw_interface.h
index 5dbeb11..616e3fb 100644
--- a/sdm/libs/core/hw_interface.h
+++ b/sdm/libs/core/hw_interface.h
@@ -61,6 +61,7 @@
   virtual void ThermalEvent(int64_t thermal_level) = 0;
   virtual void CECMessage(char *message) = 0;
   virtual void IdlePowerCollapse() = 0;
+  virtual void PingPongTimeout() = 0;
 
  protected:
   virtual ~HWEventHandler() { }
@@ -110,6 +111,7 @@
   virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info) = 0;
   virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes) = 0;
   virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes) = 0;
+  virtual DisplayError DumpDebugData() = 0;
 
  protected:
   virtual ~HWInterface() { }
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
index 2d74941..8e89784 100644
--- a/sdm/libs/core/resource_default.cpp
+++ b/sdm/libs/core/resource_default.cpp
@@ -923,8 +923,9 @@
   return kErrorNone;
 }
 
-DisplayError ResourceDefault::ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
-                                                     int x, int y) {
+DisplayError ResourceDefault::ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers,
+                                                           int x, int y,
+                                                           DisplayConfigVariableInfo *fb_config) {
   return kErrorNotSupported;
 }
 
diff --git a/sdm/libs/core/resource_default.h b/sdm/libs/core/resource_default.h
index f835410..76d19f3 100644
--- a/sdm/libs/core/resource_default.h
+++ b/sdm/libs/core/resource_default.h
@@ -60,7 +60,8 @@
   virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90,
                                        BufferLayout layout, bool use_rotator_downscale);
   DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer, bool is_top);
-  DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
+  DisplayError ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y,
+                                            DisplayConfigVariableInfo *fb_config);
   DisplayError SetMaxBandwidthMode(HWBwModes mode);
   virtual DisplayError SetDetailEnhancerData(Handle display_ctx,
                                              const DisplayDetailEnhancerData &de_data);
diff --git a/sdm/libs/hwc/hwc_color_manager.h b/sdm/libs/hwc/hwc_color_manager.h
index 0f4247d..20d2b39 100644
--- a/sdm/libs/hwc/hwc_color_manager.h
+++ b/sdm/libs/hwc/hwc_color_manager.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -42,7 +42,7 @@
 
 // This macro defines name for display APIs interface wrapper library.
 // This macro shall be used to load library using dlopen().
-#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-apis.so"
+#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-vndapis.so"
 
 // This macro defines variable name of display color APIs function tables
 // This macro shall be used to specify name of the variable in dlsym().
diff --git a/sdm/libs/hwc/hwc_debugger.cpp b/sdm/libs/hwc/hwc_debugger.cpp
index 0cc0501..ffbb5c5 100644
--- a/sdm/libs/hwc/hwc_debugger.cpp
+++ b/sdm/libs/hwc/hwc_debugger.cpp
@@ -98,6 +98,16 @@
   }
 }
 
+void HWCDebugHandler::DebugScalar(bool enable, int verbose_level) {
+  if (enable) {
+    debug_flags_[kTagScalar] = 1;
+    verbose_level_ = verbose_level;
+  } else {
+    debug_flags_[kTagScalar] = 0;
+    verbose_level_ = 0;
+  }
+}
+
 void HWCDebugHandler::DebugQdcm(bool enable, int verbose_level) {
   if (enable) {
     debug_flags_[kTagQDCM] = 1;
diff --git a/sdm/libs/hwc/hwc_debugger.h b/sdm/libs/hwc/hwc_debugger.h
index 01319ab..82ff2f2 100644
--- a/sdm/libs/hwc/hwc_debugger.h
+++ b/sdm/libs/hwc/hwc_debugger.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -43,6 +43,7 @@
 class HWCDebugHandler : public DebugHandler {
  public:
   static inline DebugHandler* Get() { return &debug_handler_; }
+  static const char* DumpDir() { return "/data/vendor/display"; }
 
   static void DebugAll(bool enable, int verbose_level);
   static void DebugResources(bool enable, int verbose_level);
@@ -50,6 +51,7 @@
   static void DebugCompManager(bool enable, int verbose_level);
   static void DebugDriverConfig(bool enable, int verbose_level);
   static void DebugRotator(bool enable, int verbose_level);
+  static void DebugScalar(bool enable, int verbose_level);
   static void DebugQdcm(bool enable, int verbose_level);
   static int  GetIdleTimeoutMs();
 
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index 557b55f..9f1f3c7 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -19,14 +19,15 @@
 
 LOCAL_SHARED_LIBRARIES        := libsdmcore libqservice libbinder libhardware libhardware_legacy \
                                  libutils libcutils libsync libqdutils libqdMetaData libdl \
-                                 libpowermanager libsdmutils libc++ liblog libgrallocutils \
-                                 libui libgpu_tonemapper
+                                 libsdmutils libc++ liblog libgrallocutils libui libgpu_tonemapper \
+                                 libhidlbase libhidltransport vendor.display.config@1.0
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
     LOCAL_SHARED_LIBRARIES += libmemalloc
 endif
 
 LOCAL_SRC_FILES               := hwc_session.cpp \
+                                 hwc_session_services.cpp \
                                  hwc_display.cpp \
                                  hwc_display_primary.cpp \
                                  hwc_display_external.cpp \
@@ -38,7 +39,8 @@
                                  hwc_callbacks.cpp \
                                  ../hwc/cpuhint.cpp \
                                  ../hwc/hwc_socket_handler.cpp \
-                                 hwc_tonemapper.cpp
+                                 hwc_tonemapper.cpp \
+                                 display_null.cpp
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
     LOCAL_SRC_FILES += ../hwc/hwc_buffer_allocator.cpp
diff --git a/sdm/libs/hwc2/display_null.cpp b/sdm/libs/hwc2/display_null.cpp
new file mode 100644
index 0000000..16f4da6
--- /dev/null
+++ b/sdm/libs/hwc2/display_null.cpp
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "display_null.h"
+
+#define __CLASS__ "DisplayNull"
+
+namespace sdm {
+
+DisplayError DisplayNull::Commit(LayerStack *layer_stack) {
+  for (Layer *layer : layer_stack->layers) {
+    if (layer->composition != kCompositionGPUTarget) {
+      layer->composition = kCompositionSDE;
+      layer->input_buffer.release_fence_fd = -1;
+    }
+  }
+  layer_stack->retire_fence_fd = -1;
+
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetDisplayState(DisplayState *state) {
+  *state = state_;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::SetDisplayState(DisplayState state) {
+  state_ = state;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) {
+  fb_config_ = variable_info;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) {
+  *variable_info = fb_config_;
+  return kErrorNone;
+}
+
+}  // namespace sdm
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
new file mode 100644
index 0000000..fa88c28
--- /dev/null
+++ b/sdm/libs/hwc2/display_null.h
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_NULL_H__
+#define __DISPLAY_NULL_H__
+
+#include <core/display_interface.h>
+#include <string>
+#include <vector>
+
+namespace sdm {
+
+#define MAKE_NO_OP(virtual_method_name) \
+      virtual DisplayError virtual_method_name { return kErrorNone; }
+
+class DisplayNull : public DisplayInterface {
+ public:
+  virtual ~DisplayNull() { }
+  virtual DisplayError Commit(LayerStack *layer_stack);
+  virtual DisplayError GetDisplayState(DisplayState *state);
+  virtual DisplayError SetDisplayState(DisplayState state);
+  virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info);
+  virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info);
+  virtual bool IsUnderscanSupported() { return true; }
+  virtual void SetIdleTimeoutMs(uint32_t active_ms) { }
+  virtual bool IsPrimaryDisplay() { return true; }
+
+  void SetActive(bool active) {
+    active_ = active;
+  }
+
+  bool IsActive() {
+    return active_;
+  }
+
+  MAKE_NO_OP(Prepare(LayerStack *))
+  MAKE_NO_OP(Flush())
+  MAKE_NO_OP(GetNumVariableInfoConfigs(uint32_t *))
+  MAKE_NO_OP(GetConfig(uint32_t, DisplayConfigVariableInfo *))
+  MAKE_NO_OP(GetConfig(DisplayConfigFixedInfo *))
+  MAKE_NO_OP(GetActiveConfig(uint32_t *))
+  MAKE_NO_OP(GetVSyncState(bool *))
+  MAKE_NO_OP(SetActiveConfig(uint32_t))
+  MAKE_NO_OP(SetActiveConfig(DisplayConfigVariableInfo *))
+  MAKE_NO_OP(SetMaxMixerStages(uint32_t))
+  MAKE_NO_OP(ControlPartialUpdate(bool, uint32_t *))
+  MAKE_NO_OP(DisablePartialUpdateOneFrame())
+  MAKE_NO_OP(SetDisplayMode(uint32_t))
+  MAKE_NO_OP(SetPanelBrightness(int))
+  MAKE_NO_OP(CachePanelBrightness(int))
+  MAKE_NO_OP(OnMinHdcpEncryptionLevelChange(uint32_t))
+  MAKE_NO_OP(ColorSVCRequestRoute(const PPDisplayAPIPayload &, PPDisplayAPIPayload *,
+                                  PPPendingParams *))
+  MAKE_NO_OP(GetColorModeCount(uint32_t *))
+  MAKE_NO_OP(GetColorModes(uint32_t *, std::vector<std::string> *))
+  MAKE_NO_OP(GetColorModeAttr(const std::string &, AttrVal *))
+  MAKE_NO_OP(SetColorMode(const std::string &))
+  MAKE_NO_OP(SetColorModeById(int32_t))
+  MAKE_NO_OP(SetColorTransform(const uint32_t, const double *))
+  MAKE_NO_OP(GetDefaultColorMode(std::string *))
+  MAKE_NO_OP(ApplyDefaultDisplayMode())
+  MAKE_NO_OP(SetCursorPosition(int, int))
+  MAKE_NO_OP(GetRefreshRateRange(uint32_t *, uint32_t *))
+  MAKE_NO_OP(SetRefreshRate(uint32_t, bool))
+  MAKE_NO_OP(GetPanelBrightness(int *))
+  MAKE_NO_OP(SetVSyncState(bool))
+  MAKE_NO_OP(SetMixerResolution(uint32_t, uint32_t))
+  MAKE_NO_OP(GetMixerResolution(uint32_t *, uint32_t *))
+  MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &))
+  MAKE_NO_OP(GetDisplayPort(DisplayPort *))
+  MAKE_NO_OP(SetCompositionState(LayerComposition, bool))
+
+ private:
+  bool active_ = false;
+  DisplayState state_ = kStateOff;
+  DisplayConfigVariableInfo fb_config_ = {};
+};
+
+}  // namespace sdm
+
+#endif  // __DISPLAY_NULL_H__
diff --git a/sdm/libs/hwc2/hwc_color_manager.cpp b/sdm/libs/hwc2/hwc_color_manager.cpp
index 9f336a0..afa9a4e 100644
--- a/sdm/libs/hwc2/hwc_color_manager.cpp
+++ b/sdm/libs/hwc2/hwc_color_manager.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -28,7 +28,6 @@
 */
 
 #include <dlfcn.h>
-#include <powermanager/IPowerManager.h>
 #include <cutils/sockets.h>
 #include <cutils/native_handle.h>
 #include <utils/String16.h>
@@ -272,7 +271,6 @@
   PPDETuningCfgData *de_tuning_cfg_data = reinterpret_cast<PPDETuningCfgData*>(params);
   if (de_tuning_cfg_data->cfg_pending == true) {
     if (!de_tuning_cfg_data->cfg_en) {
-      de_data.override_flags = kOverrideDEEnable;
       de_data.enable = 0;
     } else {
       de_data.override_flags = kOverrideDEEnable;
@@ -386,17 +384,6 @@
 
     // retrieve system GPU idle timeout value for later to recover.
     mode_mgr->entry_timeout_ = UINT32(HWCDebugHandler::GetIdleTimeoutMs());
-
-    // acquire the binder handle to Android system PowerManager for later use.
-    android::sp<android::IBinder> binder =
-        android::defaultServiceManager()->checkService(android::String16("power"));
-    if (binder == NULL) {
-      DLOGW("Application can't connect to  power manager service");
-      delete mode_mgr;
-      mode_mgr = NULL;
-    } else {
-      mode_mgr->power_mgr_ = android::interface_cast<android::IPowerManager>(binder);
-    }
   }
 
   return mode_mgr;
@@ -407,30 +394,6 @@
     ::close(socket_fd_);
 }
 
-int HWCQDCMModeManager::AcquireAndroidWakeLock(bool enable) {
-  int ret = 0;
-
-  if (enable) {
-    if (wakelock_token_ == NULL) {
-      android::sp<android::IBinder> binder = new android::BBinder();
-      android::status_t status = power_mgr_->acquireWakeLock(
-          (kFullWakeLock | kAcquireCauseWakeup | kONAfterRelease), binder,
-          android::String16(kTagName), android::String16(kPackageName));
-      if (status == android::NO_ERROR) {
-        wakelock_token_ = binder;
-      }
-    }
-  } else {
-    if (wakelock_token_ != NULL && power_mgr_ != NULL) {
-      power_mgr_->releaseWakeLock(wakelock_token_, 0);
-      wakelock_token_.clear();
-      wakelock_token_ = NULL;
-    }
-  }
-
-  return ret;
-}
-
 int HWCQDCMModeManager::EnableActiveFeatures(bool enable,
                                              const HWCQDCMModeManager::ActiveFeatureCMD &cmds,
                                              bool *was_running) {
@@ -486,7 +449,6 @@
 
   ret = EnableActiveFeatures((enable ? false : true), kActiveFeatureCMD[kCABLFeature],
                              &cabl_was_running_);
-  ret = AcquireAndroidWakeLock(enable);
 
   // if enter QDCM mode, disable GPU fallback idle timeout.
   if (hwc_display) {
diff --git a/sdm/libs/hwc2/hwc_color_manager.h b/sdm/libs/hwc2/hwc_color_manager.h
index 32f7f5f..f88a5bb 100644
--- a/sdm/libs/hwc2/hwc_color_manager.h
+++ b/sdm/libs/hwc2/hwc_color_manager.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -32,7 +32,6 @@
 
 #include <stdlib.h>
 #include <binder/Parcel.h>
-#include <powermanager/IPowerManager.h>
 #include <binder/BinderService.h>
 #include <core/sdm_types.h>
 #include <utils/locker.h>
@@ -41,7 +40,7 @@
 
 // This macro defines name for display APIs interface wrapper library.
 // This macro shall be used to load library using dlopen().
-#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-apis.so"
+#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-vndapis.so"
 
 // This macro defines variable name of display color APIs function tables
 // This macro shall be used to specify name of the variable in dlsym().
@@ -94,7 +93,6 @@
   bool cabl_was_running_ = false;
   int socket_fd_ = -1;
   android::sp<android::IBinder> wakelock_token_ = NULL;
-  android::sp<android::IPowerManager> power_mgr_ = NULL;
   uint32_t entry_timeout_ = 0;
   static const char *const kSocketName;
   static const char *const kTagName;
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 4f623ce..0331464 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1336,7 +1336,8 @@
     return;
   }
 
-  snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString());
+  snprintf(dir_path, sizeof(dir_path), "%s/frame_dump_%s", HWCDebugHandler::DumpDir(),
+           GetDisplayString());
 
   if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) {
     DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
@@ -1385,7 +1386,8 @@
 void HWCDisplay::DumpOutputBuffer(const BufferInfo &buffer_info, void *base, int fence) {
   char dir_path[PATH_MAX];
 
-  snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString());
+  snprintf(dir_path, sizeof(dir_path), "%s/frame_dump_%s", HWCDebugHandler::DumpDir(),
+           GetDisplayString());
 
   if (mkdir(dir_path, 777) != 0 && errno != EEXIST) {
     DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
@@ -1523,7 +1525,7 @@
   *y_pixels = display_config.y_pixels;
 }
 
-int HWCDisplay::SetDisplayStatus(uint32_t display_status) {
+int HWCDisplay::SetDisplayStatus(DisplayStatus display_status) {
   int status = 0;
 
   switch (display_status) {
@@ -1598,6 +1600,7 @@
     auto layer = hwc_layer->GetSDMLayer();
     layer->composition = kCompositionSDE;
   }
+  validated_ = true;
 }
 
 void HWCDisplay::MarkLayersForClientComposition() {
@@ -1726,8 +1729,8 @@
   return;
 }
 
-int HWCDisplay::SetActiveDisplayConfig(int config) {
-  return display_intf_->SetActiveConfig(UINT32(config)) == kErrorNone ? 0 : -1;
+int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
+  return display_intf_->SetActiveConfig(config) == kErrorNone ? 0 : -1;
 }
 
 int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) {
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 1b04c84..b70f160 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -20,6 +20,7 @@
 #ifndef __HWC_DISPLAY_H__
 #define __HWC_DISPLAY_H__
 
+#include <sys/stat.h>
 #include <QService.h>
 #include <core/core_interface.h>
 #include <hardware/hwcomposer.h>
@@ -92,6 +93,14 @@
 
 class HWCDisplay : public DisplayEventHandler {
  public:
+  enum DisplayStatus {
+    kDisplayStatusInvalid = -1,
+    kDisplayStatusOffline,
+    kDisplayStatusOnline,
+    kDisplayStatusPause,
+    kDisplayStatusResume,
+  };
+
   virtual ~HWCDisplay() {}
   virtual int Init();
   virtual int Deinit();
@@ -106,7 +115,7 @@
   virtual HWC2::PowerMode GetLastPowerMode();
   virtual int SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels);
   virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels);
-  virtual int SetDisplayStatus(uint32_t display_status);
+  virtual int SetDisplayStatus(DisplayStatus display_status);
   virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
   virtual int Perform(uint32_t operation, ...);
   virtual void SetSecureDisplay(bool secure_display_active);
@@ -132,7 +141,7 @@
   }
 
   // Display Configurations
-  virtual int SetActiveDisplayConfig(int config);
+  virtual int SetActiveDisplayConfig(uint32_t config);
   virtual int GetActiveDisplayConfig(uint32_t *config);
   virtual int GetDisplayConfigCount(uint32_t *count);
   virtual int GetDisplayAttributesForConfig(int config,
@@ -150,6 +159,9 @@
     return INT32(status);
   }
 
+  virtual int SetState(bool connected) {
+    return kErrorNotSupported;
+  }
   int SetPanelBrightness(int level);
   int GetPanelBrightness(int *level);
   int ToggleScreenUpdates(bool enable);
@@ -211,13 +223,6 @@
                                          float* out_min_luminance);
 
  protected:
-  enum DisplayStatus {
-    kDisplayStatusOffline = 0,
-    kDisplayStatusOnline,
-    kDisplayStatusPause,
-    kDisplayStatusResume,
-  };
-
   // Maximum number of layers supported by display manager.
   static const uint32_t kMaxLayerCount = 32;
 
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index a8f8480..e89451d 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -64,6 +64,7 @@
 
   error = hwc_display_external->GetMixerResolution(&external_width, &external_height);
   if (error != kErrorNone) {
+    Destroy(hwc_display_external);
     return -EINVAL;
   }
 
@@ -215,4 +216,65 @@
   }
 }
 
+int HWCDisplayExternal::SetState(bool connected) {
+  DisplayError error = kErrorNone;
+  DisplayState state = kStateOff;
+  DisplayConfigVariableInfo fb_config = {};
+
+  if (connected) {
+    if (display_null_.IsActive()) {
+      error = core_intf_->CreateDisplay(type_, this, &display_intf_);
+      if (error != kErrorNone) {
+        DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p",
+              error, type_, this, &display_intf_);
+        return -EINVAL;
+      }
+
+      // Restore HDMI attributes when display is reconnected.
+      // This is to ensure that surfaceflinger & sdm are in sync.
+      display_null_.GetFrameBufferConfig(&fb_config);
+      int status = SetFrameBufferResolution(fb_config.x_pixels, fb_config.y_pixels);
+      if (status) {
+        DLOGW("Set frame buffer config failed. Error = %d", error);
+        return -1;
+      }
+
+      display_null_.GetDisplayState(&state);
+      display_intf_->SetDisplayState(state);
+
+      SetVsyncEnabled(HWC2::Vsync::Enable);
+
+      display_null_.SetActive(false);
+      DLOGI("Display is connected successfully.");
+    } else {
+      DLOGI("Display is already connected.");
+    }
+  } else {
+    if (!display_null_.IsActive()) {
+      // Preserve required attributes of HDMI display that surfaceflinger sees.
+      // Restore HDMI attributes when display is reconnected.
+      display_intf_->GetDisplayState(&state);
+      display_null_.SetDisplayState(state);
+
+      error = display_intf_->GetFrameBufferConfig(&fb_config);
+      if (error != kErrorNone) {
+        DLOGW("Get frame buffer config failed. Error = %d", error);
+        return -1;
+      }
+      display_null_.SetFrameBufferConfig(fb_config);
+
+      SetVsyncEnabled(HWC2::Vsync::Disable);
+      core_intf_->DestroyDisplay(display_intf_);
+      display_intf_ = &display_null_;
+
+      display_null_.SetActive(true);
+      DLOGI("Display is disconnected successfully.");
+    } else {
+      DLOGI("Display is already disconnected.");
+    }
+  }
+
+  return 0;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 802a77c..7aa84b2 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -31,6 +31,7 @@
 #define __HWC_DISPLAY_EXTERNAL_H__
 
 #include "hwc_display.h"
+#include "display_null.h"
 
 namespace sdm {
 
@@ -47,6 +48,7 @@
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
   virtual void SetSecureDisplay(bool secure_display_active);
+  virtual int SetState(bool connected);
 
  private:
   HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
@@ -54,6 +56,8 @@
   void ApplyScanAdjustment(hwc_rect_t *display_frame);
   static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
                                      uint32_t *virtual_width, uint32_t *virtual_height);
+
+  DisplayNull display_null_;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 2fcf2a9..b82a46e 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -521,12 +521,12 @@
   GetPanelResolution(&panel_width, &panel_height);
   GetFrameBufferResolution(&fb_width, &fb_height);
 
-  if (post_processed_output && (output_buffer_info_.buffer_config.width < panel_width ||
-                                output_buffer_info_.buffer_config.height < panel_height)) {
+  if (post_processed_output && (output_buffer_info.buffer_config.width < panel_width ||
+                                output_buffer_info.buffer_config.height < panel_height)) {
     DLOGE("Buffer dimensions should not be less than panel resolution");
     return -1;
-  } else if (!post_processed_output && (output_buffer_info_.buffer_config.width < fb_width ||
-                                        output_buffer_info_.buffer_config.height < fb_height)) {
+  } else if (!post_processed_output && (output_buffer_info.buffer_config.width < fb_width ||
+                                        output_buffer_info.buffer_config.height < fb_height)) {
     DLOGE("Buffer dimensions should not be less than FB resolution");
     return -1;
   }
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index f77e9c9..8ac9be6 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -59,15 +59,15 @@
     return status;
   }
 
-  status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On));
+  status = hwc_display_virtual->SetConfig(width, height);
   if (status) {
-    DLOGW("Failed to set power mode on virtual display");
     Destroy(hwc_display_virtual);
     return status;
   }
 
-  status = hwc_display_virtual->SetConfig(width, height);
+  status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On));
   if (status) {
+    DLOGW("Failed to set power mode on virtual display");
     Destroy(hwc_display_virtual);
     return status;
   }
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index d9857ce..015dc75 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -278,6 +278,17 @@
   layer_->transform = layer_transform_;
 }
 
+HWC2::Error HWCLayer::SetCursorPosition(int32_t x, int32_t y) {
+  hwc_rect_t frame = {};
+  frame.left = x;
+  frame.top = y;
+  frame.right = x + INT(layer_->dst_rect.right - layer_->dst_rect.left);
+  frame.bottom = y + INT(layer_->dst_rect.bottom - layer_->dst_rect.top);
+  SetLayerDisplayFrame(frame);
+
+  return HWC2::Error::None;
+}
+
 HWC2::Error HWCLayer::SetLayerPlaneAlpha(float alpha) {
   // Conversion of float alpha in range 0.0 to 1.0 similar to the HWC Adapter
   uint8_t plane_alpha = static_cast<uint8_t>(std::round(255.0f * alpha));
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 82bf466..b42699d 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -69,6 +69,7 @@
   HWC2::Error SetLayerCompositionType(HWC2::Composition type);
   HWC2::Error SetLayerDataspace(int32_t dataspace);
   HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame);
+  HWC2::Error SetCursorPosition(int32_t x, int32_t y);
   HWC2::Error SetLayerPlaneAlpha(float alpha);
   HWC2::Error SetLayerSourceCrop(hwc_frect_t crop);
   HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage);
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 2bf7d4d..87eb56b 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -47,6 +47,7 @@
 
 #define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi"
 #define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0"
+#define HWC_UEVENT_DRM_EXT_HOTPLUG "mdss_mdp/drm/card"
 
 static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods;
 
@@ -93,9 +94,9 @@
     return -EINVAL;
   }
 
-  buffer_allocator_ = new HWCBufferAllocator();
+  StartServices();
 
-  DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), buffer_allocator_,
+  DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
                                                  &buffer_sync_handler_, &socket_handler_,
                                                  &core_intf_);
   if (error != kErrorNone) {
@@ -103,20 +104,31 @@
     return -EINVAL;
   }
 
-  // Read which display is first, and create it and store it in primary slot
-  // TODO(user): This will need to be redone for HWC2 - right now we validate only
-  // the primary physical path
-  HWDisplayInterfaceInfo hw_disp_info;
+  // If HDMI display is primary display, defer display creation until hotplug event is received.
+  HWDisplayInterfaceInfo hw_disp_info = {};
   error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
-  if (error == kErrorNone && hw_disp_info.type == kHDMI && hw_disp_info.is_connected) {
-    // HDMI is primary display. If already connected, then create it and store in
-    // primary display slot. If not connected, create a NULL display for now.
-    status = HWCDisplayExternal::Create(core_intf_, buffer_allocator_, &callbacks_, qservice_,
-                                        &hwc_display_[HWC_DISPLAY_PRIMARY]);
+  if (error != kErrorNone) {
+    CoreInterface::DestroyCore();
+    DLOGE("Primary display type not recognized. Error = %d", error);
+    return -EINVAL;
+  }
+
+  if (hw_disp_info.type == kHDMI) {
+    status = 0;
+    hdmi_is_primary_ = true;
+    // Create display if it is connected, else wait for hotplug connect event.
+    if (hw_disp_info.is_connected) {
+      status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
+                                          &hwc_display_[HWC_DISPLAY_PRIMARY]);
+    }
   } else {
     // Create and power on primary display
-    status = HWCDisplayPrimary::Create(core_intf_, buffer_allocator_, &callbacks_, qservice_,
+    status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
                                        &hwc_display_[HWC_DISPLAY_PRIMARY]);
+    color_mgr_ = HWCColorManager::CreateColorManager(&buffer_allocator_);
+    if (!color_mgr_) {
+      DLOGW("Failed to load HWCColorManager.");
+    }
   }
 
   if (status) {
@@ -124,19 +136,6 @@
     return status;
   }
 
-  color_mgr_ = HWCColorManager::CreateColorManager(buffer_allocator_);
-  if (!color_mgr_) {
-    DLOGW("Failed to load HWCColorManager.");
-  }
-
-  if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
-    DLOGE("Failed to start = %s, error = %s", uevent_thread_name_, strerror(errno));
-    HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
-    hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
-    CoreInterface::DestroyCore();
-    return -errno;
-  }
-
   struct rlimit fd_limit = {};
   getrlimit(RLIMIT_NOFILE, &fd_limit);
   fd_limit.rlim_cur = fd_limit.rlim_cur * 2;
@@ -146,31 +145,38 @@
       DLOGW("Unable to increase fd limit -  err:%d, %s", errno, strerror(errno));
     }
   }
+
+  std::thread uevent_thread(HWCUeventThread, this);
+  uevent_thread_.swap(uevent_thread);
+
   return 0;
 }
 
 int HWCSession::Deinit() {
-  HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
-  hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
+  HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+  if (primary_display) {
+    if (hdmi_is_primary_) {
+      HWCDisplayExternal::Destroy(primary_display);
+    } else {
+      HWCDisplayPrimary::Destroy(primary_display);
+    }
+  }
+  hwc_display_[HWC_DISPLAY_PRIMARY] = nullptr;
+
   if (color_mgr_) {
     color_mgr_->DestroyColorManager();
   }
-  uevent_thread_exit_ = true;
+
   DLOGD("Terminating uevent thread");
-  // TODO(user): on restarting HWC in the same process, the uevent thread does not restart
-  // cleanly.
-  Sys::pthread_cancel_(uevent_thread_);
+  uevent_thread_exit_ = true;
+  // todo(user): add a local event to interrupt thread execution and join.
+  uevent_thread_.detach();
 
   DisplayError error = CoreInterface::DestroyCore();
   if (error != kErrorNone) {
     DLOGE("Display core de-initialization failed. Error = %d", error);
   }
 
-  if (buffer_allocator_ != nullptr) {
-    delete buffer_allocator_;
-  }
-  buffer_allocator_ = nullptr;
-
   return 0;
 }
 
@@ -433,8 +439,13 @@
   auto desc = static_cast<HWC2::Callback>(descriptor);
   auto error = hwc_session->callbacks_.Register(desc, callback_data, pointer);
   DLOGD("Registering callback: %s", to_string(desc).c_str());
-  if (descriptor == HWC2_CALLBACK_HOTPLUG)
-    hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected);
+  if (descriptor == HWC2_CALLBACK_HOTPLUG) {
+    // If primary display (HDMI) is not created yet, wait for it to be hotplugged.
+    if (hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY]) {
+      hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected);
+    }
+  }
+
   return INT32(error);
 }
 
@@ -468,8 +479,14 @@
 
 static int32_t SetCursorPosition(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer,
                                  int32_t x, int32_t y) {
-  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetCursorPosition, layer, x,
-                                         y);
+  auto status = INT32(HWC2::Error::None);
+  status = HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetCursorPosition,
+                                           layer, x, y);
+  if (status == INT32(HWC2::Error::None)) {
+    // Update cursor position
+    HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetCursorPosition, x, y);
+  }
+  return status;
 }
 
 static int32_t SetLayerBlendMode(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer,
@@ -716,7 +733,7 @@
   if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
     return HWC2::Error::NoResources;
   }
-  auto status = HWCDisplayVirtual::Create(core_intf_, buffer_allocator_, &callbacks_, width,
+  auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width,
                                           height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
   // TODO(user): validate width and height support
   if (status)
@@ -735,7 +752,7 @@
   hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
 
   if (disp == HWC_DISPLAY_EXTERNAL) {
-    status = HWCDisplayExternal::Create(core_intf_, buffer_allocator_, &callbacks_, primary_width,
+    status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, primary_width,
                                         primary_height, qservice_, false, &hwc_display_[disp]);
   } else {
     DLOGE("Invalid display type");
@@ -769,8 +786,6 @@
 // Qclient methods
 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
-
   android::status_t status = 0;
 
   switch (command) {
@@ -779,14 +794,11 @@
       break;
 
     case qService::IQService::SCREEN_REFRESH:
-      callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+      refreshScreen();
       break;
 
     case qService::IQService::SET_IDLE_TIMEOUT:
-      if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-        uint32_t timeout = UINT32(input_parcel->readInt32());
-        hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(timeout);
-      }
+      setIdleTimeout(UINT32(input_parcel->readInt32()));
       break;
 
     case qService::IQService::SET_FRAME_DUMP_CONFIG:
@@ -801,8 +813,13 @@
       status = SetDisplayMode(input_parcel);
       break;
 
-    case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
-      status = SetSecondaryDisplayStatus(input_parcel, output_parcel);
+    case qService::IQService::SET_SECONDARY_DISPLAY_STATUS: {
+        int disp_id = INT(input_parcel->readInt32());
+        HWCDisplay::DisplayStatus disp_status =
+              static_cast<HWCDisplay::DisplayStatus>(input_parcel->readInt32());
+        status = SetSecondaryDisplayStatus(disp_id, disp_status);
+        output_parcel->writeInt32(status);
+      }
       break;
 
     case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
@@ -812,56 +829,89 @@
     case qService::IQService::SET_VIEW_FRAME:
       break;
 
-    case qService::IQService::TOGGLE_SCREEN_UPDATES:
-      status = ToggleScreenUpdates(input_parcel, output_parcel);
+    case qService::IQService::TOGGLE_SCREEN_UPDATES: {
+        int32_t input = input_parcel->readInt32();
+        status = toggleScreenUpdate(input == 1);
+        output_parcel->writeInt32(status);
+      }
       break;
 
     case qService::IQService::QDCM_SVC_CMDS:
       status = QdcmCMDHandler(input_parcel, output_parcel);
       break;
 
-    case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED:
-      status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel);
+    case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t min_enc_level = UINT32(input_parcel->readInt32());
+        status = MinHdcpEncryptionLevelChanged(disp_id, min_enc_level);
+        output_parcel->writeInt32(status);
+      }
       break;
 
-    case qService::IQService::CONTROL_PARTIAL_UPDATE:
-      status = ControlPartialUpdate(input_parcel, output_parcel);
+    case qService::IQService::CONTROL_PARTIAL_UPDATE: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t enable = UINT32(input_parcel->readInt32());
+        status = ControlPartialUpdate(disp_id, enable == 1);
+        output_parcel->writeInt32(status);
+      }
       break;
 
-    case qService::IQService::SET_ACTIVE_CONFIG:
-      status = HandleSetActiveDisplayConfig(input_parcel, output_parcel);
+    case qService::IQService::SET_ACTIVE_CONFIG: {
+        uint32_t config = UINT32(input_parcel->readInt32());
+        int disp_id = input_parcel->readInt32();
+        status = SetActiveConfigIndex(disp_id, config);
+      }
       break;
 
-    case qService::IQService::GET_ACTIVE_CONFIG:
-      status = HandleGetActiveDisplayConfig(input_parcel, output_parcel);
+    case qService::IQService::GET_ACTIVE_CONFIG: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t config = 0;
+        status = GetActiveConfigIndex(disp_id, &config);
+        output_parcel->writeInt32(INT(config));
+      }
       break;
 
-    case qService::IQService::GET_CONFIG_COUNT:
-      status = HandleGetDisplayConfigCount(input_parcel, output_parcel);
+    case qService::IQService::GET_CONFIG_COUNT: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t count = 0;
+        status = GetConfigCount(disp_id, &count);
+        output_parcel->writeInt32(INT(count));
+      }
       break;
 
     case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
       status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel);
       break;
 
-    case qService::IQService::GET_PANEL_BRIGHTNESS:
-      status = GetPanelBrightness(input_parcel, output_parcel);
+    case qService::IQService::GET_PANEL_BRIGHTNESS: {
+        int level = 0;
+        status = GetPanelBrightness(&level);
+        output_parcel->writeInt32(level);
+      }
       break;
 
-    case qService::IQService::SET_PANEL_BRIGHTNESS:
-      status = SetPanelBrightness(input_parcel, output_parcel);
+    case qService::IQService::SET_PANEL_BRIGHTNESS: {
+        uint32_t level = UINT32(input_parcel->readInt32());
+        status = setPanelBrightness(level);
+        output_parcel->writeInt32(status);
+      }
       break;
 
     case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
       status = GetVisibleDisplayRect(input_parcel, output_parcel);
       break;
 
-    case qService::IQService::SET_CAMERA_STATUS:
-      status = SetDynamicBWForCamera(input_parcel, output_parcel);
+    case qService::IQService::SET_CAMERA_STATUS: {
+        uint32_t camera_status = UINT32(input_parcel->readInt32());
+        status = setCameraLaunchStatus(camera_status);
+      }
       break;
 
-    case qService::IQService::GET_BW_TRANSACTION_STATUS:
-      status = GetBWTransactionStatus(input_parcel, output_parcel);
+    case qService::IQService::GET_BW_TRANSACTION_STATUS: {
+        bool state = true;
+        status = DisplayBWTransactionPending(&state);
+        output_parcel->writeInt32(state);
+      }
       break;
 
     case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
@@ -884,167 +934,11 @@
   return status;
 }
 
-android::status_t HWCSession::ToggleScreenUpdates(const android::Parcel *input_parcel,
-                                                  android::Parcel *output_parcel) {
-  int input = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY] && (input <= 1) && (input >= 0)) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(input == 1);
-    if (error != 0) {
-      DLOGE("Failed to toggle screen updates = %d. Error = %d", input, error);
-    }
-  }
-  output_parcel->writeInt32(error);
-
-  return error;
-}
-
-android::status_t HWCSession::SetPanelBrightness(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel) {
-  int level = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(level);
-    if (error != 0) {
-      DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
-    }
-  }
-  output_parcel->writeInt32(error);
-
-  return error;
-}
-
-android::status_t HWCSession::GetPanelBrightness(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel) {
-  int error = android::BAD_VALUE;
-  int ret = error;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(&ret);
-    if (error != 0) {
-      ret = error;
-      DLOGE("Failed to get the panel brightness. Error = %d", error);
-    }
-  }
-  output_parcel->writeInt32(ret);
-
-  return error;
-}
-
-android::status_t HWCSession::ControlPartialUpdate(const android::Parcel *input_parcel,
-                                                   android::Parcel *out) {
-  DisplayError error = kErrorNone;
-  int ret = 0;
-  uint32_t disp_id = UINT32(input_parcel->readInt32());
-  uint32_t enable = UINT32(input_parcel->readInt32());
-
-  if (disp_id != HWC_DISPLAY_PRIMARY) {
-    DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
-    ret = -EINVAL;
-    out->writeInt32(ret);
-    return ret;
-  }
-
-  if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    DLOGE("primary display object is not instantiated");
-    ret = -EINVAL;
-    out->writeInt32(ret);
-    return ret;
-  }
-
-  uint32_t pending = 0;
-  error = hwc_display_[HWC_DISPLAY_PRIMARY]->ControlPartialUpdate(enable, &pending);
-
-  if (error == kErrorNone) {
-    if (!pending) {
-      out->writeInt32(ret);
-      return ret;
-    }
-  } else if (error == kErrorNotSupported) {
-    out->writeInt32(ret);
-    return ret;
-  } else {
-    ret = -EINVAL;
-    out->writeInt32(ret);
-    return ret;
-  }
-
-  // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
-  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
-
-  // Wait until partial update control is complete
-  ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
-
-  out->writeInt32(ret);
-
-  return ret;
-}
-
-android::status_t HWCSession::HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                           android::Parcel *output_parcel) {
-  int config = input_parcel->readInt32();
-  int dpy = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
-    return android::BAD_VALUE;
-  }
-
-  if (hwc_display_[dpy]) {
-    error = hwc_display_[dpy]->SetActiveDisplayConfig(config);
-    if (error == 0) {
-      callbacks_.Refresh(0);
-    }
-  }
-
-  return error;
-}
-
-android::status_t HWCSession::HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                           android::Parcel *output_parcel) {
-  int dpy = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
-    return android::BAD_VALUE;
-  }
-
-  if (hwc_display_[dpy]) {
-    uint32_t config = 0;
-    error = hwc_display_[dpy]->GetActiveDisplayConfig(&config);
-    if (error == 0) {
-      output_parcel->writeInt32(INT(config));
-    }
-  }
-
-  return error;
-}
-
-android::status_t HWCSession::HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
-                                                          android::Parcel *output_parcel) {
-  int dpy = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
-    return android::BAD_VALUE;
-  }
-
-  uint32_t count = 0;
-  if (hwc_display_[dpy]) {
-    error = hwc_display_[dpy]->GetDisplayConfigCount(&count);
-    if (error == 0) {
-      output_parcel->writeInt32(INT(count));
-    }
-  }
-
-  return error;
-}
-
 android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
                                                                   *input_parcel,
                                                                   android::Parcel *output_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int config = input_parcel->readInt32();
   int dpy = input_parcel->readInt32();
   int error = android::BAD_VALUE;
@@ -1069,44 +963,24 @@
   return error;
 }
 
-android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
-                                                        android::Parcel *output_parcel) {
-  int ret = -EINVAL;
-
-  uint32_t display_id = UINT32(input_parcel->readInt32());
-  uint32_t display_status = UINT32(input_parcel->readInt32());
-
-  DLOGI("Display = %d, Status = %d", display_id, display_status);
-
-  if (display_id >= HWC_NUM_DISPLAY_TYPES) {
-    DLOGE("Invalid display_id");
-  } else if (display_id == HWC_DISPLAY_PRIMARY) {
-    DLOGE("Not supported for this display");
-  } else if (!hwc_display_[display_id]) {
-    DLOGW("Display is not connected");
-  } else {
-    ret = hwc_display_[display_id]->SetDisplayStatus(display_status);
-  }
-
-  output_parcel->writeInt32(ret);
-
-  return ret;
-}
-
 android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   uint32_t operation = UINT32(input_parcel->readInt32());
+  HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+
   switch (operation) {
     case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
-      return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
-          HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+
     case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE:
-      return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
-          HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+
     case qdutils::SET_BINDER_DYN_REFRESH_RATE: {
       uint32_t refresh_rate = UINT32(input_parcel->readInt32());
-      return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
-          HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refresh_rate);
+      return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refresh_rate);
     }
+
     default:
       DLOGW("Invalid operation %d", operation);
       return -EINVAL;
@@ -1116,11 +990,15 @@
 }
 
 android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   uint32_t mode = UINT32(input_parcel->readInt32());
   return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
 }
 
 android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   DisplayError error = kErrorNone;
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
@@ -1155,42 +1033,9 @@
   return 0;
 }
 
-android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
-                                                    android::Parcel *output_parcel) {
-  DisplayError error = kErrorNone;
-  uint32_t camera_status = UINT32(input_parcel->readInt32());
-  HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
-
-  // trigger invalidate to apply new bw caps.
-  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
-
-  error = core_intf_->SetMaxBandwidthMode(mode);
-  if (error != kErrorNone) {
-    return -EINVAL;
-  }
-
-  new_bw_mode_ = true;
-  need_invalidate_ = true;
-
-  return 0;
-}
-
-android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
-                                                     android::Parcel *output_parcel) {
-  bool state = true;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    if (sync_wait(bw_mode_release_fd_, 0) < 0) {
-      DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
-      state = false;
-    }
-    output_parcel->writeInt32(state);
-  }
-
-  return 0;
-}
-
 void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
@@ -1215,6 +1060,8 @@
 }
 
 android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   DisplayError error = kErrorNone;
   uint32_t dpy = UINT32(input_parcel->readInt32());
 
@@ -1240,6 +1087,8 @@
 }
 
 android::status_t HWCSession::SetColorModeOverride(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   auto display = static_cast<hwc2_display_t >(input_parcel->readInt32());
   auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32());
   auto device = static_cast<hwc2_device_t *>(this);
@@ -1260,6 +1109,8 @@
 }
 
 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int type = input_parcel->readInt32();
   bool enable = (input_parcel->readInt32() > 0);
   DLOGI("type = %d enable = %d", type, enable);
@@ -1293,6 +1144,10 @@
       HWCDebugHandler::DebugQdcm(enable, verbose_level);
       break;
 
+    case qService::IQService::DEBUG_SCALAR:
+      HWCDebugHandler::DebugScalar(enable, verbose_level);
+      break;
+
     default:
       DLOGW("type = %d is not supported", type);
   }
@@ -1300,6 +1155,8 @@
 
 android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int ret = 0;
   int32_t *brightness_value = NULL;
   uint32_t display_id(0);
@@ -1391,29 +1248,6 @@
   return (ret ? -EINVAL : 0);
 }
 
-android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
-                                                             android::Parcel *output_parcel) {
-  int ret = -EINVAL;
-  uint32_t display_id = UINT32(input_parcel->readInt32());
-  uint32_t min_enc_level = UINT32(input_parcel->readInt32());
-
-  DLOGI("Display %d", display_id);
-
-  if (display_id >= HWC_NUM_DISPLAY_TYPES) {
-    DLOGE("Invalid display_id");
-  } else if (display_id != HWC_DISPLAY_EXTERNAL) {
-    DLOGE("Not supported for display");
-  } else if (!hwc_display_[display_id]) {
-    DLOGW("Display is not connected");
-  } else {
-    ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
-  }
-
-  output_parcel->writeInt32(ret);
-
-  return ret;
-}
-
 void *HWCSession::HWCUeventThread(void *context) {
   if (context) {
     return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
@@ -1453,6 +1287,8 @@
         callbacks_.Refresh(0);
         reset_panel_ = true;
       }
+    } else if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
+      HandleExtHPD(uevent_data, length);
     }
   }
   pthread_exit(0);
@@ -1460,6 +1296,29 @@
   return NULL;
 }
 
+void HWCSession::HandleExtHPD(const char *uevent_data, int length) {
+  const char *iterator_str = uevent_data;
+  const char *event_info = "status=";
+  const char *pstr = NULL;
+  while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
+    pstr = strstr(iterator_str, event_info);
+    if (pstr != NULL) {
+      break;
+    }
+    iterator_str += strlen(iterator_str) + 1;
+  }
+
+  if (pstr) {
+    bool connected = false;
+    if (strcmp(pstr+strlen(event_info), "connected") == 0) {
+      connected = true;
+    }
+
+    DLOGI("Recived Ext HPD, connected:%d  status=%s", connected, pstr+strlen(event_info));
+    HotPlugHandler(connected);
+  }
+}
+
 int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
   const char *iterator_str = uevent_data;
   while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
@@ -1500,34 +1359,35 @@
 int HWCSession::HotPlugHandler(bool connected) {
   int status = 0;
   bool notify_hotplug = false;
-  bool hdmi_primary = false;
 
   // To prevent sending events to client while a lock is held, acquire scope locks only within
   // below scope so that those get automatically unlocked after the scope ends.
-  {
+  do {
     SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
+    // If HDMI is primary but not created yet (first time), create it and notify surfaceflinger.
+    //    if it is already created, but got disconnected/connected again,
+    //    just toggle display status and do not notify surfaceflinger.
+    // If HDMI is not primary, create/destroy external display normally.
+    if (hdmi_is_primary_) {
+      if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+        status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetState(connected);
+      } else {
+        status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
+                                            qservice_, &hwc_display_[HWC_DISPLAY_PRIMARY]);
+        notify_hotplug = true;
+      }
+
+      break;
+    }
+
+    // Primary display must be connected for HDMI as secondary cases.
     if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
       DLOGE("Primary display is not connected.");
       return -1;
     }
 
-    HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
-    HWCDisplay *external_display = NULL;
-
-    if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) {
-      external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
-      hdmi_primary = true;
-    }
-
-    // If primary display connected is a NULL display, then replace it with the external display
     if (connected) {
-      // If we are in HDMI as primary and the primary display just got plugged in
-      if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-        DLOGE("HDMI is already connected");
-        return -1;
-      }
-
       // Connect external display if virtual display is not connected.
       // Else, defer external display connection and process it when virtual display
       // tears down; Do not notify SurfaceFlinger since connection is deferred now.
@@ -1545,39 +1405,28 @@
       // Do not return error if external display is not in connected status.
       // Due to virtual display concurrency, external display connection might be still pending
       // but hdmi got disconnected before pending connection could be processed.
-
-      if (hdmi_primary) {
-        assert(external_display != NULL);
-        uint32_t x_res, y_res;
-        external_display->GetFrameBufferResolution(&x_res, &y_res);
-        // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases
-        // for HDMI as primary
-        external_display->SetVsyncEnabled(HWC2::Vsync::Disable);
-        HWCDisplayExternal::Destroy(external_display);
-
-        // In HWC2, primary displays can be hotplugged out
+      if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+        status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
         notify_hotplug = true;
-      } else {
-        if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-          status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
-          notify_hotplug = true;
-        }
-        external_pending_connect_ = false;
       }
+      external_pending_connect_ = false;
+    }
+  } while (0);
+
+  if (connected) {
+    callbacks_.Refresh(0);
+
+    if (!hdmi_is_primary_) {
+      // wait for sufficient time to ensure sufficient resources are available to process new
+      // new display connection.
+      uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
+      usleep(vsync_period * 2 / 1000);
     }
   }
 
-  if (connected && notify_hotplug) {
-    // trigger screen refresh to ensure sufficient resources are available to process new
-    // new display connection.
-    callbacks_.Refresh(0);
-    uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
-    usleep(vsync_period * 2 / 1000);
-  }
   // notify client
-  // Handle HDMI as primary here
   if (notify_hotplug) {
-    callbacks_.Hotplug(HWC_DISPLAY_EXTERNAL,
+    callbacks_.Hotplug(hdmi_is_primary_ ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL,
                        connected ? HWC2::Connection::Connected : HWC2::Connection::Disconnected);
   }
 
@@ -1601,6 +1450,8 @@
 
 android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                                     android::Parcel *output_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int dpy = input_parcel->readInt32();
 
   if (dpy < HWC_DISPLAY_PRIMARY || dpy > HWC_DISPLAY_VIRTUAL) {
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 7d31a3a..cd9831d 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -20,8 +20,10 @@
 #ifndef __HWC_SESSION_H__
 #define __HWC_SESSION_H__
 
+#include <vendor/display/config/1.0/IDisplayConfig.h>
 #include <core/core_interface.h>
 #include <utils/locker.h>
+#include <thread>
 
 #include "hwc_callbacks.h"
 #include "hwc_layers.h"
@@ -34,7 +36,10 @@
 
 namespace sdm {
 
-class HWCSession : hwc2_device_t, public qClient::BnQClient {
+using ::vendor::display::config::V1_0::IDisplayConfig;
+using ::android::hardware::Return;
+
+class HWCSession : hwc2_device_t, public IDisplayConfig, public qClient::BnQClient {
  public:
   struct HWCModuleMethods : public hw_module_methods_t {
     HWCModuleMethods() { hw_module_methods_t::open = HWCSession::Open; }
@@ -119,11 +124,50 @@
   static void *HWCUeventThread(void *context);
   void *HWCUeventThreadHandler();
   int GetEventValue(const char *uevent_data, int length, const char *event_info);
+  void HandleExtHPD(const char *uevent_data, int length);
   int HotPlugHandler(bool connected);
   void ResetPanel();
   int32_t ConnectDisplay(int disp);
   int DisconnectDisplay(int disp);
   int GetVsyncPeriod(int disp);
+  int32_t GetConfigCount(int disp_id, uint32_t *count);
+  int32_t GetActiveConfigIndex(int disp_id, uint32_t *config);
+  int32_t SetActiveConfigIndex(int disp_id, uint32_t config);
+  int32_t ControlPartialUpdate(int dpy, bool enable);
+  int32_t DisplayBWTransactionPending(bool *status);
+  int32_t SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status);
+  int32_t GetPanelBrightness(int *level);
+  int32_t MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level);
+
+  // service methods
+  void StartServices();
+
+  // Methods from ::android::hardware::display::config::V1_0::IDisplayConfig follow.
+  Return<void> isDisplayConnected(IDisplayConfig::DisplayType dpy,
+                                  isDisplayConnected_cb _hidl_cb) override;
+  Return<int32_t> setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
+                                  IDisplayConfig::DisplayExternalStatus status) override;
+  Return<int32_t> configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
+                                  uint32_t refreshRate) override;
+  Return<void> getConfigCount(IDisplayConfig::DisplayType dpy,
+                              getConfigCount_cb _hidl_cb) override;
+  Return<void> getActiveConfig(IDisplayConfig::DisplayType dpy,
+                               getActiveConfig_cb _hidl_cb) override;
+  Return<int32_t> setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) override;
+  Return<void> getDisplayAttributes(uint32_t configIndex, IDisplayConfig::DisplayType dpy,
+                                    getDisplayAttributes_cb _hidl_cb) override;
+  Return<int32_t> setPanelBrightness(uint32_t level) override;
+  Return<void> getPanelBrightness(getPanelBrightness_cb _hidl_cb) override;
+  Return<int32_t> minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
+                                                uint32_t min_enc_level) override;
+  Return<int32_t> refreshScreen() override;
+  Return<int32_t> controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) override;
+  Return<int32_t> toggleScreenUpdate(bool on) override;
+  Return<int32_t> setIdleTimeout(uint32_t value) override;
+  Return<void> getHDRCapabilities(IDisplayConfig::DisplayType dpy,
+                                  getHDRCapabilities_cb _hidl_cb) override;
+  Return<int32_t> setCameraLaunchStatus(uint32_t on) override;
+  Return<void> displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) override;
 
   // QClient methods
   virtual android::status_t notifyCallback(uint32_t command, const android::Parcel *input_parcel,
@@ -132,60 +176,37 @@
   void SetFrameDumpConfig(const android::Parcel *input_parcel);
   android::status_t SetMaxMixerStages(const android::Parcel *input_parcel);
   android::status_t SetDisplayMode(const android::Parcel *input_parcel);
-  android::status_t SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
-                                              android::Parcel *output_parcel);
-  android::status_t ToggleScreenUpdates(const android::Parcel *input_parcel,
-                                        android::Parcel *output_parcel);
   android::status_t ConfigureRefreshRate(const android::Parcel *input_parcel);
   android::status_t QdcmCMDHandler(const android::Parcel *input_parcel,
                                    android::Parcel *output_parcel);
-  android::status_t ControlPartialUpdate(const android::Parcel *input_parcel, android::Parcel *out);
-  android::status_t OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
-                                                   android::Parcel *output_parcel);
-  android::status_t SetPanelBrightness(const android::Parcel *input_parcel,
-                                       android::Parcel *output_parcel);
-  android::status_t GetPanelBrightness(const android::Parcel *input_parcel,
-                                       android::Parcel *output_parcel);
-  // These functions return the actual display config info as opposed to FB
-  android::status_t HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel);
-  android::status_t HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel);
-  android::status_t HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
-                                                android::Parcel *output_parcel);
   android::status_t HandleGetDisplayAttributesForConfig(const android::Parcel *input_parcel,
                                                         android::Parcel *output_parcel);
   android::status_t GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                           android::Parcel *output_parcel);
-
-  android::status_t SetDynamicBWForCamera(const android::Parcel *input_parcel,
-                                          android::Parcel *output_parcel);
-  android::status_t GetBWTransactionStatus(const android::Parcel *input_parcel,
-                                           android::Parcel *output_parcel);
   android::status_t SetMixerResolution(const android::Parcel *input_parcel);
-
   android::status_t SetColorModeOverride(const android::Parcel *input_parcel);
 
   android::status_t SetColorModeById(const android::Parcel *input_parcel);
 
   static Locker locker_;
-  CoreInterface *core_intf_ = NULL;
-  HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {NULL};
+  CoreInterface *core_intf_ = nullptr;
+  HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
   HWCCallbacks callbacks_;
-  pthread_t uevent_thread_;
+  std::thread uevent_thread_;
   bool uevent_thread_exit_ = false;
   const char *uevent_thread_name_ = "HWC_UeventThread";
-  HWCBufferAllocator *buffer_allocator_;
+  HWCBufferAllocator buffer_allocator_;
   HWCBufferSyncHandler buffer_sync_handler_;
-  HWCColorManager *color_mgr_ = NULL;
+  HWCColorManager *color_mgr_ = nullptr;
   bool reset_panel_ = false;
   bool secure_display_active_ = false;
   bool external_pending_connect_ = false;
   bool new_bw_mode_ = false;
   bool need_invalidate_ = false;
   int bw_mode_release_fd_ = -1;
-  qService::QService *qservice_ = NULL;
+  qService::QService *qservice_ = nullptr;
   HWCSocketHandler socket_handler_;
+  bool hdmi_is_primary_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
new file mode 100644
index 0000000..4b5374f
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -0,0 +1,483 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <core/buffer_allocator.h>
+#include <utils/debug.h>
+#include <sync/sync.h>
+#include <profiler.h>
+
+#include "hwc_buffer_sync_handler.h"
+#include "hwc_session.h"
+
+#define __CLASS__ "HWCSession"
+
+namespace sdm {
+
+using ::android::hardware::Void;
+
+void HWCSession::StartServices() {
+  status_t status = IDisplayConfig::registerAsService();
+  if (status != OK) {
+    DLOGW("Could not register IDisplayConfig as service (%d).", status);
+  } else {
+    DLOGI("IDisplayConfig service registration completed.");
+  }
+}
+
+int MapDisplayType(IDisplayConfig::DisplayType dpy) {
+  switch (dpy) {
+    case IDisplayConfig::DisplayType::DISPLAY_PRIMARY:
+      return HWC_DISPLAY_PRIMARY;
+
+    case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL:
+      return HWC_DISPLAY_EXTERNAL;
+
+    case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL:
+      return HWC_DISPLAY_VIRTUAL;
+
+    default:
+      break;
+  }
+
+  return -EINVAL;
+}
+
+HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) {
+  switch (status) {
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE:
+      return HWCDisplay::kDisplayStatusOffline;
+
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE:
+      return HWCDisplay::kDisplayStatusOnline;
+
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE:
+      return HWCDisplay::kDisplayStatusPause;
+
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME:
+      return HWCDisplay::kDisplayStatusResume;
+
+    default:
+      break;
+  }
+
+  return HWCDisplay::kDisplayStatusInvalid;
+}
+
+// Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
+Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
+                                            isDisplayConnected_cb _hidl_cb) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  bool connected = false;
+
+  int disp_id = MapDisplayType(dpy);
+  if (disp_id >= 0) {
+    connected = hwc_display_[disp_id];
+    error = 0;
+  }
+
+  _hidl_cb(error, connected);
+
+  return Void();
+}
+
+int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  DLOGI("Display = %d, Status = %d", disp_id, status);
+
+  if (disp_id == HWC_DISPLAY_PRIMARY) {
+    DLOGE("Not supported for this display");
+  } else if (!hwc_display_[disp_id]) {
+    DLOGW("Display is not connected");
+  } else {
+    return hwc_display_[disp_id]->SetDisplayStatus(status);
+  }
+
+  return -EINVAL;
+}
+
+Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
+                                                  IDisplayConfig::DisplayExternalStatus status) {
+  return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
+}
+
+Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
+                                                   uint32_t refreshRate) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+
+  switch (op) {
+    case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE:
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+
+    case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE:
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+
+    case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE:
+      return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
+
+    default:
+      DLOGW("Invalid operation %d", op);
+      return -EINVAL;
+  }
+
+  return 0;
+}
+
+int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id >= 0 && hwc_display_[disp_id]) {
+    return hwc_display_[disp_id]->GetDisplayConfigCount(count);
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
+                                        getConfigCount_cb _hidl_cb) {
+  uint32_t count = 0;
+  int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &count);
+
+  _hidl_cb(error, count);
+
+  return Void();
+}
+
+int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id >= 0 && hwc_display_[disp_id]) {
+    return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
+                                         getActiveConfig_cb _hidl_cb) {
+  uint32_t config = 0;
+  int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
+
+  _hidl_cb(error, config);
+
+  return Void();
+}
+
+int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  int32_t error = -EINVAL;
+  if (hwc_display_[disp_id]) {
+    error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
+    if (!error) {
+      callbacks_.Refresh(0);
+    }
+  }
+
+  return error;
+}
+
+Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
+  return SetActiveConfigIndex(MapDisplayType(dpy), config);
+}
+
+Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
+                                              IDisplayConfig::DisplayType dpy,
+                                              getDisplayAttributes_cb _hidl_cb) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  IDisplayConfig::DisplayAttributes display_attributes = {};
+
+  int disp_id = MapDisplayType(dpy);
+  if (disp_id >= 0 && hwc_display_[disp_id]) {
+    DisplayConfigVariableInfo hwc_display_attributes;
+    error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
+                                                                 &hwc_display_attributes);
+    if (!error) {
+      display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
+      display_attributes.xRes = hwc_display_attributes.x_pixels;
+      display_attributes.yRes = hwc_display_attributes.y_pixels;
+      display_attributes.xDpi = hwc_display_attributes.x_dpi;
+      display_attributes.yDpi = hwc_display_attributes.y_dpi;
+      display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
+      display_attributes.isYuv = hwc_display_attributes.is_yuv;
+    }
+  }
+
+  return Void();
+}
+
+Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
+    if (error) {
+      DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
+    }
+  }
+
+  return error;
+}
+
+int32_t HWCSession::GetPanelBrightness(int *level) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
+    if (error) {
+      DLOGE("Failed to get the panel brightness. Error = %d", error);
+    }
+  }
+
+  return error;
+}
+
+Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
+  int level = 0;
+  int32_t error = GetPanelBrightness(&level);
+
+  _hidl_cb(error, static_cast<uint32_t>(level));
+
+  return Void();
+}
+
+int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  DLOGI("Display %d", disp_id);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  if (disp_id != HWC_DISPLAY_EXTERNAL) {
+    DLOGE("Not supported for display");
+  } else if (!hwc_display_[disp_id]) {
+    DLOGW("Display is not connected");
+  } else {
+    return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
+  }
+
+  return -EINVAL;
+}
+
+Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
+                                                          uint32_t min_enc_level) {
+  return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
+}
+
+Return<int32_t> HWCSession::refreshScreen() {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+
+  return 0;
+}
+
+int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  if (disp_id != HWC_DISPLAY_PRIMARY) {
+    DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
+    return -EINVAL;
+  }
+
+  HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+  if (!hwc_display) {
+    DLOGE("primary display object is not instantiated");
+    return -EINVAL;
+  }
+
+  uint32_t pending = 0;
+  DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
+
+  if (hwc_error == kErrorNone) {
+    if (!pending) {
+      return 0;
+    }
+  } else if (hwc_error == kErrorNotSupported) {
+    return 0;
+  } else {
+    return -EINVAL;
+  }
+
+  // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
+  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+
+  // Wait until partial update control is complete
+  int32_t error = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
+
+  return error;
+}
+
+Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) {
+  return ControlPartialUpdate(MapDisplayType(dpy), enable);
+}
+
+Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
+    if (error) {
+      DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
+    }
+  }
+
+  return error;
+}
+
+Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
+    return 0;
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
+                                            getHDRCapabilities_cb _hidl_cb) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
+
+  do {
+    int disp_id = MapDisplayType(dpy);
+    if (disp_id < 0) {
+      DLOGE("Invalid display id = %d", disp_id);
+      break;
+    }
+
+    HWCDisplay *hwc_display = hwc_display_[disp_id];
+    if (!hwc_display) {
+      DLOGE("Display = %d is not connected.", disp_id);
+      break;
+    }
+
+    // query number of hdr types
+    uint32_t out_num_types = 0;
+    if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr)
+        != HWC2::Error::None) {
+      break;
+    }
+
+    if (!out_num_types) {
+      error = 0;
+      break;
+    }
+
+    // query hdr caps
+    hdr_caps.supportedHdrTypes.resize(out_num_types);
+
+    float out_max_luminance = 0.0f;
+    float out_max_average_luminance = 0.0f;
+    float out_min_luminance = 0.0f;
+    if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(),
+                                        &out_max_luminance, &out_max_average_luminance,
+                                        &out_min_luminance)
+        == HWC2::Error::None) {
+      error = 0;
+    }
+  } while (false);
+
+  _hidl_cb(error, hdr_caps);
+
+  return Void();
+}
+
+Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
+
+  // trigger invalidate to apply new bw caps.
+  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+
+  if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
+    return -EINVAL;
+  }
+
+  new_bw_mode_ = true;
+  need_invalidate_ = true;
+
+  return 0;
+}
+
+int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    if (sync_wait(bw_mode_release_fd_, 0) < 0) {
+      DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
+      *status = false;
+    }
+
+    return 0;
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
+  bool status = true;
+
+  int32_t error = DisplayBWTransactionPending(&status);
+
+  _hidl_cb(error, status);
+
+  return Void();
+}
+
+}  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_tonemapper.cpp b/sdm/libs/hwc2/hwc_tonemapper.cpp
index 7bda725..3086fb4 100644
--- a/sdm/libs/hwc2/hwc_tonemapper.cpp
+++ b/sdm/libs/hwc2/hwc_tonemapper.cpp
@@ -49,18 +49,57 @@
 
 namespace sdm {
 
-ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator) :
-                buffer_allocator_(buffer_allocator) {
+ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator)
+  : tone_map_task_(*this), buffer_allocator_(buffer_allocator) {
   buffer_info_.resize(kNumIntermediateBuffers);
 }
 
 ToneMapSession::~ToneMapSession() {
-  delete gpu_tone_mapper_;
-  gpu_tone_mapper_ = nullptr;
+  tone_map_task_.PerformTask(ToneMapTaskCode::kCodeDestroy, nullptr);
   FreeIntermediateBuffers();
   buffer_info_.clear();
 }
 
+void ToneMapSession::OnTask(const ToneMapTaskCode &task_code,
+                            SyncTask<ToneMapTaskCode>::TaskContext *task_context) {
+  switch (task_code) {
+    case ToneMapTaskCode::kCodeGetInstance: {
+        ToneMapGetInstanceContext *ctx = static_cast<ToneMapGetInstanceContext *>(task_context);
+        Lut3d &lut_3d = ctx->layer->lut_3d;
+        Color10Bit *grid_entries = NULL;
+        int grid_size = 0;
+        if (lut_3d.validGridEntries) {
+          grid_entries = lut_3d.gridEntries;
+          grid_size = INT(lut_3d.gridSize);
+        }
+        gpu_tone_mapper_ = TonemapperFactory_GetInstance(tone_map_config_.type,
+                                                         lut_3d.lutEntries, lut_3d.dim,
+                                                         grid_entries, grid_size,
+                                                         tone_map_config_.secure);
+      }
+      break;
+
+    case ToneMapTaskCode::kCodeBlit: {
+        ToneMapBlitContext *ctx = static_cast<ToneMapBlitContext *>(task_context);
+        uint8_t buffer_index = current_buffer_index_;
+        const void *dst_hnd = reinterpret_cast<const void *>
+                                (buffer_info_[buffer_index].private_data);
+        const void *src_hnd = reinterpret_cast<const void *>
+                                (ctx->layer->input_buffer.buffer_id);
+        ctx->fence_fd = gpu_tone_mapper_->blit(dst_hnd, src_hnd, ctx->merged_fd);
+      }
+      break;
+
+    case ToneMapTaskCode::kCodeDestroy: {
+        delete gpu_tone_mapper_;
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
 DisplayError ToneMapSession::AllocateIntermediateBuffers(const Layer *layer) {
   DisplayError error = kErrorNone;
   for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
@@ -180,35 +219,30 @@
 }
 
 void HWCToneMapper::ToneMap(Layer* layer, ToneMapSession *session) {
-  int fence_fd = -1;
-  int acquire_fd = -1;
-  int merged_fd = -1;
+  ToneMapBlitContext ctx = {};
+  ctx.layer = layer;
 
   uint8_t buffer_index = session->current_buffer_index_;
-  const private_handle_t *dst_hnd = static_cast<private_handle_t *>
-                                    (session->buffer_info_[buffer_index].private_data);
-  const private_handle_t *src_hnd = reinterpret_cast<const private_handle_t *>
-                                    (layer->input_buffer.buffer_id);
+  int &release_fence_fd = session->release_fence_fd_[buffer_index];
 
   // use and close the layer->input_buffer acquire fence fd.
-  acquire_fd = layer->input_buffer.acquire_fence_fd;
-  buffer_sync_handler_.SyncMerge(session->release_fence_fd_[buffer_index], acquire_fd, &merged_fd);
+  int acquire_fd = layer->input_buffer.acquire_fence_fd;
+  buffer_sync_handler_.SyncMerge(release_fence_fd, acquire_fd, &ctx.merged_fd);
 
   if (acquire_fd >= 0) {
     CloseFd(&acquire_fd);
   }
 
-  if (session->release_fence_fd_[buffer_index] >= 0) {
-    CloseFd(&session->release_fence_fd_[buffer_index]);
+  if (release_fence_fd >= 0) {
+    CloseFd(&release_fence_fd);
   }
 
   DTRACE_BEGIN("GPU_TM_BLIT");
-  fence_fd = session->gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd),
-                                             reinterpret_cast<const void *>(src_hnd), merged_fd);
+  session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeBlit, &ctx);
   DTRACE_END();
 
-  DumpToneMapOutput(session, &fence_fd);
-  session->UpdateBuffer(fence_fd, &layer->input_buffer);
+  DumpToneMapOutput(session, &ctx.fence_fd);
+  session->UpdateBuffer(ctx.fence_fd, &layer->input_buffer);
 }
 
 void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
@@ -265,9 +299,9 @@
 
   size_t result = 0;
   char dump_file_name[PATH_MAX];
-  snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
-           "/tonemap_%dx%d_frame%d.raw", target_buffer->width, target_buffer->height,
-           dump_frame_index_);
+  snprintf(dump_file_name, sizeof(dump_file_name), "%s/frame_dump_primary"
+           "/tonemap_%dx%d_frame%d.raw", HWCDebugHandler::DumpDir(), target_buffer->width,
+           target_buffer->height, dump_frame_index_);
 
   FILE* fp = fopen(dump_file_name, "w+");
   if (fp) {
@@ -281,14 +315,6 @@
 }
 
 DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index) {
-  Color10Bit *grid_entries = NULL;
-  int grid_size = 0;
-
-  if (layer->lut_3d.validGridEntries) {
-    grid_entries = layer->lut_3d.gridEntries;
-    grid_size = INT(layer->lut_3d.gridSize);
-  }
-
   // When the property sdm.disable_hdr_lut_gen is set, the lutEntries and gridEntries in
   // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut
   // for Tonemapping.
@@ -311,13 +337,15 @@
   }
 
   ToneMapSession *session = new ToneMapSession(buffer_allocator_);
+  if (!session) {
+    return kErrorMemory;
+  }
 
   session->SetToneMapConfig(layer);
-  session->gpu_tone_mapper_ = TonemapperFactory_GetInstance(session->tone_map_config_.type,
-                                                            layer->lut_3d.lutEntries,
-                                                            layer->lut_3d.dim,
-                                                            grid_entries, grid_size,
-                                                            session->tone_map_config_.secure);
+
+  ToneMapGetInstanceContext ctx;
+  ctx.layer = layer;
+  session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeGetInstance, &ctx);
 
   if (session->gpu_tone_mapper_ == NULL) {
     DLOGE("Get Tonemapper failed!");
diff --git a/sdm/libs/hwc2/hwc_tonemapper.h b/sdm/libs/hwc2/hwc_tonemapper.h
index 8367c3e..e2c8ef4 100644
--- a/sdm/libs/hwc2/hwc_tonemapper.h
+++ b/sdm/libs/hwc2/hwc_tonemapper.h
@@ -37,6 +37,7 @@
 
 #include <core/layer_stack.h>
 #include <utils/sys.h>
+#include <utils/sync_task.h>
 #include <vector>
 #include "hwc_buffer_sync_handler.h"
 #include "hwc_buffer_allocator.h"
@@ -45,6 +46,22 @@
 
 namespace sdm {
 
+enum class ToneMapTaskCode : int32_t {
+  kCodeGetInstance,
+  kCodeBlit,
+  kCodeDestroy,
+};
+
+struct ToneMapGetInstanceContext : public SyncTask<ToneMapTaskCode>::TaskContext {
+  Layer *layer = nullptr;
+};
+
+struct ToneMapBlitContext : public SyncTask<ToneMapTaskCode>::TaskContext {
+  Layer *layer = nullptr;
+  int merged_fd = -1;
+  int fence_fd = -1;
+};
+
 struct ToneMapConfig {
   int type = 0;
   ColorPrimaries colorPrimaries = ColorPrimaries_Max;
@@ -53,7 +70,7 @@
   bool secure = false;
 };
 
-class ToneMapSession {
+class ToneMapSession : public SyncTask<ToneMapTaskCode>::TaskHandler {
  public:
   explicit ToneMapSession(HWCBufferAllocator *buffer_allocator);
   ~ToneMapSession();
@@ -64,7 +81,12 @@
   void SetToneMapConfig(Layer *layer);
   bool IsSameToneMapConfig(Layer *layer);
 
+  // TaskHandler methods implementation.
+  virtual void OnTask(const ToneMapTaskCode &task_code,
+                      SyncTask<ToneMapTaskCode>::TaskContext *task_context);
+
   static const uint8_t kNumIntermediateBuffers = 2;
+  SyncTask<ToneMapTaskCode> tone_map_task_;
   Tonemapper *gpu_tone_mapper_ = nullptr;
   HWCBufferAllocator *buffer_allocator_ = nullptr;
   ToneMapConfig tone_map_config_ = {};
diff --git a/sdm/libs/utils/formats.cpp b/sdm/libs/utils/formats.cpp
index b7deb18..4b7190b 100644
--- a/sdm/libs/utils/formats.cpp
+++ b/sdm/libs/utils/formats.cpp
@@ -127,5 +127,87 @@
   }
 }
 
+float GetBufferFormatBpp(LayerBufferFormat format) {
+  float bpp = 0.0f;
+  switch (format) {
+    case kFormatARGB8888:
+    case kFormatRGBA8888:
+    case kFormatBGRA8888:
+    case kFormatXRGB8888:
+    case kFormatRGBX8888:
+    case kFormatBGRX8888:
+    case kFormatRGBA8888Ubwc:
+    case kFormatRGBX8888Ubwc:
+    case kFormatRGBA1010102:
+    case kFormatARGB2101010:
+    case kFormatRGBX1010102:
+    case kFormatXRGB2101010:
+    case kFormatBGRA1010102:
+    case kFormatABGR2101010:
+    case kFormatBGRX1010102:
+    case kFormatXBGR2101010:
+    case kFormatRGBA1010102Ubwc:
+    case kFormatRGBX1010102Ubwc:
+      return 4.0f;
+    case kFormatRGB888:
+    case kFormatBGR888:
+    case kFormatYCbCr420P010:
+    case kFormatYCbCr420P010Ubwc:
+      return 3.0f;
+    case kFormatRGB565:
+    case kFormatBGR565:
+    case kFormatRGBA5551:
+    case kFormatRGBA4444:
+    case kFormatBGR565Ubwc:
+    case kFormatYCbCr422H2V1Packed:
+    case kFormatCbYCrY422H2V1Packed:
+    case kFormatYCrCb422H2V1SemiPlanar:
+    case kFormatYCbCr422H2V1SemiPlanar:
+    case kFormatYCbCr420TP10Ubwc:
+    case kFormatYCbCr422H1V2SemiPlanar:
+    case kFormatYCrCb422H1V2SemiPlanar:
+      return 2.0f;
+    case kFormatYCbCr420Planar:
+    case kFormatYCrCb420Planar:
+    case kFormatYCrCb420PlanarStride16:
+    case kFormatYCbCr420SemiPlanar:
+    case kFormatYCrCb420SemiPlanar:
+    case kFormatYCbCr420SemiPlanarVenus:
+    case kFormatYCrCb420SemiPlanarVenus:
+    case kFormatYCbCr420SPVenusUbwc:
+      return 1.5f;
+    default:
+      return 0.0f;
+  }
+
+  return bpp;
+}
+
+DisplayError GetBufferFormatTileSize(LayerBufferFormat format, FormatTileSize *tile_size) {
+  switch (format) {
+  case kFormatYCbCr420SPVenusUbwc:
+    tile_size->tile_width = 32;
+    tile_size->tile_height = 8;
+    tile_size->uv_tile_width = 16;
+    tile_size->uv_tile_height = 8;
+    break;
+  case kFormatYCbCr420TP10Ubwc:
+    tile_size->tile_width = 48;
+    tile_size->tile_height = 4;
+    tile_size->uv_tile_width = 24;
+    tile_size->uv_tile_height = 4;
+    break;
+  case kFormatYCbCr420P010Ubwc:
+    tile_size->tile_width = 32;
+    tile_size->tile_height = 4;
+    tile_size->uv_tile_width = 16;
+    tile_size->uv_tile_height = 4;
+    break;
+  default:
+    return kErrorNotSupported;
+  }
+  return kErrorNone;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/utils/rect.cpp b/sdm/libs/utils/rect.cpp
index b0cd536..c227cb3 100644
--- a/sdm/libs/utils/rect.cpp
+++ b/sdm/libs/utils/rect.cpp
@@ -261,5 +261,47 @@
   return kOrientationLandscape;
 }
 
+DisplayError GetCropAndDestination(const LayerRect &crop, const LayerRect &dst,
+                                   const bool rotated90, float *crop_width,
+                                   float *crop_height, float *dst_width,
+                                   float *dst_height) {
+  if (!IsValid(crop)) {
+    Log(kTagResources, "Invalid crop rect", crop);
+    return kErrorNotSupported;
+  }
+
+  if (!IsValid(dst)) {
+    Log(kTagResources, "Invalid dst rect", dst);
+    return kErrorNotSupported;
+  }
+
+  *crop_width = crop.right - crop.left;
+  *crop_height = crop.bottom - crop.top;
+  if (rotated90) {
+    std::swap(*crop_width, *crop_height);
+  }
+
+  *dst_width = dst.right - dst.left;
+  *dst_height = dst.bottom - dst.top;
+
+  return kErrorNone;
+}
+
+DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst,
+                            bool rotated90, float *scale_x, float *scale_y) {
+  float crop_width = 1.0f, crop_height = 1.0f, dst_width = 1.0f, dst_height = 1.0f;
+
+  DisplayError error = GetCropAndDestination(crop, dst, rotated90, &crop_width, &crop_height,
+                                             &dst_width, &dst_height);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  *scale_x = crop_width / dst_width;
+  *scale_y = crop_height / dst_height;
+
+  return kErrorNone;
+}
+
 }  // namespace sdm