Merge "sdm:fb: update cdm csc_type during HDR playback"
diff --git a/libdisplayconfig/DisplayConfig.h b/libdisplayconfig/DisplayConfig.h
index 69a542a..17b6421 100644
--- a/libdisplayconfig/DisplayConfig.h
+++ b/libdisplayconfig/DisplayConfig.h
@@ -1,31 +1,31 @@
 /*
- * 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.
- */
+* 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_CONFIG_H__
 #define __DISPLAY_CONFIG_H__
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index f40f324..1727818 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -209,7 +209,14 @@
    * Arg: uint32_t - CRTC ID
    *      uint32_t - rot_clk
    */
-  CRTC_SET_ROT_CLK,  /*
+  CRTC_SET_ROT_CLK,
+  /*
+   * Op: Sets destination scalar data
+   * Arg: uint32_t - CRTC ID
+   *      uint64_t - Pointer to destination scalar data
+   */
+  CRTC_SET_DEST_SCALER_CONFIG,
+  /*
    * Op: Returns release fence for this frame. Should be called after Commit() on
    * DRMAtomicReqInterface.
    * Arg: uint32_t - CRTC ID
@@ -242,6 +249,12 @@
    */
   CRTC_SET_SOLIDFILL_STAGES,
   /*
+   * Op: Sets idle timeout.
+   * Arg: uint32_t - CRTC ID
+   *      uint32_t - idle timeout in ms
+   */
+  CRTC_SET_IDLE_TIMEOUT,
+  /*
    * Op: Returns retire fence for this commit. Should be called after Commit() on
    * DRMAtomicReqInterface.
    * Arg: uint32_t - Connector ID
@@ -279,6 +292,12 @@
    *      uint32_t - FB Secure mode
    */
   CONNECTOR_SET_FB_SECURE_MODE,
+  /*
+   * Op: Sets a crtc id to this connector
+   * Arg: uint32_t - Connector ID
+   *      uint32_t - CRTC ID
+   */
+  CONNECTOR_SET_CRTC,
 };
 
 enum struct DRMRotation {
@@ -365,9 +384,10 @@
   CompRatioMap comp_ratio_rt_map;
   CompRatioMap comp_ratio_nrt_map;
   uint32_t hw_version;
-  uint64_t min_core_ib;
-  uint64_t min_llcc_ib;
-  uint64_t min_dram_ib;
+  uint32_t dest_scaler_count = 0;
+  uint32_t max_dest_scaler_input_width = 0;
+  uint32_t max_dest_scaler_output_width = 0;
+  uint32_t max_dest_scale_up = 1;
 };
 
 enum struct DRMPlaneType {
@@ -462,6 +482,12 @@
   kFeatureDither,
   kFeatureGamut,
   kFeaturePADither,
+  kFeaturePAHsic,
+  kFeaturePASixZone,
+  kFeaturePAMemColSkin,
+  kFeaturePAMemColSky,
+  kFeaturePAMemColFoliage,
+  kFeaturePAMemColProt,
   kPPFeaturesMax,
 };
 
@@ -597,7 +623,7 @@
    * Will query post propcessing feature info of a CRTC.
    * [output]: DRMPPFeatureInfo: CRTC post processing feature info
    */
-  virtual void GetCrtcPPInfo(uint32_t crtc_id, DRMPPFeatureInfo &info) = 0;
+  virtual void GetCrtcPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info) = 0;
   /*
    * Register a logical display to receive a token.
    * Each display pipeline in DRM is identified by its CRTC and Connector(s).
diff --git a/libgralloc1/gr_adreno_info.cpp b/libgralloc1/gr_adreno_info.cpp
index f71f1d2..1ac99be 100644
--- a/libgralloc1/gr_adreno_info.cpp
+++ b/libgralloc1/gr_adreno_info.cpp
@@ -212,6 +212,8 @@
        return ADRENO_PIXELFORMAT_R10G10B10X2_UNORM;
     case HAL_PIXEL_FORMAT_ABGR_2101010:
        return ADRENO_PIXELFORMAT_A2B10G10R10_UNORM;
+    case HAL_PIXEL_FORMAT_RGBA_FP16:
+       return ADRENO_PIXELFORMAT_R16G16B16A16_FLOAT;
     default:
       ALOGE("%s: No map for format: 0x%x", __FUNCTION__, hal_format);
       break;
diff --git a/libgralloc1/gr_adreno_info.h b/libgralloc1/gr_adreno_info.h
index b19256a..83966ae 100644
--- a/libgralloc1/gr_adreno_info.h
+++ b/libgralloc1/gr_adreno_info.h
@@ -37,6 +37,7 @@
 // Adreno Pixel Formats
 typedef enum {
   ADRENO_PIXELFORMAT_UNKNOWN = 0,
+  ADRENO_PIXELFORMAT_R16G16B16A16_FLOAT = 10,
   ADRENO_PIXELFORMAT_R10G10B10A2_UNORM = 24,  // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES
   ADRENO_PIXELFORMAT_R8G8B8A8 = 28,
   ADRENO_PIXELFORMAT_R8G8B8A8_SRGB = 29,
@@ -66,7 +67,7 @@
   ADRENO_PIXELFORMAT_NV21 = 619,
   ADRENO_PIXELFORMAT_Y8U8V8A8 = 620,  // YUV 4:4:4 packed (1 plane)
   ADRENO_PIXELFORMAT_Y8 = 625,        //  Single 8-bit luma only channel YUV format
-  ADRENO_PIXELFORMAT_TP10 = 648,      // YUV 4:2:0 planar 10 bits/comp (2 planes)
+  ADRENO_PIXELFORMAT_TP10 = 654,      // YUV 4:2:0 planar 10 bits/comp (2 planes)
 } ADRENOPIXELFORMAT;
 
 class AdrenoMemInfo {
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index 59afe19..cd89d41 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -508,7 +508,7 @@
                                                descriptor.GetHeight(),
                                                format,
                                                buffer_type,
-                                               size,
+                                               data.size,
                                                prod_usage,
                                                cons_usage);
 
@@ -540,6 +540,10 @@
       int format = va_arg(args, int);
 
       native_handle_t **handle = va_arg(args, native_handle_t **);
+      if (!handle) {
+        return GRALLOC1_ERROR_BAD_HANDLE;
+      }
+
       private_handle_t *hnd = reinterpret_cast<private_handle_t *>(
           native_handle_create(private_handle_t::kNumFds, private_handle_t::NumInts()));
       if (hnd) {
@@ -549,7 +553,7 @@
         hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
         hnd->size = size;
         hnd->offset = offset;
-        hnd->base = uint64_t(base) + offset;
+        hnd->base = uint64_t(base);
         hnd->gpuaddr = 0;
         BufferInfo info(width, height, format);
         GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
@@ -567,6 +571,11 @@
       int format = va_arg(args, int);
       int *stride = va_arg(args, int *);
       unsigned int alignedw = 0, alignedh = 0;
+
+      if (!stride) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       BufferInfo info(width, width, format);
       GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
       *stride = INT(alignedw);
@@ -579,6 +588,10 @@
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
 
+      if (!stride) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       BufferDim_t buffer_dim;
       if (getMetaData(hnd, GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
         *stride = buffer_dim.sliceWidth;
@@ -596,6 +609,10 @@
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
 
+      if (!stride || !height) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       BufferDim_t buffer_dim;
       int interlaced = 0;
 
@@ -631,6 +648,10 @@
       int *aligned_width = va_arg(args, int *);
       int *aligned_height = va_arg(args, int *);
       int *tile_enabled = va_arg(args, int *);
+      if (!aligned_width || !aligned_height || !tile_enabled) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       unsigned int alignedw, alignedh;
       BufferInfo info(width, height, format, prod_usage, cons_usage);
       *tile_enabled = IsUBwcEnabled(format, prod_usage, cons_usage);
@@ -642,9 +663,15 @@
     case GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE: {
       private_handle_t *hnd = va_arg(args, private_handle_t *);
       int *color_space = va_arg(args, int *);
+
       if (private_handle_t::validate(hnd) != 0) {
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
+
+      if (!color_space) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       *color_space = 0;
 #ifdef USE_COLOR_METADATA
       ColorMetaData color_metadata;
@@ -654,6 +681,7 @@
             *color_space = HAL_CSC_ITU_R_709;
             break;
           case ColorPrimaries_BT601_6_525:
+          case ColorPrimaries_BT601_6_625:
             *color_space = ((color_metadata.range) ? HAL_CSC_ITU_R_601_FR : HAL_CSC_ITU_R_601);
             break;
           case ColorPrimaries_BT2020:
@@ -676,6 +704,11 @@
       if (private_handle_t::validate(hnd) != 0) {
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
+
+      if (!ycbcr) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       if (GetYUVPlaneInfo(hnd, ycbcr)) {
         return GRALLOC1_ERROR_UNDEFINED;
       }
@@ -684,11 +717,16 @@
     case GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO: {
       private_handle_t *hnd = va_arg(args, private_handle_t *);
       int *map_secure_buffer = va_arg(args, int *);
+
       if (private_handle_t::validate(hnd) != 0) {
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
 
-      if (getMetaData(hnd, GET_MAP_SECURE_BUFFER, map_secure_buffer) == 0) {
+      if (!map_secure_buffer) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
+      if (getMetaData(hnd, GET_MAP_SECURE_BUFFER, map_secure_buffer) != 0) {
         *map_secure_buffer = 0;
       }
     } break;
@@ -696,9 +734,15 @@
     case GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG: {
       private_handle_t *hnd = va_arg(args, private_handle_t *);
       int *flag = va_arg(args, int *);
+
       if (private_handle_t::validate(hnd) != 0) {
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
+
+      if (!flag) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       *flag = hnd->flags &private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
       int linear_format = 0;
       if (getMetaData(hnd, GET_LINEAR_FORMAT, &linear_format) == 0) {
@@ -711,9 +755,15 @@
     case GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS: {
       private_handle_t *hnd = va_arg(args, private_handle_t *);
       void **rgb_data = va_arg(args, void **);
+
       if (private_handle_t::validate(hnd) != 0) {
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
+
+      if (!rgb_data) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       if (GetRgbDataAddress(hnd, rgb_data)) {
         return GRALLOC1_ERROR_UNDEFINED;
       }
@@ -730,6 +780,11 @@
       uint32_t *aligned_width = va_arg(args, uint32_t *);
       uint32_t *aligned_height = va_arg(args, uint32_t *);
       uint32_t *size = va_arg(args, uint32_t *);
+
+      if (!aligned_width || !aligned_height || !size) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       auto info = BufferInfo(width, height, format, producer_usage, consumer_usage);
       GetBufferSizeAndDimensions(info, size, aligned_width, aligned_height);
       // Align size
@@ -737,14 +792,18 @@
       *size = ALIGN(*size, align);
     } break;
 
-      // TODO(user): Break out similar functionality, preferably moving to a common lib.
-
     case GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG: {
       private_handle_t *hnd = va_arg(args, private_handle_t *);
       int *flag = va_arg(args, int *);
+
       if (private_handle_t::validate(hnd) != 0) {
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
+
+      if (!flag) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+      }
+
       if (getMetaData(hnd, GET_PP_PARAM_INTERLACED, flag) != 0) {
         *flag = 0;
       }
@@ -773,6 +832,9 @@
     case HAL_PIXEL_FORMAT_RAW10:
     case HAL_PIXEL_FORMAT_YV12:
     case HAL_PIXEL_FORMAT_Y8:
+    case HAL_PIXEL_FORMAT_YCbCr_420_P010:
+    case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC:
+    case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC:
       return true;
     default:
       return false;
@@ -795,8 +857,8 @@
     return GRALLOC1_ERROR_UNSUPPORTED;
   }
 
-  android_ycbcr ycbcr;
-  int err = GetYUVPlaneInfo(hnd, &ycbcr);
+  android_ycbcr yuvPlaneInfo[2];
+  int err = GetYUVPlaneInfo(hnd, yuvPlaneInfo);
 
   if (err != 0) {
     return GRALLOC1_ERROR_BAD_HANDLE;
@@ -814,6 +876,8 @@
     layout->planes[i].v_subsampling = 2;
   }
 
+  // We are only returning flex layout for progressive or single field formats.
+  struct android_ycbcr ycbcr = yuvPlaneInfo[0];
   layout->planes[0].top_left = static_cast<uint8_t *>(ycbcr.y);
   layout->planes[0].component = FLEX_COMPONENT_Y;
   layout->planes[0].v_increment = static_cast<int32_t>(ycbcr.ystride);
diff --git a/libgralloc1/gr_device_impl.cpp b/libgralloc1/gr_device_impl.cpp
index 03e42ab..c900d23 100644
--- a/libgralloc1/gr_device_impl.cpp
+++ b/libgralloc1/gr_device_impl.cpp
@@ -65,7 +65,7 @@
 
 int gralloc_device_open(const struct hw_module_t *module, const char *name, hw_device_t **device) {
   int status = -EINVAL;
-  if (!strcmp(name, GRALLOC_HARDWARE_MODULE_ID)) {
+  if (module && device && !strcmp(name, GRALLOC_HARDWARE_MODULE_ID)) {
     gralloc1::GrallocImpl * /*gralloc1_device_t*/ dev = gralloc1::GrallocImpl::GetInstance(module);
     *device = reinterpret_cast<hw_device_t *>(dev);
     if (dev) {
@@ -105,7 +105,7 @@
 
 void GrallocImpl::GetCapabilities(struct gralloc1_device *device, uint32_t *out_count,
                                   int32_t  /*gralloc1_capability_t*/ *out_capabilities) {
-  if (device != nullptr) {
+  if (device != nullptr && out_count != nullptr) {
     if (out_capabilities != nullptr && *out_count >= 3) {
       out_capabilities[0] = GRALLOC1_CAPABILITY_TEST_ALLOCATE;
       out_capabilities[1] = GRALLOC1_CAPABILITY_LAYERED_BUFFERS;
@@ -178,7 +178,7 @@
 
 gralloc1_error_t GrallocImpl::Dump(gralloc1_device_t *device, uint32_t *out_size,
                                    char *out_buffer) {
-  if (!device) {
+  if (!device || !out_size) {
     ALOGE("Gralloc Error : device=%p", (void *)device);
     return GRALLOC1_ERROR_BAD_DESCRIPTOR;
   }
@@ -213,7 +213,7 @@
 
 gralloc1_error_t GrallocImpl::CreateBufferDescriptor(gralloc1_device_t *device,
                                                      gralloc1_buffer_descriptor_t *out_descriptor) {
-  if (!device) {
+  if (!device || !out_descriptor) {
     return GRALLOC1_ERROR_BAD_DESCRIPTOR;
   }
   GrallocImpl const *dev = GRALLOC_IMPL(device);
@@ -347,6 +347,10 @@
 
 gralloc1_error_t GrallocImpl::GetProducerUsage(gralloc1_device_t *device, buffer_handle_t buffer,
                                                gralloc1_producer_usage_t *outUsage) {
+  if (!outUsage) {
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
   gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
   if (status == GRALLOC1_ERROR_NONE) {
     const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer);
@@ -358,6 +362,10 @@
 
 gralloc1_error_t GrallocImpl::GetBufferStride(gralloc1_device_t *device, buffer_handle_t buffer,
                                               uint32_t *outStride) {
+  if (!outStride) {
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
   gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
   if (status == GRALLOC1_ERROR_NONE) {
     *outStride = UINT(PRIV_HANDLE_CONST(buffer)->GetStride());
@@ -373,6 +381,10 @@
     return GRALLOC1_ERROR_BAD_DESCRIPTOR;
   }
 
+  if (!device) {
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
   GrallocImpl const *dev = GRALLOC_IMPL(device);
   gralloc1_error_t status = dev->buf_mgr_->AllocateBuffers(num_descriptors, descriptors,
                                                            out_buffers);
@@ -403,6 +415,10 @@
 
 gralloc1_error_t GrallocImpl::GetNumFlexPlanes(gralloc1_device_t *device, buffer_handle_t buffer,
                                                uint32_t *out_num_planes) {
+  if (!out_num_planes) {
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
   gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
   if (status == GRALLOC1_ERROR_NONE) {
     GrallocImpl const *dev = GRALLOC_IMPL(device);
@@ -425,7 +441,8 @@
                                          int32_t acquire_fence) {
   ATRACE_CALL();
   gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
-  if (status != GRALLOC1_ERROR_NONE) {
+  if (status != GRALLOC1_ERROR_NONE || !out_data ||
+      !region) {  // currently we ignore the region/rect client wants to lock
     CloseFdIfValid(acquire_fence);
     return status;
   }
@@ -452,13 +469,8 @@
     // return GRALLOC1_ERROR_BAD_VALUE;
   }
 
-  // currently we ignore the region/rect client wants to lock
-  if (region == NULL) {
-    return GRALLOC1_ERROR_BAD_VALUE;
-  }
   // TODO(user): Need to check if buffer was allocated with the same flags
   status = dev->buf_mgr_->LockBuffer(hnd, prod_usage, cons_usage);
-
   *out_data = reinterpret_cast<void *>(hnd->base);
 
   return status;
@@ -470,7 +482,12 @@
                                        const gralloc1_rect_t *region,
                                        struct android_flex_layout *out_flex_layout,
                                        int32_t acquire_fence) {
-  void *out_data;
+  if (!out_flex_layout) {
+    CloseFdIfValid(acquire_fence);
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
+  void *out_data {};
   gralloc1_error_t status = GrallocImpl::LockBuffer(device, buffer, prod_usage, cons_usage, region,
                                                     &out_data, acquire_fence);
   if (status != GRALLOC1_ERROR_NONE) {
@@ -486,11 +503,14 @@
 gralloc1_error_t GrallocImpl::UnlockBuffer(gralloc1_device_t *device, buffer_handle_t buffer,
                                            int32_t *release_fence) {
   gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
-
   if (status != GRALLOC1_ERROR_NONE) {
     return status;
   }
 
+  if (!release_fence) {
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
   const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer);
   GrallocImpl const *dev = GRALLOC_IMPL(device);
 
@@ -500,6 +520,10 @@
 }
 
 gralloc1_error_t GrallocImpl::Gralloc1Perform(gralloc1_device_t *device, int operation, ...) {
+  if (!device) {
+    return GRALLOC1_ERROR_BAD_VALUE;
+  }
+
   va_list args;
   va_start(args, operation);
   GrallocImpl const *dev = GRALLOC_IMPL(device);
diff --git a/libgralloc1/gr_utils.cpp b/libgralloc1/gr_utils.cpp
index 945dea4..a7e8c91 100644
--- a/libgralloc1/gr_utils.cpp
+++ b/libgralloc1/gr_utils.cpp
@@ -312,7 +312,7 @@
 }
 
 void GetYuvUbwcInterlacedSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height,
-                                     int color_format, struct android_ycbcr *ycbcr) {
+                                     int color_format, struct android_ycbcr ycbcr[2]) {
   unsigned int uv_stride, uv_height, uv_size;
   unsigned int alignment = 4096;
   uint64_t field_base;
@@ -329,6 +329,7 @@
   field_base = base;
   GetYuvUbwcSPPlaneInfo(field_base, width, height, COLOR_FMT_NV12_UBWC, &ycbcr[0]);
 
+  memset(ycbcr[1].reserved, 0, sizeof(ycbcr[1].reserved));
   field_base = reinterpret_cast<uint64_t>(ycbcr[0].cb) + uv_size;
   GetYuvUbwcSPPlaneInfo(field_base, width, height, COLOR_FMT_NV12_UBWC, &ycbcr[1]);
 }
@@ -346,7 +347,7 @@
   ycbcr->chroma_step = 2 * bpp;
 }
 
-int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr *ycbcr) {
+int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr ycbcr[2]) {
   int err = 0;
   uint32_t width = UINT(hnd->width);
   uint32_t height = UINT(hnd->height);
@@ -382,7 +383,7 @@
   // Check metadata for interlaced content.
   int interlace_flag = 0;
   if (getMetaData(const_cast<private_handle_t *>(hnd),
-                  GET_PP_PARAM_INTERLACED, &interlace_flag) != 0) {
+                  GET_PP_PARAM_INTERLACED, &interlace_flag) == 0) {
     interlaced = interlace_flag;
   }
 
@@ -772,7 +773,7 @@
     return -EINVAL;
   }
 
-  struct android_ycbcr yuvInfo = {};
+  struct android_ycbcr yuvPlaneInfo[2] = {};
   *num_planes = 1;
   stride[0] = 0;
 
@@ -808,12 +809,14 @@
   }
 
   (*num_planes)++;
-  int ret = GetYUVPlaneInfo(hnd, &yuvInfo);
+  int ret = GetYUVPlaneInfo(hnd, yuvPlaneInfo);
   if (ret < 0) {
     ALOGE("%s failed", __FUNCTION__);
     return ret;
   }
 
+  // We are only returning buffer layout for progressive or single field formats.
+  struct android_ycbcr yuvInfo = yuvPlaneInfo[0];
   stride[0] = static_cast<uint32_t>(yuvInfo.ystride);
   offset[0] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(yuvInfo.y) - hnd->base);
   stride[1] = static_cast<uint32_t>(yuvInfo.cstride);
diff --git a/libgralloc1/gr_utils.h b/libgralloc1/gr_utils.h
index 2a08539..4b2f136 100644
--- a/libgralloc1/gr_utils.h
+++ b/libgralloc1/gr_utils.h
@@ -71,7 +71,7 @@
                                 unsigned int *alignedw, unsigned int *alignedh);
 void GetAlignedWidthAndHeight(const BufferInfo &d, unsigned int *aligned_w,
                               unsigned int *aligned_h);
-int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr *ycbcr);
+int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr ycbcr[2]);
 int GetRgbDataAddress(private_handle_t *hnd, void **rgb_data);
 bool IsUBwcFormat(int format);
 bool IsUBwcSupported(int format);
@@ -84,7 +84,7 @@
 void GetYuvUbwcSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, int color_format,
                            struct android_ycbcr *ycbcr);
 void GetYuvUbwcInterlacedSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height,
-                                     int color_format, struct android_ycbcr *ycbcr);
+                                     int color_format, struct android_ycbcr ycbcr[2]);
 void GetRgbUBwcBlockSize(uint32_t bpp, int *block_width, int *block_height);
 unsigned int GetRgbUBwcMetaBufferSize(int width, int height, uint32_t bpp);
 unsigned int GetUBwcSize(int width, int height, int format, unsigned int alignedw,
diff --git a/liblight/lights.c b/liblight/lights.c
index 15db827..115b98c 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -48,6 +48,7 @@
 static int g_last_backlight_mode = BRIGHTNESS_MODE_USER;
 static int g_attention = 0;
 static int g_brightness_max = 0;
+static bool g_has_persistence_node = false;
 
 char const*const RED_LED_FILE
         = "/sys/class/leds/red/brightness";
@@ -139,20 +140,23 @@
 
     pthread_mutex_lock(&g_lock);
     // Toggle low persistence mode state
-    if ((g_last_backlight_mode != state->brightnessMode && lpEnabled) ||
-        (!lpEnabled &&
-         g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE)) {
-        if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) {
-            ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__,
-                   PERSISTENCE_FILE, strerror(errno));
+    bool persistence_mode = ((g_last_backlight_mode != state->brightnessMode && lpEnabled) ||
+                            (!lpEnabled &&
+                            g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE));
+    bool cannot_handle_persistence = !g_has_persistence_node && persistence_mode;
+    if (g_has_persistence_node) {
+        if (persistence_mode) {
+            if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) {
+                ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__,
+                       PERSISTENCE_FILE, strerror(errno));
+            }
+            if (lpEnabled != 0) {
+                brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS;
+            }
         }
-        if (lpEnabled != 0) {
-            brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS;
-        }
+        g_last_backlight_mode = state->brightnessMode;
     }
 
-    g_last_backlight_mode = state->brightnessMode;
-
     if (!err) {
         if (!access(LCD_FILE, F_OK)) {
             err = write_int(LCD_FILE, brightness);
@@ -162,7 +166,7 @@
     }
 
     pthread_mutex_unlock(&g_lock);
-    return err;
+    return cannot_handle_persistence ? -ENOSYS : err;
 }
 
 static int
@@ -355,8 +359,10 @@
             g_brightness_max = atoi(property);
             set_brightness_ext_init();
             set_light = set_light_backlight_ext;
-        } else
+        } else {
+            g_has_persistence_node = !access(PERSISTENCE_FILE, F_OK);
             set_light = set_light_backlight;
+        }
     } else if (0 == strcmp(LIGHT_ID_BATTERY, name))
         set_light = set_light_battery;
     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index 0837c99..af2adf7 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -44,9 +44,8 @@
         ALOGE("%s: Private handle is invalid - handle:%p", __func__, handle);
         return -1;
     }
-    if (handle->fd_metadata == -1) {
-        ALOGE("%s: Invalid metadata fd - handle:%p fd: %d",
-                __func__, handle, handle->fd_metadata);
+    if (handle->fd_metadata < 0) {
+        // Silently return, metadata cannot be used
         return -1;
     }
 
diff --git a/libqdutils/qd_utils.cpp b/libqdutils/qd_utils.cpp
index 10ac90b..2cce39c 100644
--- a/libqdutils/qd_utils.cpp
+++ b/libqdutils/qd_utils.cpp
@@ -31,6 +31,7 @@
 #include <gralloc_priv.h>
 #include "qd_utils.h"
 
+static const int kFBNodeMax = 4;
 namespace qdutils {
 
 static int parseLine(char *input, char *tokens[], const uint32_t maxToken, uint32_t *count) {
@@ -57,9 +58,9 @@
     char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
     int j = 0;
 
-    for(j = 0; j < HWC_NUM_DISPLAY_TYPES; j++) {
+    for(j = 0; j < kFBNodeMax; j++) {
         snprintf (msmFbTypePath, sizeof(msmFbTypePath),
-                  "/sys/class/graphics/fb%d/msm_fb_type", j);
+                  "/sys/devices/virtual/graphics/fb%d/msm_fb_type", j);
         displayDeviceFP = fopen(msmFbTypePath, "r");
         if(displayDeviceFP) {
             fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
@@ -71,11 +72,11 @@
             }
             fclose(displayDeviceFP);
         } else {
-            ALOGE("%s: Failed to open fb node %d", __func__, j);
+            ALOGE("%s: Failed to open fb node %s", __func__, msmFbTypePath);
         }
     }
 
-    if (j < HWC_NUM_DISPLAY_TYPES)
+    if (j < kFBNodeMax)
         return j;
     else
         ALOGE("%s: Failed to find %s node", __func__, type);
@@ -186,12 +187,12 @@
     }
 
     snprintf(msmFbTypePath, sizeof(msmFbTypePath),
-                 "/sys/class/graphics/fb%d/edid_raw_data", node_id);
+                 "/sys/devices/virtual/graphics/fb%d/edid_raw_data", node_id);
 
     edidFile = open(msmFbTypePath, O_RDONLY, 0);
 
     if (edidFile < 0) {
-        ALOGE("%s no edid raw data found", __func__);
+        ALOGE("%s no edid raw data found %s", __func__,msmFbTypePath);
         return 0;
     }
 
@@ -214,11 +215,11 @@
     }
 
     snprintf(connectPath, sizeof(connectPath),
-             "/sys/class/graphics/fb%d/connected", nodeId);
+             "/sys/devices/virtual/graphics/fb%d/connected", nodeId);
 
     connectFile = fopen(connectPath, "rb");
     if (!connectFile) {
-        ALOGW("Failed to open connect node for device node %d", nodeId);
+        ALOGW("Failed to open connect node for device node %s", connectPath);
         return false;
     }
 
@@ -253,11 +254,11 @@
     }
 
     snprintf(configPath, sizeof(configPath),
-             "/sys/class/graphics/fb%d/config", nodeId);
+             "/sys/devices/virtual/graphics/fb%d/config", nodeId);
 
     configFile = fopen(configPath, "rb");
     if (!configFile) {
-        ALOGW("Failed to open config node for device node %d", nodeId);
+        ALOGW("Failed to open config node for device node %s", configPath);
         return -EINVAL;
     }
 
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 142d2c6..080f7a1 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -140,6 +140,7 @@
   kIdleTimeout,        // Event triggered by Idle Timer.
   kThermalEvent,       // Event triggered by Thermal.
   kIdlePowerCollapse,  // Event triggered by Idle Power Collapse.
+  kPanelDeadEvent,     // Event triggered by ESD.
 };
 
 /*! @brief This structure defines configuration for fixed properties of a display device.
@@ -674,6 +675,20 @@
   */
   virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable) = 0;
 
+  /*! @brief Method to check whether a client target with the given properties
+      can be supported/handled by hardware.
+
+    @param[in] width client target width
+    @param[in] height client target height
+    @param[in] format client target format
+    @param[in] colorMetaData client target colorMetaData
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetClientTargetSupport(uint32_t width, uint32_t height,
+                                              LayerBufferFormat format,
+                                              const ColorMetaData &color_metadata) = 0;
+
  protected:
   virtual ~DisplayInterface() { }
 };
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index 2cfb99e..f65fabf 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -613,6 +613,16 @@
     return kErrorNone;
   }
 
+  inline PPFeatureInfo* GetFeature(uint32_t feature_id) {
+    PPFeatureInfo* feature = nullptr;
+    if (feature_id < kMaxNumPPFeatures) {
+      if (feature_[feature_id]) {
+        feature = feature_[feature_id];
+      }
+    }
+    return feature;
+  }
+
   inline Locker &GetLocker(void) { return locker_; }
   inline PPFrameCaptureData *GetFrameCaptureData(void) { return &frame_capture_data; }
   inline PPDETuningCfgData *GetDETuningCfgData(void) { return &de_tuning_data_; }
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index b6c4690..173dc4f 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -39,8 +39,10 @@
 const int kMaxSDELayers = 16;   // Maximum number of layers that can be handled by MDP5 hardware
                                 // in a given layer stack.
 #define MAX_PLANES 4
-
 #define MAX_DETAIL_ENHANCE_CURVE 3
+#define MAJOR 28
+#define MINOR 16
+#define SDEVERSION(major, minor, hw_rev) ((major) << MAJOR) | ((minor) << MINOR) | (hw_rev)
 
 enum HWDeviceType {
   kDevicePrimary,
@@ -226,9 +228,6 @@
   CompRatioMap comp_ratio_nrt_map;
   uint32_t cache_size = 0;  // cache size in bytes
   HWQseedStepVersion pipe_qseed3_version = kQseed3v2;  // only valid when has_qseed3=true
-  uint64_t min_core_ib_kbps = 0;
-  uint64_t min_llcc_ib_kbps = 0;
-  uint64_t min_dram_ib_kbps = 0;
 
   void Reset() { *this = HWResourceInfo(); }
 };
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
index bb3b71d..aba66c6 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_peripheral_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_tv_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_events_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_scale_drm.cpp \
diff --git a/sdm/libs/core/color_manager.cpp b/sdm/libs/core/color_manager.cpp
index 938ab99..4c33a25 100644
--- a/sdm/libs/core/color_manager.cpp
+++ b/sdm/libs/core/color_manager.cpp
@@ -180,6 +180,12 @@
 }
 
 DisplayError ColorManagerProxy::Commit() {
+  static bool first_cycle = true;
+  if (first_cycle) {
+    first_cycle = false;
+    return kErrorNone;
+  }
+
   Locker &locker(pp_features_.GetLocker());
   SCOPE_LOCK(locker);
 
diff --git a/sdm/libs/core/core_impl.cpp b/sdm/libs/core/core_impl.cpp
index 661616e..5532858 100644
--- a/sdm/libs/core/core_impl.cpp
+++ b/sdm/libs/core/core_impl.cpp
@@ -23,6 +23,7 @@
 */
 
 #include <dlfcn.h>
+#include <signal.h>
 #include <utils/locker.h>
 #include <utils/constants.h>
 #include <utils/debug.h>
@@ -91,6 +92,7 @@
     DLOGW("Unable creating color manager and continue without it.");
   }
 
+  signal(SIGPIPE, SIG_IGN);
   return kErrorNone;
 
 CleanupOnError:
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 1ffe862..34740a9 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -27,6 +27,7 @@
 #include <utils/debug.h>
 #include <utils/formats.h>
 #include <utils/rect.h>
+#include <utils/utils.h>
 #include <string>
 #include <vector>
 #include <algorithm>
@@ -108,6 +109,9 @@
   }
 
   Debug::Get()->GetProperty("sdm.disable_hdr_lut_gen", &disable_hdr_lut_gen_);
+  // TODO(user): Temporary changes, to be removed when DRM driver supports
+  // Partial update with Destination scaler enabled.
+  SetPUonDestScaler();
 
   return kErrorNone;
 
@@ -235,8 +239,10 @@
   if (color_mgr_ && color_mgr_->NeedsPartialUpdateDisable()) {
     DisablePartialUpdateOneFrame();
   }
-
-  if (partial_update_control_ == false || disable_pu_one_frame_) {
+  // TODO(user): Temporary changes, to be removed when DRM driver supports
+  // Partial update with Destination scaler enabled.
+  if (partial_update_control_ == false || disable_pu_one_frame_ ||
+      disable_pu_on_dest_scaler_) {
     comp_manager_->ControlPartialUpdate(display_comp_ctx_, false /* enable */);
     disable_pu_one_frame_ = false;
   }
@@ -416,6 +422,10 @@
   return kErrorNone;
 }
 
+DisplayState DisplayBase::GetLastPowerMode() {
+  return last_power_mode_;
+}
+
 DisplayError DisplayBase::SetDisplayState(DisplayState state) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   DisplayError error = kErrorNone;
@@ -450,11 +460,13 @@
     }
 
     active = true;
+    last_power_mode_ = kStateOn;
     break;
 
   case kStateDoze:
     error = hw_intf_->Doze();
     active = true;
+    last_power_mode_ = kStateDoze;
     break;
 
   case kStateDozeSuspend:
@@ -462,11 +474,12 @@
     if (display_type_ != kPrimary) {
       active = true;
     }
-
+    last_power_mode_ = kStateDozeSuspend;
     break;
 
   case kStateStandby:
     error = hw_intf_->Standby();
+    last_power_mode_ = kStateStandby;
     break;
 
   default:
@@ -1050,13 +1063,15 @@
     return error;
   }
 
-  if (mixer_attributes != mixer_attributes_) {
-    DisablePartialUpdateOneFrame();
-  }
+  // Disable partial update for one frame on any display changes
+  DisablePartialUpdateOneFrame();
 
   display_attributes_ = display_attributes;
   mixer_attributes_ = mixer_attributes;
   hw_panel_info_ = hw_panel_info;
+  // TODO(user): Temporary changes, to be removed when DRM driver supports
+  // Partial update with Destination scaler enabled.
+  SetPUonDestScaler();
 
   return kErrorNone;
 }
@@ -1196,7 +1211,10 @@
       *new_mixer_width = display_width;
       *new_mixer_height = display_height;
     }
-
+    if (*new_mixer_width > display_width || *new_mixer_height > display_height) {
+      *new_mixer_width = display_width;
+      *new_mixer_height = display_height;
+    }
     return true;
   }
 
@@ -1256,8 +1274,17 @@
   if (error != kErrorNone) {
     return error;
   }
-
-  DisablePartialUpdateOneFrame();
+  // TODO(user): Temporary changes, to be removed when DRM driver supports
+  // Partial update with Destination scaler enabled.
+  if (GetDriverType() == DriverType::DRM) {
+    if (de_data.enable) {
+      disable_pu_on_dest_scaler_ = true;
+    } else {
+      SetPUonDestScaler();
+    }
+  } else {
+    DisablePartialUpdateOneFrame();
+  }
 
   return kErrorNone;
 }
@@ -1493,4 +1520,108 @@
   return kErrorNone;
 }
 
+DisplayError DisplayBase::GetClientTargetSupport(uint32_t width, uint32_t height,
+                                                 LayerBufferFormat format,
+                                                 const ColorMetaData &color_metadata) {
+  DisplayError error = kErrorNone;
+
+  if (format != kFormatRGBA8888 && format != kFormatRGBA1010102) {
+    DLOGW("Unsupported format = %d", format);
+    error = kErrorNotSupported;
+  } else if (ValidateScaling(width, height) != kErrorNone) {
+    DLOGW("Unsupported width = %d height = %d", width, height);
+    error = kErrorNotSupported;
+  } else {
+    error = ValidateDataspace(color_metadata);
+    if (error != kErrorNone) {
+      return error;
+    }
+
+    // Check for BT2020 support
+    if (color_metadata.colorPrimaries == ColorPrimaries_BT2020) {
+      DLOGW("Unsupported dataspace");
+      error = kErrorNotSupported;
+    }
+  }
+
+  return error;
+}
+
+DisplayError DisplayBase::ValidateScaling(uint32_t width, uint32_t height) {
+  uint32_t display_width = display_attributes_.x_pixels;
+  uint32_t display_height = display_attributes_.y_pixels;
+
+  HWResourceInfo hw_resource_info = HWResourceInfo();
+  hw_info_intf_->GetHWResourceInfo(&hw_resource_info);
+  float max_scale_down = FLOAT(hw_resource_info.max_scale_down);
+  float max_scale_up = FLOAT(hw_resource_info.max_scale_up);
+
+  float scale_x = FLOAT(width / display_width);
+  float scale_y = FLOAT(height / display_height);
+
+  if (scale_x > max_scale_down || scale_y > max_scale_down) {
+    return kErrorNotSupported;
+  }
+
+  if (UINT32(scale_x) < 1 && scale_x > 0.0f) {
+    if ((1.0f / scale_x) > max_scale_up) {
+      return kErrorNotSupported;
+    }
+  }
+
+  if (UINT32(scale_y) < 1 && scale_y > 0.0f) {
+    if ((1.0f / scale_y) > max_scale_up) {
+      return kErrorNotSupported;
+    }
+  }
+
+  return kErrorNone;
+}
+
+DisplayError DisplayBase::ValidateDataspace(const ColorMetaData &color_metadata) {
+  // Handle transfer
+  switch (color_metadata.transfer) {
+    case Transfer_sRGB:
+    case Transfer_SMPTE_170M:
+    case Transfer_SMPTE_ST2084:
+    case Transfer_HLG:
+    case Transfer_Linear:
+    case Transfer_Gamma2_2:
+      break;
+    default:
+      DLOGW("Unsupported Transfer Request = %d", color_metadata.transfer);
+      return kErrorNotSupported;
+  }
+
+  // Handle colorPrimaries
+  switch (color_metadata.colorPrimaries) {
+    case ColorPrimaries_BT709_5:
+    case ColorPrimaries_BT601_6_525:
+    case ColorPrimaries_BT601_6_625:
+    case ColorPrimaries_DCIP3:
+    case ColorPrimaries_BT2020:
+      break;
+    default:
+      DLOGW("Unsupported Color Primary = %d", color_metadata.colorPrimaries);
+      return kErrorNotSupported;
+  }
+
+  return kErrorNone;
+}
+
+// TODO(user): Temporary changes, to be removed when DRM driver supports
+// Partial update with Destination scaler enabled.
+void DisplayBase::SetPUonDestScaler() {
+  if (GetDriverType() == DriverType::FB) {
+    return;
+  }
+  uint32_t mixer_width = mixer_attributes_.width;
+  uint32_t mixer_height = mixer_attributes_.height;
+  uint32_t display_width = display_attributes_.x_pixels;
+  uint32_t display_height = display_attributes_.y_pixels;
+
+  disable_pu_on_dest_scaler_ = (mixer_width != display_width ||
+                                mixer_height != display_height);
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 979a465..9696a3f 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -115,6 +115,9 @@
   virtual DisplayError GetDisplayPort(DisplayPort *port);
   virtual bool IsPrimaryDisplay();
   virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable);
+  virtual DisplayError GetClientTargetSupport(uint32_t width, uint32_t height,
+                                              LayerBufferFormat format,
+                                              const ColorMetaData &color_metadata);
 
  protected:
   DisplayError BuildLayerStackStats(LayerStack *layer_stack);
@@ -124,6 +127,8 @@
   DisplayError HandleHDR(LayerStack *layer_stack);
   DisplayError ValidateHDR(LayerStack *layer_stack);
   DisplayError SetHDRMode(bool set);
+  DisplayError ValidateScaling(uint32_t width, uint32_t height);
+  DisplayError ValidateDataspace(const ColorMetaData &color_metadata);
 
   // DumpImpl method
   void AppendDump(char *buffer, uint32_t length);
@@ -140,6 +145,8 @@
                                        std::string *value);
   DisplayError GetHdrColorMode(std::string *color_mode, bool *found_hdr);
   bool IsSupportColorModeAttribute(const std::string &color_mode);
+  DisplayState GetLastPowerMode();
+  void SetPUonDestScaler();
 
   recursive_mutex recursive_mutex_;
   DisplayType display_type_;
@@ -163,6 +170,9 @@
   bool partial_update_control_ = true;
   HWEventsInterface *hw_events_intf_ = NULL;
   bool disable_pu_one_frame_ = false;
+  // TODO(user): Temporary changes, to be removed when DRM driver supports
+  // Partial update with Destination scaler enabled.
+  bool disable_pu_on_dest_scaler_ = false;
   uint32_t num_color_modes_ = 0;
   std::vector<SDEDisplayMode> color_modes_;
   typedef std::map<std::string, SDEDisplayMode *> ColorModeMap;
@@ -178,6 +188,7 @@
   bool hdr_playback_ = false;
   bool hdr_mode_ = false;
   int disable_hdr_lut_gen_ = 0;
+  DisplayState last_power_mode_ = kStateOff;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/display_hdmi.h b/sdm/libs/core/display_hdmi.h
index 8248840..dde3858 100644
--- a/sdm/libs/core/display_hdmi.h
+++ b/sdm/libs/core/display_hdmi.h
@@ -56,6 +56,7 @@
   virtual void CECMessage(char *message);
   virtual void IdlePowerCollapse() { }
   virtual void PingPongTimeout() { }
+  virtual void PanelDead() { }
 
  private:
   uint32_t GetBestConfig(HWS3DMode s3d_mode);
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index 8f3d6f0..0c8760e 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -91,6 +91,12 @@
   uint32_t display_width = display_attributes_.x_pixels;
   uint32_t display_height = display_attributes_.y_pixels;
 
+  if (reset_panel_) {
+    DLOGW("panel is in bad state, resetting the panel");
+    ResetPanel();
+    reset_panel_ = false;
+  }
+
   if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) {
     error = ReconfigureMixer(new_mixer_width, new_mixer_height);
     if (error != kErrorNone) {
@@ -160,10 +166,7 @@
 
 void DisplayPrimary::SetIdleTimeoutMs(uint32_t active_ms) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
-
-  if (comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, active_ms) == kErrorNone) {
-    hw_intf_->SetIdleTimeoutMs(active_ms);
-  }
+  comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, active_ms);
 }
 
 DisplayError DisplayPrimary::SetDisplayMode(uint32_t mode) {
@@ -202,7 +205,7 @@
       ControlPartialUpdate(false /* enable */, &pending);
     } else if (mode == kModeCommand) {
       // Flush idle timeout value currently set.
-      hw_intf_->SetIdleTimeoutMs(0);
+      comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, 0);
       switch_to_cmd_ = true;
     }
   }
@@ -308,6 +311,15 @@
   comp_manager_->ProcessIdlePowerCollapse(display_comp_ctx_);
 }
 
+void DisplayPrimary::PanelDead() {
+  event_handler_->HandleEvent(kPanelDeadEvent);
+  event_handler_->Refresh();
+  {
+    lock_guard<recursive_mutex> obj(recursive_mutex_);
+    reset_panel_ = true;
+  }
+}
+
 DisplayError DisplayPrimary::GetPanelBrightness(int *level) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   return hw_intf_->GetPanelBrightness(level);
@@ -359,5 +371,28 @@
           hw_panel_info_.min_fps != hw_panel_info_.max_fps)));
 }
 
+void DisplayPrimary::ResetPanel() {
+  DisplayError status = kErrorNone;
+
+  DLOGI("Powering off primary");
+  status = SetDisplayState(kStateOff);
+  if (status != kErrorNone) {
+    DLOGE("power-off on primary failed with error = %d", status);
+  }
+
+  DLOGI("Restoring power mode on primary");
+  DisplayState mode = GetLastPowerMode();
+  status = SetDisplayState(mode);
+  if (status != kErrorNone) {
+    DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status);
+  }
+
+  DLOGI("Enabling HWVsync");
+  status = SetVSyncState(true);
+  if (status != kErrorNone) {
+    DLOGE("enabling vsync failed for primary with error = %d", status);
+  }
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/display_primary.h b/sdm/libs/core/display_primary.h
index e5aeabc..ac4160e 100644
--- a/sdm/libs/core/display_primary.h
+++ b/sdm/libs/core/display_primary.h
@@ -62,20 +62,24 @@
   virtual void CECMessage(char *message) { }
   virtual void IdlePowerCollapse();
   virtual void PingPongTimeout();
+  virtual void PanelDead();
 
  private:
   bool NeedsAVREnable();
+  void ResetPanel();
 
   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 };
+                                       HWEvent::PINGPONG_TIMEOUT,
+                                       HWEvent::PANEL_DEAD };
   bool avr_prop_disabled_ = false;
   bool switch_to_cmd_ = false;
   bool handle_idle_timeout_ = false;
   uint32_t current_refresh_rate_ = 0;
+  bool reset_panel_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/display_virtual.cpp b/sdm/libs/core/display_virtual.cpp
index fcdc152..dfe4fd3 100644
--- a/sdm/libs/core/display_virtual.cpp
+++ b/sdm/libs/core/display_virtual.cpp
@@ -24,7 +24,7 @@
 
 #include <utils/constants.h>
 #include <utils/debug.h>
-
+#include <algorithm>
 #include "display_virtual.h"
 #include "hw_interface.h"
 #include "hw_info_interface.h"
@@ -49,11 +49,25 @@
     return error;
   }
 
-  hw_intf_->GetDisplayAttributes(0 /* active_index */, &display_attributes_);
+  HWScaleLutInfo lut_info = {};
+  error = comp_manager_->GetScaleLutConfig(&lut_info);
+  if (error == kErrorNone) {
+    error = hw_intf_->SetScaleLutConfig(&lut_info);
+    if (error != kErrorNone) {
+      HWInterface::Destroy(hw_intf_);
+      return error;
+    }
+  }
 
-  error = DisplayBase::Init();
-  if (error != kErrorNone) {
-    HWInterface::Destroy(hw_intf_);
+  if (hw_info_intf_) {
+    HWResourceInfo hw_resource_info = HWResourceInfo();
+    hw_info_intf_->GetHWResourceInfo(&hw_resource_info);
+    auto max_mixer_stages = hw_resource_info.num_blending_stages;
+    int property_value = Debug::GetMaxPipesPerMixer(display_type_);
+    if (property_value >= 0) {
+      max_mixer_stages = std::min(UINT32(property_value), hw_resource_info.num_blending_stages);
+    }
+    DisplayBase::SetMaxMixerStages(max_mixer_stages);
   }
 
   return error;
@@ -87,6 +101,8 @@
   DisplayError error = kErrorNone;
   HWDisplayAttributes display_attributes;
   HWMixerAttributes mixer_attributes;
+  HWPanelInfo hw_panel_info = {};
+  DisplayConfigVariableInfo fb_config = fb_config_;
 
   display_attributes.x_pixels = variable_info->x_pixels;
   display_attributes.y_pixels = variable_info->y_pixels;
@@ -101,25 +117,34 @@
     return error;
   }
 
+  hw_intf_->GetHWPanelInfo(&hw_panel_info);
+
   error = hw_intf_->GetMixerAttributes(&mixer_attributes);
   if (error != kErrorNone) {
     return error;
   }
 
+  // fb_config will be updated only once after creation of virtual display
+  if (fb_config.x_pixels == 0 || fb_config.y_pixels == 0) {
+    fb_config = display_attributes;
+  }
+
   // if display is already connected, unregister display from composition manager and register
   // the display with new configuration.
   if (display_comp_ctx_) {
     comp_manager_->UnregisterDisplay(display_comp_ctx_);
   }
 
-  error = comp_manager_->RegisterDisplay(display_type_, display_attributes, hw_panel_info_,
-                                         mixer_attributes, fb_config_, &display_comp_ctx_);
+  error = comp_manager_->RegisterDisplay(display_type_, display_attributes, hw_panel_info,
+                                         mixer_attributes, fb_config, &display_comp_ctx_);
   if (error != kErrorNone) {
     return error;
   }
 
   display_attributes_ = display_attributes;
   mixer_attributes_ = mixer_attributes;
+  hw_panel_info_ = hw_panel_info;
+  fb_config_ = fb_config;
 
   DLOGI("Virtual display resolution changed to[%dx%d]", display_attributes_.x_pixels,
         display_attributes_.y_pixels);
diff --git a/sdm/libs/core/display_virtual.h b/sdm/libs/core/display_virtual.h
index 185366c..f9cc737 100644
--- a/sdm/libs/core/display_virtual.h
+++ b/sdm/libs/core/display_virtual.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 met:
@@ -56,9 +56,6 @@
   virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate) {
     return kErrorNotSupported;
   }
-  virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height) {
-    return kErrorNotSupported;
-  }
   virtual DisplayError SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data) {
     return kErrorNotSupported;
   }
diff --git a/sdm/libs/core/drm/hw_color_manager_drm.cpp b/sdm/libs/core/drm/hw_color_manager_drm.cpp
index 2000f9a..95c25cd 100644
--- a/sdm/libs/core/drm/hw_color_manager_drm.cpp
+++ b/sdm/libs/core/drm/hw_color_manager_drm.cpp
@@ -35,35 +35,63 @@
 #include <utils/debug.h>
 #include "hw_color_manager_drm.h"
 
-using sde_drm::kFeaturePcc;
-using sde_drm::kFeatureIgc;
-using sde_drm::kFeaturePgc;
-using sde_drm::kFeatureMixerGc;
-using sde_drm::kFeaturePaV2;
-using sde_drm::kFeatureDither;
-using sde_drm::kFeatureGamut;
-using sde_drm::kFeaturePADither;
-using sde_drm::kPPFeaturesMax;
-
 #ifdef PP_DRM_ENABLE
 static const uint32_t kPgcDataMask = 0x3FF;
 static const uint32_t kPgcShift = 16;
 
 static const uint32_t kIgcDataMask = 0xFFF;
 static const uint32_t kIgcShift = 16;
+
+#ifdef DRM_MSM_PA_HSIC
+static const uint32_t kPAHueMask = (1 << 12);
+static const uint32_t kPASatMask = (1 << 13);
+static const uint32_t kPAValMask = (1 << 14);
+static const uint32_t kPAContrastMask = (1 << 15);
+#endif
+
+#ifdef DRM_MSM_SIXZONE
+static const uint32_t kSixZoneP0Mask = 0x0FFF;
+static const uint32_t kSixZoneP1Mask = 0x0FFF0FFF;
+static const uint32_t kSixZoneHueMask = (1 << 16);
+static const uint32_t kSixZoneSatMask = (1 << 17);
+static const uint32_t kSixZoneValMask = (1 << 18);
+#endif
+
+#ifdef DRM_MSM_MEMCOL
+static const uint32_t kMemColorProtHueMask = (1 << 0);
+static const uint32_t kMemColorProtSatMask = (1 << 1);
+static const uint32_t kMemColorProtValMask = (1 << 2);
+static const uint32_t kMemColorProtContMask = (1 << 3);
+static const uint32_t kMemColorProtSixZoneMask = (1 << 4);
+static const uint32_t kMemColorProtBlendMask = (1 << 5);
+
+static const uint32_t kMemColorProtMask = \
+  (kMemColorProtHueMask | kMemColorProtSatMask | kMemColorProtValMask | \
+    kMemColorProtContMask | kMemColorProtSixZoneMask | kMemColorProtBlendMask);
+
+static const uint32_t kMemColorSkinMask = (1 << 19);
+static const uint32_t kMemColorSkyMask = (1 << 20);
+static const uint32_t kMemColorFolMask = (1 << 21);
+#endif
 #endif
 
 namespace sdm {
 
 DisplayError (*HWColorManagerDrm::GetDrmFeature[])(const PPFeatureInfo &, DRMPPFeatureInfo *) = {
-        [kGlobalColorFeaturePcc] = &HWColorManagerDrm::GetDrmPCC,
-        [kGlobalColorFeatureIgc] = &HWColorManagerDrm::GetDrmIGC,
-        [kGlobalColorFeaturePgc] = &HWColorManagerDrm::GetDrmPGC,
-        [kMixerColorFeatureGc] = &HWColorManagerDrm::GetDrmMixerGC,
-        [kGlobalColorFeaturePaV2] = &HWColorManagerDrm::GetDrmPAV2,
-        [kGlobalColorFeatureDither] = &HWColorManagerDrm::GetDrmDither,
-        [kGlobalColorFeatureGamut] = &HWColorManagerDrm::GetDrmGamut,
-        [kGlobalColorFeaturePADither] = &HWColorManagerDrm::GetDrmPADither,
+        [kFeaturePcc] = &HWColorManagerDrm::GetDrmPCC,
+        [kFeatureIgc] = &HWColorManagerDrm::GetDrmIGC,
+        [kFeaturePgc] = &HWColorManagerDrm::GetDrmPGC,
+        [kFeatureMixerGc] = &HWColorManagerDrm::GetDrmMixerGC,
+        [kFeaturePaV2] = NULL,
+        [kFeatureDither] = &HWColorManagerDrm::GetDrmDither,
+        [kFeatureGamut] = &HWColorManagerDrm::GetDrmGamut,
+        [kFeaturePADither] = &HWColorManagerDrm::GetDrmPADither,
+        [kFeaturePAHsic] = &HWColorManagerDrm::GetDrmPAHsic,
+        [kFeaturePASixZone] = &HWColorManagerDrm::GetDrmPASixZone,
+        [kFeaturePAMemColSkin] = &HWColorManagerDrm::GetDrmPAMemColSkin,
+        [kFeaturePAMemColSky] = &HWColorManagerDrm::GetDrmPAMemColSky,
+        [kFeaturePAMemColFoliage] = &HWColorManagerDrm::GetDrmPAMemColFoliage,
+        [kFeaturePAMemColProt] = &HWColorManagerDrm::GetDrmPAMemColProt,
 };
 
 void HWColorManagerDrm::FreeDrmFeatureData(DRMPPFeatureInfo *feature) {
@@ -94,7 +122,13 @@
     case kFeatureMixerGc:
         version = PPFeatureVersion::kSDEPgcV17;
       break;
-    case kFeaturePaV2:
+    case kFeaturePAHsic:
+    case kFeaturePASixZone:
+    case kFeaturePAMemColSkin:
+    case kFeaturePAMemColSky:
+    case kFeaturePAMemColFoliage:
+    case kFeaturePAMemColProt:
+      if (feature.version == 1)
         version = PPFeatureVersion::kSDEPaV17;
       break;
     case kFeatureDither:
@@ -132,7 +166,7 @@
       ret = kFeatureMixerGc;
       break;
     case kGlobalColorFeaturePaV2:
-      ret = kFeaturePaV2;
+      ret = kFeaturePAHsic;
       break;
     case kGlobalColorFeatureDither:
       ret = kFeatureDither;
@@ -366,18 +400,394 @@
   return ret;
 }
 
-DisplayError HWColorManagerDrm::GetDrmPAV2(const PPFeatureInfo &in_data,
+DisplayError HWColorManagerDrm::GetDrmPAHsic(const PPFeatureInfo &in_data,
                                            DRMPPFeatureInfo *out_data) {
   DisplayError ret = kErrorNone;
-#ifdef PP_DRM_ENABLE
+#if defined(PP_DRM_ENABLE) && defined(DRM_MSM_PA_HSIC)
+  struct SDEPaData *sde_pa;
+  struct drm_msm_pa_hsic *mdp_hsic;
+
   if (!out_data) {
-    DLOGE("Invalid input parameter for PA V2");
+    DLOGE("Invalid input parameter for pa hsic");
     return kErrorParameters;
   }
 
-  out_data->id = kPPFeaturesMax;
+  sde_pa = (struct SDEPaData *) in_data.GetConfigData();
+
+  out_data->id = kFeaturePAHsic;
   out_data->type = sde_drm::kPropBlob;
   out_data->version = in_data.feature_version_;
+  out_data->payload_size = 0;
+  out_data->payload = NULL;
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* Complete PA features disable case */
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    DLOGE("Invalid ops for pa hsic");
+    return kErrorParameters;
+  }
+
+  if (!(sde_pa->mode & (kPAHueMask | kPASatMask |
+                        kPAValMask | kPAContrastMask))) {
+    /* PA HSIC feature disable case, but other PA features active */
+    return ret;
+  }
+
+  mdp_hsic = new drm_msm_pa_hsic();
+  if (!mdp_hsic) {
+    DLOGE("Failed to allocate memory for pa hsic");
+    return kErrorMemory;
+  }
+
+  mdp_hsic->flags = 0;
+
+  if (in_data.enable_flags_ & kPaHueEnable) {
+    mdp_hsic->flags |= PA_HSIC_HUE_ENABLE;
+    mdp_hsic->hue = sde_pa->hue_adj;
+  }
+  if (in_data.enable_flags_ & kPaSatEnable) {
+    mdp_hsic->flags |= PA_HSIC_SAT_ENABLE;
+    mdp_hsic->saturation = sde_pa->sat_adj;
+  }
+  if (in_data.enable_flags_ & kPaValEnable) {
+    mdp_hsic->flags |= PA_HSIC_VAL_ENABLE;
+    mdp_hsic->value = sde_pa->val_adj;
+  }
+  if (in_data.enable_flags_ & kPaContEnable) {
+    mdp_hsic->flags |= PA_HSIC_CONT_ENABLE;
+    mdp_hsic->contrast = sde_pa->cont_adj;
+  }
+
+  if (mdp_hsic->flags) {
+    out_data->payload = mdp_hsic;
+    out_data->payload_size = sizeof(struct drm_msm_pa_hsic);
+  } else {
+    /* PA HSIC configuration unchanged, no better return code available */
+    delete mdp_hsic;
+    ret = kErrorPermission;
+  }
+#endif
+  return ret;
+}
+
+DisplayError HWColorManagerDrm::GetDrmPASixZone(const PPFeatureInfo &in_data,
+                                                DRMPPFeatureInfo *out_data) {
+  DisplayError ret = kErrorNone;
+#if defined(PP_DRM_ENABLE) && defined(DRM_MSM_SIXZONE)
+  struct SDEPaData *sde_pa;
+
+  if (!out_data) {
+    DLOGE("Invalid input parameter for six zone");
+    return kErrorParameters;
+  }
+
+  sde_pa = (struct SDEPaData *) in_data.GetConfigData();
+
+  out_data->id = kFeaturePASixZone;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+  out_data->payload_size = 0;
+  out_data->payload = NULL;
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* Complete PA features disable case */
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    DLOGE("Invalid ops for six zone");
+    return kErrorParameters;
+  }
+
+  if (!(sde_pa->mode & (kSixZoneHueMask | kSixZoneSatMask |
+                        kSixZoneValMask))) {
+    /* PA SixZone feature disable case, but other PA features active */
+    return ret;
+  }
+
+  if (in_data.enable_flags_ & kPaSixZoneEnable) {
+    struct drm_msm_sixzone *mdp_sixzone = NULL;
+
+    if ((!sde_pa->six_zone_curve_p0 || !sde_pa->six_zone_curve_p1) ||
+        (sde_pa->six_zone_len != SIXZONE_LUT_SIZE)) {
+        DLOGE("Invaid sixzone curve");
+        return kErrorParameters;
+    }
+
+    mdp_sixzone = new drm_msm_sixzone();
+    if (!mdp_sixzone) {
+      DLOGE("Failed to allocate memory for six zone");
+      return kErrorMemory;
+    }
+
+    mdp_sixzone->flags = 0;
+
+    if (sde_pa->mode & kSixZoneHueMask) {
+      mdp_sixzone->flags |= SIXZONE_HUE_ENABLE;
+    }
+    if (sde_pa->mode & kSixZoneSatMask) {
+      mdp_sixzone->flags |= SIXZONE_SAT_ENABLE;
+    }
+    if (sde_pa->mode & kSixZoneValMask) {
+      mdp_sixzone->flags |= SIXZONE_VAL_ENABLE;
+    }
+
+    mdp_sixzone->threshold = sde_pa->six_zone_thresh;
+    mdp_sixzone->adjust_p0 = sde_pa->six_zone_adj_p0;
+    mdp_sixzone->adjust_p1 = sde_pa->six_zone_adj_p1;
+    mdp_sixzone->sat_hold = sde_pa->six_zone_sat_hold;
+    mdp_sixzone->val_hold = sde_pa->six_zone_val_hold;
+
+    for (int i = 0; i < SIXZONE_LUT_SIZE; i++) {
+      mdp_sixzone->curve[i].p0 = sde_pa->six_zone_curve_p0[i] & kSixZoneP0Mask;
+      mdp_sixzone->curve[i].p1 = sde_pa->six_zone_curve_p1[i] & kSixZoneP1Mask;
+    }
+    out_data->payload = mdp_sixzone;
+    out_data->payload_size = sizeof(struct drm_msm_sixzone);
+  } else {
+    /* PA SixZone configuration unchanged, no better return code available */
+    ret = kErrorPermission;
+  }
+
+#endif
+  return ret;
+}
+
+DisplayError HWColorManagerDrm::GetDrmPAMemColSkin(const PPFeatureInfo &in_data,
+                                                   DRMPPFeatureInfo *out_data) {
+  DisplayError ret = kErrorNone;
+#if defined(PP_DRM_ENABLE) && defined(DRM_MSM_MEMCOL)
+  struct SDEPaData *sde_pa;
+
+  if (!out_data) {
+    DLOGE("Invalid input parameter for memory color skin");
+    return kErrorParameters;
+  }
+
+  sde_pa = (struct SDEPaData *) in_data.GetConfigData();
+
+  out_data->id = kFeaturePAMemColSkin;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+  out_data->payload_size = 0;
+  out_data->payload = NULL;
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* Complete PA features disable case */
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    DLOGE("Invalid ops for memory color skin");
+    return kErrorParameters;
+  }
+
+  if (!(sde_pa->mode & kMemColorSkinMask)) {
+    /* PA MemColSkin feature disable case, but other PA features active */
+    return ret;
+  }
+
+  if (in_data.enable_flags_ & kPaSkinEnable) {
+    struct drm_msm_memcol *mdp_memcol = NULL;
+    struct SDEPaMemColorData *pa_memcol = &sde_pa->skin;
+
+    mdp_memcol = new drm_msm_memcol();
+    if (!mdp_memcol) {
+      DLOGE("Failed to allocate memory for memory color skin");
+      return kErrorMemory;
+    }
+
+    mdp_memcol->prot_flags = 0;
+    mdp_memcol->color_adjust_p0 = pa_memcol->adjust_p0;
+    mdp_memcol->color_adjust_p1 = pa_memcol->adjust_p1;
+    mdp_memcol->color_adjust_p2 = pa_memcol->adjust_p2;
+    mdp_memcol->blend_gain = pa_memcol->blend_gain;
+    mdp_memcol->sat_hold = pa_memcol->sat_hold;
+    mdp_memcol->val_hold = pa_memcol->val_hold;
+    mdp_memcol->hue_region = pa_memcol->hue_region;
+    mdp_memcol->sat_region = pa_memcol->sat_region;
+    mdp_memcol->val_region = pa_memcol->val_region;
+
+    out_data->payload = mdp_memcol;
+    out_data->payload_size = sizeof(struct drm_msm_memcol);
+  } else {
+    /* PA MemColSkin configuration unchanged, no better return code available */
+    ret = kErrorPermission;
+  }
+#endif
+  return ret;
+}
+
+DisplayError HWColorManagerDrm::GetDrmPAMemColSky(const PPFeatureInfo &in_data,
+                                                  DRMPPFeatureInfo *out_data) {
+  DisplayError ret = kErrorNone;
+#if defined(PP_DRM_ENABLE) && defined(DRM_MSM_MEMCOL)
+  struct SDEPaData *sde_pa;
+
+  if (!out_data) {
+    DLOGE("Invalid input parameter for memory color sky");
+    return kErrorParameters;
+  }
+
+  sde_pa = (struct SDEPaData *) in_data.GetConfigData();
+
+  out_data->id = kFeaturePAMemColSky;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+  out_data->payload_size = 0;
+  out_data->payload = NULL;
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* Complete PA features disable case */
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    DLOGE("Invalid ops for memory color sky");
+    return kErrorParameters;
+  }
+
+  if (!(sde_pa->mode & kMemColorSkyMask)) {
+    /* PA MemColSky feature disable case, but other PA features active */
+    return ret;
+  }
+
+  if (in_data.enable_flags_ & kPaSkyEnable) {
+    struct drm_msm_memcol *mdp_memcol = NULL;
+    struct SDEPaMemColorData *pa_memcol = &sde_pa->sky;
+
+    mdp_memcol = new drm_msm_memcol();
+    if (!mdp_memcol) {
+      DLOGE("Failed to allocate memory for memory color sky");
+      return kErrorMemory;
+    }
+
+    mdp_memcol->prot_flags = 0;
+    mdp_memcol->color_adjust_p0 = pa_memcol->adjust_p0;
+    mdp_memcol->color_adjust_p1 = pa_memcol->adjust_p1;
+    mdp_memcol->color_adjust_p2 = pa_memcol->adjust_p2;
+    mdp_memcol->blend_gain = pa_memcol->blend_gain;
+    mdp_memcol->sat_hold = pa_memcol->sat_hold;
+    mdp_memcol->val_hold = pa_memcol->val_hold;
+    mdp_memcol->hue_region = pa_memcol->hue_region;
+    mdp_memcol->sat_region = pa_memcol->sat_region;
+    mdp_memcol->val_region = pa_memcol->val_region;
+
+    out_data->payload = mdp_memcol;
+    out_data->payload_size = sizeof(struct drm_msm_memcol);
+  } else {
+    /* PA MemColSky configuration unchanged, no better return code available */
+    ret = kErrorPermission;
+  }
+#endif
+  return ret;
+}
+
+DisplayError HWColorManagerDrm::GetDrmPAMemColFoliage(const PPFeatureInfo &in_data,
+                                                      DRMPPFeatureInfo *out_data) {
+  DisplayError ret = kErrorNone;
+#if defined(PP_DRM_ENABLE) && defined(DRM_MSM_MEMCOL)
+  struct SDEPaData *sde_pa;
+
+  if (!out_data) {
+    DLOGE("Invalid input parameter for memory color foliage");
+    return kErrorParameters;
+  }
+
+  sde_pa = (struct SDEPaData *) in_data.GetConfigData();
+
+  out_data->id = kFeaturePAMemColFoliage;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+  out_data->payload_size = 0;
+  out_data->payload = NULL;
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* Complete PA features disable case */
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    DLOGE("Invalid ops for memory color foliage");
+    return kErrorParameters;
+  }
+
+  if (!(sde_pa->mode & kMemColorFolMask)) {
+    /* PA MemColFoliage feature disable case, but other PA features active */
+    return ret;
+  }
+
+  if (in_data.enable_flags_ & kPaFoliageEnable) {
+    struct drm_msm_memcol *mdp_memcol = NULL;
+    struct SDEPaMemColorData *pa_memcol = &sde_pa->foliage;
+
+    mdp_memcol = new drm_msm_memcol();
+    if (!mdp_memcol) {
+      DLOGE("Failed to allocate memory for memory color foliage");
+      return kErrorMemory;
+    }
+
+    mdp_memcol->prot_flags = 0;
+    mdp_memcol->color_adjust_p0 = pa_memcol->adjust_p0;
+    mdp_memcol->color_adjust_p1 = pa_memcol->adjust_p1;
+    mdp_memcol->color_adjust_p2 = pa_memcol->adjust_p2;
+    mdp_memcol->blend_gain = pa_memcol->blend_gain;
+    mdp_memcol->sat_hold = pa_memcol->sat_hold;
+    mdp_memcol->val_hold = pa_memcol->val_hold;
+    mdp_memcol->hue_region = pa_memcol->hue_region;
+    mdp_memcol->sat_region = pa_memcol->sat_region;
+    mdp_memcol->val_region = pa_memcol->val_region;
+
+    out_data->payload = mdp_memcol;
+    out_data->payload_size = sizeof(struct drm_msm_memcol);
+  } else {
+    /* PA MemColFoliage configuration unchanged, no better return code available */
+    ret = kErrorPermission;
+  }
+#endif
+  return ret;
+}
+
+DisplayError HWColorManagerDrm::GetDrmPAMemColProt(const PPFeatureInfo &in_data,
+                                                   DRMPPFeatureInfo *out_data) {
+  DisplayError ret = kErrorNone;
+#if defined(PP_DRM_ENABLE) && defined(DRM_MSM_MEMCOL)
+  struct SDEPaData *sde_pa;
+  struct drm_msm_memcol *mdp_memcol;
+
+  if (!out_data) {
+    DLOGE("Invalid input parameter for memory color prot");
+    return kErrorParameters;
+  }
+
+  sde_pa = (struct SDEPaData *) in_data.GetConfigData();
+
+  out_data->id = kFeaturePAMemColProt;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+  out_data->payload_size = sizeof(struct drm_msm_memcol);
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* Complete PA features disable case */
+    out_data->payload = NULL;
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    out_data->payload = NULL;
+    return kErrorParameters;
+  }
+
+  out_data->payload = NULL;
+  if (!(sde_pa->mode & kMemColorProtMask)) {
+    /* PA MemColProt feature disable case, but other PA features active */
+    return ret;
+  }
+
+  mdp_memcol = new drm_msm_memcol();
+  if (!mdp_memcol) {
+    DLOGE("Failed to allocate memory for memory color prot");
+    return kErrorMemory;
+  }
+
+  mdp_memcol->prot_flags = 0;
+
+  if (sde_pa->mode & kMemColorProtMask) {
+    mdp_memcol->prot_flags |= (sde_pa->mode & kMemColorProtMask);
+  }
+
+  out_data->payload = mdp_memcol;
 
 #endif
   return ret;
diff --git a/sdm/libs/core/drm/hw_color_manager_drm.h b/sdm/libs/core/drm/hw_color_manager_drm.h
index 290c606..1e77f6c 100644
--- a/sdm/libs/core/drm/hw_color_manager_drm.h
+++ b/sdm/libs/core/drm/hw_color_manager_drm.h
@@ -32,21 +32,55 @@
 
 #include <drm_interface.h>
 #include <private/color_params.h>
+#include <vector>
+#include <map>
 
 using sde_drm::DRMPPFeatureID;
 using sde_drm::DRMPPFeatureInfo;
 
+using sde_drm::kFeaturePcc;
+using sde_drm::kFeatureIgc;
+using sde_drm::kFeaturePgc;
+using sde_drm::kFeatureMixerGc;
+using sde_drm::kFeaturePaV2;
+using sde_drm::kFeatureDither;
+using sde_drm::kFeatureGamut;
+using sde_drm::kFeaturePADither;
+using sde_drm::kFeaturePAHsic;
+using sde_drm::kFeaturePASixZone;
+using sde_drm::kFeaturePAMemColSkin;
+using sde_drm::kFeaturePAMemColSky;
+using sde_drm::kFeaturePAMemColFoliage;
+using sde_drm::kFeaturePAMemColProt;
+using sde_drm::kPPFeaturesMax;
+
 namespace sdm {
 
+typedef std::map<uint32_t, std::vector<uint32_t>> DrmPPFeatureMap;
+
+static const DrmPPFeatureMap DrmPPfeatureMap_ = \
+  {{kGlobalColorFeaturePcc, {kFeaturePcc}},
+    {kGlobalColorFeatureIgc, {kFeatureIgc}},
+    {kGlobalColorFeaturePgc, {kFeaturePgc}},
+    {kMixerColorFeatureGc, {kMixerColorFeatureGc}},
+    {kGlobalColorFeaturePaV2, {kFeaturePAHsic, kFeaturePASixZone,
+                               kFeaturePAMemColSkin, kFeaturePAMemColSky,
+                               kFeaturePAMemColFoliage, kFeaturePAMemColProt}},
+    {kGlobalColorFeatureDither, {kFeatureDither}},
+    {kGlobalColorFeatureGamut, {kFeatureGamut}},
+    {kGlobalColorFeaturePADither, {kFeaturePADither}},
+};
+
 static const uint32_t kMaxPCCChanel = 3;
 
 class HWColorManagerDrm {
  public:
-  static DisplayError (*GetDrmFeature[kMaxNumPPFeatures])(const PPFeatureInfo &in_data,
+  static DisplayError (*GetDrmFeature[kPPFeaturesMax])(const PPFeatureInfo &in_data,
                                                           DRMPPFeatureInfo *out_data);
   static void FreeDrmFeatureData(DRMPPFeatureInfo *feature);
   static uint32_t GetFeatureVersion(const DRMPPFeatureInfo &feature);
   static DRMPPFeatureID ToDrmFeatureId(uint32_t id);
+
  protected:
   HWColorManagerDrm() {}
 
@@ -55,10 +89,16 @@
   static DisplayError GetDrmIGC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
   static DisplayError GetDrmPGC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
   static DisplayError GetDrmMixerGC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
-  static DisplayError GetDrmPAV2(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
   static DisplayError GetDrmDither(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
   static DisplayError GetDrmGamut(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
   static DisplayError GetDrmPADither(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
+  static DisplayError GetDrmPAHsic(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
+  static DisplayError GetDrmPASixZone(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
+  static DisplayError GetDrmPAMemColSkin(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
+  static DisplayError GetDrmPAMemColSky(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
+  static DisplayError GetDrmPAMemColFoliage(const PPFeatureInfo &in_data,
+                                            DRMPPFeatureInfo *out_data);
+  static DisplayError GetDrmPAMemColProt(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data);
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 345aeb2..9d0a6ad 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -329,8 +329,6 @@
                          HWInfoInterface *hw_info_intf)
     : hw_info_intf_(hw_info_intf), buffer_sync_handler_(buffer_sync_handler),
       registry_(buffer_allocator) {
-  disp_type_ = DRMDisplayType::PERIPHERAL;
-  device_name_ = "Peripheral Display";
   hw_info_intf_ = hw_info_intf;
 }
 
@@ -346,53 +344,53 @@
       DLOGE("RegisterDisplay failed for %s", device_name_);
       return kErrorResources;
     }
+
     drm_mgr_intf_->CreateAtomicReq(token_, &drm_atomic_intf_);
     drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
-    // Commit to setup pipeline with mode, which then tells us the topology etc
-    if (!deferred_initialize_) {
-      drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id,
-                                &connector_info_.modes[current_mode_index_]);
-      drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
-      if (drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes*/)) {
-        DRM_LOGI("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_);
-    }
-    InitializeConfigs();
   } else {
     display_attributes_.push_back(HWDisplayAttributes());
     PopulateDisplayAttributes(current_mode_index_);
   }
-  PopulateHWPanelInfo();
-  UpdateMixerAttributes();
 
   hw_info_intf_->GetHWResourceInfo(&hw_resource_);
-
   // TODO(user): In future, remove has_qseed3 member, add version and pass version to constructor
   if (hw_resource_.has_qseed3) {
     hw_scale_ = new HWScaleDRM(HWScaleDRM::Version::V2);
   }
-
   return kErrorNone;
 }
 
 DisplayError HWDeviceDRM::Deinit() {
-  PowerOff();
+  DisplayError err = kErrorNone;
+  drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, 0);
+  drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::OFF);
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, nullptr);
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
+  int ret = drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes */);
+  if (ret) {
+    DLOGE("Commit failed with error: %d", ret);
+    err = kErrorHardware;
+  }
+
   delete hw_scale_;
   registry_.Clear();
   display_attributes_ = {};
   drm_mgr_intf_->DestroyAtomicReq(drm_atomic_intf_);
   drm_atomic_intf_ = {};
   drm_mgr_intf_->UnregisterDisplay(token_);
-  return kErrorNone;
+  return err;
 }
 
 void HWDeviceDRM::InitializeConfigs() {
-  // TODO(user): Choose Best Mode
   current_mode_index_ = 0;
+  // Update current mode with preferred mode
+  for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+      if (connector_info_.modes[mode_index].type & DRM_MODE_TYPE_PREFERRED) {
+        current_mode_index_ = mode_index;
+        break;
+      }
+  }
+
   display_attributes_.resize(connector_info_.modes.size());
 
   uint32_t width = connector_info_.modes[current_mode_index_].hdisplay;
@@ -486,7 +484,12 @@
   snprintf(hw_panel_info_.panel_name, sizeof(hw_panel_info_.panel_name), "%s",
            connector_info_.panel_name.c_str());
 
-  UpdatePanelSplitInfo();
+  uint32_t index = current_mode_index_;
+  hw_panel_info_.split_info.left_split = display_attributes_[index].x_pixels;
+  if (display_attributes_[index].is_device_split) {
+    hw_panel_info_.split_info.left_split = hw_panel_info_.split_info.right_split =
+        display_attributes_[index].x_pixels / 2;
+  }
 
   hw_panel_info_.partial_update = connector_info_.num_roi;
   hw_panel_info_.left_roi_count = UINT32(connector_info_.num_roi);
@@ -499,8 +502,28 @@
   hw_panel_info_.min_roi_height = connector_info_.hmin;
   hw_panel_info_.needs_roi_merge = connector_info_.roi_merge;
   hw_panel_info_.dynamic_fps = connector_info_.dynamic_fps;
-  hw_panel_info_.min_fps = 60;
-  hw_panel_info_.max_fps = 60;
+  drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+  if (hw_panel_info_.dynamic_fps) {
+    uint32_t min_fps = current_mode.vrefresh;
+    uint32_t max_fps = current_mode.vrefresh;
+    for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+      if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+          (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay)) {
+        if (min_fps > connector_info_.modes[mode_index].vrefresh)  {
+          min_fps = connector_info_.modes[mode_index].vrefresh;
+        }
+        if (max_fps < connector_info_.modes[mode_index].vrefresh)  {
+          max_fps = connector_info_.modes[mode_index].vrefresh;
+        }
+      }
+    }
+    hw_panel_info_.min_fps = min_fps;
+    hw_panel_info_.max_fps = max_fps;
+  } else {
+    hw_panel_info_.min_fps = current_mode.vrefresh;
+    hw_panel_info_.max_fps = current_mode.vrefresh;
+  }
+
   hw_panel_info_.is_primary_panel = connector_info_.is_primary;
   hw_panel_info_.is_pluggable = 0;
   hw_panel_info_.hdr_enabled = connector_info_.panel_hdr_prop.hdr_enabled;
@@ -537,7 +560,7 @@
         hw_panel_info_.width_align, hw_panel_info_.top_align, hw_panel_info_.height_align);
   DLOGI("ROI: min_width = %d, min_height = %d, need_merge = %d", hw_panel_info_.min_roi_width,
         hw_panel_info_.min_roi_height, hw_panel_info_.needs_roi_merge);
-  DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
+  DLOGI("FPS: min = %d, max = %d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
   DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split,
         hw_panel_info_.split_info.right_split);
   DLOGI("Panel Transfer time = %d us", hw_panel_info_.transfer_time_us);
@@ -607,14 +630,22 @@
 }
 
 DisplayError HWDeviceDRM::GetActiveConfig(uint32_t *active_config) {
-  *active_config = current_mode_index_;
+  if (IsResolutionSwitchEnabled()) {
+    *active_config = current_mode_index_;
+  } else {
+    *active_config = 0;
+  }
   return kErrorNone;
 }
 
 DisplayError HWDeviceDRM::GetNumDisplayAttributes(uint32_t *count) {
-  *count = UINT32(display_attributes_.size());
-  if (*count <= 0) {
-    return kErrorHardware;
+  if (IsResolutionSwitchEnabled()) {
+    *count = UINT32(display_attributes_.size());
+    if (*count <= 0) {
+       return kErrorHardware;
+    }
+  } else {
+    *count = 1;
   }
   return kErrorNone;
 }
@@ -624,8 +655,11 @@
   if (index >= display_attributes_.size()) {
     return kErrorParameters;
   }
-
-  *display_attributes = display_attributes_[index];
+  if (IsResolutionSwitchEnabled()) {
+    *display_attributes = display_attributes_[index];
+  } else {
+    *display_attributes = display_attributes_[current_mode_index_];
+  }
   return kErrorNone;
 }
 
@@ -635,20 +669,21 @@
 }
 
 DisplayError HWDeviceDRM::SetDisplayAttributes(uint32_t index) {
-  if (index >= display_attributes_.size()) {
-    return kErrorParameters;
+  if (!IsResolutionSwitchEnabled()) {
+    return kErrorNotSupported;
   }
 
-  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &connector_info_.modes[index]);
-  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
-
+  if (index >= display_attributes_.size()) {
+    DLOGE("Invalid mode index %d mode size %d", index, UINT32(display_attributes_.size()));
+    return kErrorParameters;
+  }
   current_mode_index_ = index;
-  UpdatePanelSplitInfo();
+  // TODO(user): Topology/panel roi alignment information will be updated as a part of next commit
+  // which is too late for the requested mode that has different panel alignments. So driver needs
+  // to update panel/topology information for all modes during probe to reslove this issue.
+  PopulateHWPanelInfo();
   UpdateMixerAttributes();
-
-  DLOGI("Setting mode index %d for CRTC %d, Connector %d display %s is successful", index,
-         token_.crtc_id, token_.conn_id, device_name_);
-
+  switch_mode_ = true;
   return kErrorNone;
 }
 
@@ -674,6 +709,7 @@
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
+
   return kErrorNone;
 }
 
@@ -691,6 +727,7 @@
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
+
   return kErrorNone;
 }
 
@@ -735,6 +772,7 @@
   HWQosData &qos_data = hw_layers->qos_data;
   DRMSecurityLevel crtc_security_level = DRMSecurityLevel::SECURE_NON_SECURE;
   uint32_t index = current_mode_index_;
+  drmModeModeInfo current_mode = connector_info_.modes[index];
 
   solid_fills_.clear();
 
@@ -753,6 +791,8 @@
       crtc_rects[i].top = UINT32(roi.top);
       crtc_rects[i].bottom = UINT32(roi.bottom);
       // TODO(user): In Dest scaler + PU, populate from HWDestScaleInfo->panel_roi
+      // TODO(user): panel_roi need to be made as a vector in HWLayersInfo and
+      // needs to be removed from  HWDestScaleInfo.
       conn_rects[i].left = UINT32(roi.left);
       conn_rects[i].right = UINT32(roi.right);
       conn_rects[i].top = UINT32(roi.top);
@@ -834,7 +874,7 @@
         }
         if (hw_scale_) {
           SDEScaler scaler_output = {};
-          hw_scale_->SetPlaneScaler(pipe_info->scale_data, &scaler_output);
+          hw_scale_->SetScaler(pipe_info->scale_data, &scaler_output);
           // TODO(user): Remove qseed3 and add version check, then send appropriate scaler object
           if (hw_resource_.has_qseed3) {
             drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SCALER_CONFIG, pipe_id,
@@ -865,6 +905,27 @@
            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);
+
+  // Set refresh rate
+  if (vrefresh_) {
+    for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+      if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+          (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay) &&
+          (vrefresh_ == connector_info_.modes[mode_index].vrefresh)) {
+        current_mode = connector_info_.modes[mode_index];
+        break;
+      }
+    }
+  }
+  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 (!validate && (hw_layer_info.set_idle_time_ms >= 0)) {
+    DLOGI_IF(kTagDriverConfig, "Setting idle timeout to = %d ms",
+             hw_layer_info.set_idle_time_ms);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_IDLE_TIMEOUT, token_.crtc_id,
+                              hw_layer_info.set_idle_time_ms);
+  }
 }
 
 void HWDeviceDRM::AddSolidfillStage(const HWSolidfillStage &sf, uint32_t plane_alpha) {
@@ -909,7 +970,8 @@
 
   int ret = drm_atomic_intf_->Validate();
   if (ret) {
-    DLOGE("%s failed with error %d", __FUNCTION__, ret);
+    DLOGE("failed with error %d for %s", ret, device_name_);
+    vrefresh_ = 0;
     return kErrorHardware;
   }
 
@@ -989,6 +1051,7 @@
   int ret = drm_atomic_intf_->Commit(false /* synchronous */, false /* retain_planes*/);
   if (ret) {
     DLOGE("%s failed with error %d crtc %d", __FUNCTION__, ret, token_.crtc_id);
+    vrefresh_ = 0;
     return kErrorHardware;
   }
 
@@ -1014,6 +1077,27 @@
 
   hw_layer_info.sync_handle = release_fence;
 
+  if (vrefresh_) {
+    // Update current mode index if refresh rate is changed
+    drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+    for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+      if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+          (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay) &&
+          (vrefresh_ == connector_info_.modes[mode_index].vrefresh)) {
+        current_mode_index_ = mode_index;
+        break;
+      }
+    }
+    vrefresh_ = 0;
+  }
+
+  if (switch_mode_) {
+    // Reload connector info for updated info after 1st commit
+    drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+    PopulateHWPanelInfo();
+    switch_mode_ = false;
+  }
+
   return kErrorNone;
 }
 
@@ -1120,8 +1204,6 @@
   return true;
 }
 
-void HWDeviceDRM::ResetDisplayParams() {}
-
 DisplayError HWDeviceDRM::SetCursorPosition(HWLayers *hw_layers, int x, int y) {
   DTRACE_SCOPED();
   return kErrorNone;
@@ -1135,7 +1217,7 @@
     if (info.id >= sde_drm::kPPFeaturesMax)
       continue;
     // use crtc_id_ = 0 since PP features are same across all CRTCs
-    drm_mgr_intf_->GetCrtcPPInfo(0, info);
+    drm_mgr_intf_->GetCrtcPPInfo(0, &info);
     vers->version[i] = HWColorManagerDrm::GetFeatureVersion(info);
   }
   return kErrorNone;
@@ -1153,14 +1235,22 @@
 
     if (feature) {
       DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_);
-      if (!HWColorManagerDrm::GetDrmFeature[feature->feature_id_]) {
-        DLOGE("GetDrmFeature is not valid for feature %d", feature->feature_id_);
+      auto drm_features = DrmPPfeatureMap_.find(feature->feature_id_);
+      if (drm_features == DrmPPfeatureMap_.end()) {
+        DLOGE("DrmFeatures not valid for feature %d", feature->feature_id_);
         continue;
       }
-      ret = HWColorManagerDrm::GetDrmFeature[feature->feature_id_](*feature, &kernel_params);
-      if (!ret)
-        drm_atomic_intf_->Perform(DRMOps::CRTC_SET_POST_PROC, token_.crtc_id, &kernel_params);
-      HWColorManagerDrm::FreeDrmFeatureData(&kernel_params);
+
+      for (uint32_t drm_feature : drm_features->second) {
+        if (!HWColorManagerDrm::GetDrmFeature[drm_feature]) {
+          DLOGE("GetDrmFeature is not valid for DRM feature %d", drm_feature);
+          continue;
+        }
+        ret = HWColorManagerDrm::GetDrmFeature[drm_feature](*feature, &kernel_params);
+        if (!ret)
+          drm_atomic_intf_->Perform(DRMOps::CRTC_SET_POST_PROC, token_.crtc_id, &kernel_params);
+        HWColorManagerDrm::FreeDrmFeatureData(&kernel_params);
+      }
     }
   }
 
@@ -1174,13 +1264,26 @@
   return kErrorNotSupported;
 }
 
-void HWDeviceDRM::SetIdleTimeoutMs(uint32_t timeout_ms) {}
+void HWDeviceDRM::SetIdleTimeoutMs(uint32_t timeout_ms) {
+  // TODO(user): This function can be removed after fb is deprecated
+}
 
 DisplayError HWDeviceDRM::SetDisplayMode(const HWDisplayMode hw_display_mode) {
   return kErrorNotSupported;
 }
 
 DisplayError HWDeviceDRM::SetRefreshRate(uint32_t refresh_rate) {
+  // Check if requested refresh rate is valid
+  drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+  for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+    if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+        (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay) &&
+        (refresh_rate == connector_info_.modes[mode_index].vrefresh)) {
+      vrefresh_ = refresh_rate;
+      DLOGV_IF(kTagDriverConfig, "Set refresh rate to %d", refresh_rate);
+      return kErrorNone;
+    }
+  }
   return kErrorNotSupported;
 }
 
@@ -1343,12 +1446,6 @@
     return kErrorParameters;
   }
 
-  uint32_t index = current_mode_index_;
-  mixer_attributes_.width = display_attributes_[index].x_pixels;
-  mixer_attributes_.height = display_attributes_[index].y_pixels;
-  mixer_attributes_.split_left = display_attributes_[index].is_device_split
-                                     ? hw_panel_info_.split_info.left_split
-                                     : mixer_attributes_.width;
   *mixer_attributes = mixer_attributes_;
 
   return kErrorNone;
@@ -1367,6 +1464,7 @@
   mixer_attributes_.split_left = display_attributes_[index].is_device_split
                                      ? hw_panel_info_.split_info.left_split
                                      : mixer_attributes_.width;
+  DLOGI("Mixer WxH %dx%d for %s", mixer_attributes_.width, mixer_attributes_.height, device_name_);
 }
 
 void HWDeviceDRM::SetSecureConfig(const LayerBuffer &input_buffer, DRMSecureMode *fb_secure_mode,
@@ -1395,15 +1493,6 @@
   }
 }
 
-void HWDeviceDRM::UpdatePanelSplitInfo() {
-  uint32_t index = current_mode_index_;
-  hw_panel_info_.split_info.left_split = display_attributes_[index].x_pixels;
-  if (display_attributes_[index].is_device_split) {
-    hw_panel_info_.split_info.left_split = hw_panel_info_.split_info.right_split =
-        display_attributes_[index].x_pixels / 2;
-  }
-}
-
 void HWDeviceDRM::SetTopology(sde_drm::DRMTopology drm_topology, HWTopology *hw_topology) {
   switch (drm_topology) {
     case DRMTopology::SINGLE_LM:          *hw_topology = kSingleLM;        break;
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index cc17668..0a8b722 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -116,7 +116,6 @@
   void PopulateHWPanelInfo();
   void GetHWDisplayPortAndMode();
   void GetHWPanelMaxBrightness();
-  void ResetDisplayParams();
   bool EnableHotPlugDetection(int enable);
   void UpdateMixerAttributes();
   void SetSolidfillStages();
@@ -132,7 +131,6 @@
   void SetSecureConfig(const LayerBuffer &input_buffer, sde_drm::DRMSecureMode *fb_secure_mode,
                        sde_drm::DRMSecurityLevel *security_level);
   bool IsResolutionSwitchEnabled() const { return resolution_switch_enabled_; }
-  void UpdatePanelSplitInfo();
   void SetTopology(sde_drm::DRMTopology drm_topology, HWTopology *hw_topology);
 
   class Registry {
@@ -161,7 +159,6 @@
 
  protected:
   const char *device_name_ = {};
-  bool deferred_initialize_ = false;
   bool default_mode_ = false;
   sde_drm::DRMDisplayType disp_type_ = {};
   HWInfoInterface *hw_info_intf_ = {};
@@ -177,6 +174,7 @@
   std::vector<HWDisplayAttributes> display_attributes_ = {};
   uint32_t current_mode_index_ = 0;
   sde_drm::DRMConnectorInfo connector_info_ = {};
+  bool first_cycle_ = true;
 
  private:
   bool synchronous_commit_ = false;
@@ -184,6 +182,8 @@
   std::string interface_str_ = "DSI";
   std::vector<sde_drm::DRMSolidfillStage> solid_fills_ {};
   bool resolution_switch_enabled_ = false;
+  uint32_t vrefresh_ = 0;
+  bool switch_mode_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index 2816c5e..a90d294 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -40,6 +40,7 @@
 #include <utils/debug.h>
 #include <utils/sys.h>
 #include <xf86drm.h>
+#include <drm/msm_drm.h>
 
 #include <algorithm>
 #include <map>
@@ -86,13 +87,30 @@
         // Clear any existing data
         Sys::pread_(poll_fds_[i].fd, data, kMaxStringLength, 0);
       } break;
-      case HWEvent::IDLE_NOTIFY:
+      case HWEvent::IDLE_NOTIFY: {
+        poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
+        if (poll_fds_[i].fd < 0) {
+          DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
+          return kErrorResources;
+        }
+        poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
+        idle_notify_index_ = i;
+      } break;
       case HWEvent::CEC_READ_MESSAGE:
       case HWEvent::SHOW_BLANK_EVENT:
       case HWEvent::THERMAL_LEVEL:
       case HWEvent::IDLE_POWER_COLLAPSE:
       case HWEvent::PINGPONG_TIMEOUT:
         break;
+      case HWEvent::PANEL_DEAD: {
+        poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
+        if (poll_fds_[i].fd < 0) {
+          DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
+          return kErrorResources;
+        }
+        poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
+        panel_dead_index_ = i;
+      } break;
     }
   }
 
@@ -125,6 +143,9 @@
       case HWEvent::IDLE_POWER_COLLAPSE:
         event_data.event_parser = &HWEventsDRM::HandleIdlePowerCollapse;
         break;
+      case HWEvent::PANEL_DEAD:
+        event_data.event_parser = &HWEventsDRM::HandlePanelDead;
+        break;
       default:
         error = kErrorParameters;
         break;
@@ -169,11 +190,16 @@
     return kErrorResources;
   }
 
+  RegisterPanelDead(true);
+  RegisterIdleNotify(true);
+
   return kErrorNone;
 }
 
 DisplayError HWEventsDRM::Deinit() {
   exit_threads_ = true;
+  RegisterPanelDead(false);
+  RegisterIdleNotify(false);
   Sys::pthread_cancel_(event_thread_);
   WakeUpEventThread();
   pthread_join(event_thread_, NULL);
@@ -232,6 +258,10 @@
       case HWEvent::THERMAL_LEVEL:
       case HWEvent::IDLE_POWER_COLLAPSE:
         break;
+      case HWEvent::PANEL_DEAD:
+        drmClose(poll_fds_[i].fd);
+        poll_fds_[i].fd = -1;
+        break;
       default:
         return kErrorNotSupported;
     }
@@ -274,7 +304,9 @@
 
       switch (event_data_list_[i].event_type) {
         case HWEvent::VSYNC:
-          if (poll_fd.revents & (POLLIN | POLLPRI)) {
+        case HWEvent::PANEL_DEAD:
+        case HWEvent::IDLE_NOTIFY:
+          if (poll_fd.revents & (POLLIN | POLLPRI | POLLERR)) {
             (this->*(event_data_list_[i]).event_parser)(nullptr);
           }
           break;
@@ -284,7 +316,6 @@
             (this->*(event_data_list_[i]).event_parser)(data);
           }
           break;
-        case HWEvent::IDLE_NOTIFY:
         case HWEvent::CEC_READ_MESSAGE:
         case HWEvent::SHOW_BLANK_EVENT:
         case HWEvent::THERMAL_LEVEL:
@@ -321,6 +352,72 @@
   return kErrorNone;
 }
 
+DisplayError HWEventsDRM::RegisterPanelDead(bool enable) {
+  uint32_t i = 0;
+  for (; i < event_data_list_.size(); i++) {
+    if (event_data_list_[i].event_type == HWEvent::PANEL_DEAD) {
+      break;
+    }
+  }
+
+  if (i == event_data_list_.size()) {
+    DLOGI("panel dead is not supported event");
+    return kErrorNone;
+  }
+
+  struct drm_msm_event_req req = {};
+  int ret = 0;
+
+  req.object_id = token_.conn_id;
+  req.object_type = DRM_MODE_OBJECT_CONNECTOR;
+  req.event = DRM_EVENT_PANEL_DEAD;
+  if (enable) {
+    ret = drmIoctl(poll_fds_[panel_dead_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
+  } else {
+    ret = drmIoctl(poll_fds_[panel_dead_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
+  }
+
+  if (ret) {
+    DLOGE("register panel dead enable:%d failed", enable);
+    return kErrorResources;
+  }
+
+  return kErrorNone;
+}
+
+DisplayError HWEventsDRM::RegisterIdleNotify(bool enable) {
+  uint32_t i = 0;
+  for (; i < event_data_list_.size(); i++) {
+    if (event_data_list_[i].event_type == HWEvent::IDLE_NOTIFY) {
+      break;
+    }
+  }
+
+  if (i == event_data_list_.size()) {
+    DLOGI("idle notify is not supported event");
+    return kErrorNone;
+  }
+
+  struct drm_msm_event_req req = {};
+  int ret = 0;
+
+  req.object_id = token_.crtc_id;
+  req.object_type = DRM_MODE_OBJECT_CRTC;
+  req.event = DRM_EVENT_IDLE_NOTIFY;
+  if (enable) {
+    ret = drmIoctl(poll_fds_[idle_notify_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
+  } else {
+    ret = drmIoctl(poll_fds_[idle_notify_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
+  }
+
+  if (ret) {
+    DLOGE("register idle notify enable:%d failed", enable);
+    return kErrorResources;
+  }
+
+  return kErrorNone;
+}
+
 void HWEventsDRM::HandleVSync(char *data) {
   drmEventContext event = {};
   event.version = DRM_EVENT_CONTEXT_VERSION;
@@ -331,6 +428,47 @@
   }
 }
 
+void HWEventsDRM::HandlePanelDead(char *data) {
+  char event_data[kMaxStringLength] = {0};
+  int32_t size;
+  struct drm_msm_event_resp *event_resp = NULL;
+
+  size = (int32_t)Sys::pread_(poll_fds_[panel_dead_index_].fd, event_data, kMaxStringLength, 0);
+  if (size <= 0) {
+    return;
+  }
+
+  if (size > kMaxStringLength) {
+    DLOGE("event size %d is greater than event buffer size %zd\n", size, kMaxStringLength);
+    return;
+  }
+
+  if (size < (int32_t)sizeof(*event_resp)) {
+    DLOGE("Invalid event size %d expected %zd\n", size, sizeof(*event_resp));
+    return;
+  }
+
+  int32_t i = 0;
+  while (i < size) {
+    event_resp = (struct drm_msm_event_resp *)&event_data[i];
+    switch (event_resp->base.type) {
+      case DRM_EVENT_PANEL_DEAD:
+      {
+        DLOGI("Received panel dead event");
+        event_handler_->PanelDead();
+        break;
+      }
+      default: {
+        DLOGE("invalid event %d", event_resp->base.type);
+        break;
+      }
+    }
+    i += event_resp->base.length;
+  }
+
+  return;
+}
+
 void HWEventsDRM::VSyncHandlerCallback(int fd, unsigned int sequence, unsigned int tv_sec,
                                        unsigned int tv_usec, void *data) {
   int64_t timestamp = (int64_t)(tv_sec)*1000000000 + (int64_t)(tv_usec)*1000;
@@ -338,7 +476,45 @@
 }
 
 void HWEventsDRM::HandleIdleTimeout(char *data) {
-  event_handler_->IdleTimeout();
+  char event_data[kMaxStringLength];
+  int32_t size;
+  struct drm_msm_event_resp *event_resp = NULL;
+
+  size = (int32_t)Sys::pread_(poll_fds_[idle_notify_index_].fd, event_data, kMaxStringLength, 0);
+  if (size < 0) {
+    return;
+  }
+
+  if (size > kMaxStringLength) {
+    DLOGE("event size %d is greater than event buffer size %zd\n", size, kMaxStringLength);
+    return;
+  }
+
+  if (size < (int32_t)sizeof(*event_resp)) {
+    DLOGE("size %d exp %zd\n", size, sizeof(*event_resp));
+    return;
+  }
+
+  int32_t i = 0;
+
+  while (i < size) {
+    event_resp = (struct drm_msm_event_resp *)&event_data[i];
+    switch (event_resp->base.type) {
+      case DRM_EVENT_IDLE_NOTIFY:
+      {
+        DLOGV("Received Idle time event");
+        event_handler_->IdleTimeout();
+        break;
+      }
+      default: {
+        DLOGE("invalid event %d", event_resp->base.type);
+        break;
+      }
+    }
+    i += event_resp->base.length;
+  }
+
+  return;
 }
 
 void HWEventsDRM::HandleCECMessage(char *data) {
diff --git a/sdm/libs/core/drm/hw_events_drm.h b/sdm/libs/core/drm/hw_events_drm.h
index 1d04153..a7fb463 100644
--- a/sdm/libs/core/drm/hw_events_drm.h
+++ b/sdm/libs/core/drm/hw_events_drm.h
@@ -75,12 +75,15 @@
   void HandleThermal(char *data) {}
   void HandleBlank(char *data) {}
   void HandleIdlePowerCollapse(char *data);
+  void HandlePanelDead(char *data);
   void PopulateHWEventData(const vector<HWEvent> &event_list);
   void WakeUpEventThread();
   DisplayError SetEventParser();
   DisplayError InitializePollFd();
   DisplayError CloseFds();
   DisplayError RegisterVSync();
+  DisplayError RegisterPanelDead(bool enable);
+  DisplayError RegisterIdleNotify(bool enable);
 
   HWEventHandler *event_handler_{};
   vector<HWEventData> event_data_list_{};
@@ -90,8 +93,10 @@
   bool exit_threads_ = false;
   uint32_t vsync_index_ = 0;
   bool vsync_enabled_ = false;
+  uint32_t idle_notify_index_ = 0;
   sde_drm::DRMDisplayToken token_ = {};
   bool is_primary_ = false;
+  uint32_t panel_dead_index_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_info_drm.cpp b/sdm/libs/core/drm/hw_info_drm.cpp
index 1ce77b6..88e4efa 100644
--- a/sdm/libs/core/drm/hw_info_drm.cpp
+++ b/sdm/libs/core/drm/hw_info_drm.cpp
@@ -193,11 +193,11 @@
   hw_resource->has_concurrent_writeback = false;
   hw_resource->has_hdr = true;
 
-  hw_resource->hw_version = kHWMdssVersion5;
+  hw_resource->hw_version = SDEVERSION(4, 0, 1);
   hw_resource->hw_revision = 0;
 
   // TODO(user): Deprecate
-  hw_resource->max_mixer_width = 0;
+  hw_resource->max_mixer_width = 2560;
   hw_resource->writeback_index = 0;
   hw_resource->has_bwc = false;
   hw_resource->has_ubwc = true;
@@ -209,9 +209,15 @@
   GetHWPlanesInfo(hw_resource);
   GetWBInfo(hw_resource);
 
-  // Disable destination scalar count to 0 if extension library is not present
+  // Disable destination scalar count to 0 if extension library is not present or disabled
+  // through property
+  int value = 0;
+  bool disable_dest_scalar = false;
+  if (Debug::Get()->GetProperty("sdm.debug.disable_dest_scalar", &value) == kErrorNone) {
+    disable_dest_scalar = (value == 1);
+  }
   DynLib extension_lib;
-  if (!extension_lib.Open("libsdmextension.so")) {
+  if (!extension_lib.Open("libsdmextension.so") || disable_dest_scalar) {
     hw_resource->hw_dest_scalar_info.count = 0;
   }
 
@@ -236,7 +242,7 @@
   DLOGI("\tLinear = %d", hw_resource->linear_factor);
   DLOGI("\tScale = %d", hw_resource->scale_factor);
   DLOGI("\tFudge_factor = %d", hw_resource->extra_fudge_factor);
-  DLOGI("\tib_fudge_factor = %d", hw_resource->ib_fudge_factor);
+  DLOGI("\tib_fudge_factor = %f", hw_resource->ib_fudge_factor);
 
   if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) {
     GetHWRotatorInfo(hw_resource);
@@ -286,10 +292,7 @@
   hw_resource->max_bandwidth_low = info.max_bandwidth_low / kKiloUnit;
   hw_resource->max_bandwidth_high = info.max_bandwidth_high / kKiloUnit;
   hw_resource->max_sde_clk = info.max_sde_clk;
-  hw_resource->hw_revision = info.hw_version;
-  hw_resource->min_core_ib_kbps = info.min_core_ib / kKiloUnit;
-  hw_resource->min_llcc_ib_kbps = info.min_llcc_ib / kKiloUnit;
-  hw_resource->min_dram_ib_kbps = info.min_dram_ib / kKiloUnit;
+  hw_resource->hw_version = info.hw_version;
 
   std::vector<LayerBufferFormat> sdm_format;
   for (auto &it : info.comp_ratio_rt_map) {
@@ -305,6 +308,11 @@
     hw_resource->comp_ratio_rt_map.insert(std::make_pair(sdm_format[0], it.second));
     sdm_format.clear();
   }
+
+  hw_resource->hw_dest_scalar_info.count = info.dest_scaler_count;
+  hw_resource->hw_dest_scalar_info.max_scale_up = info.max_dest_scale_up;
+  hw_resource->hw_dest_scalar_info.max_input_width = info.max_dest_scaler_input_width;
+  hw_resource->hw_dest_scalar_info.max_output_width = info.max_dest_scaler_output_width;
 }
 
 void HWInfoDRM::GetHWPlanesInfo(HWResourceInfo *hw_resource) {
diff --git a/sdm/libs/core/drm/hw_info_drm.h b/sdm/libs/core/drm/hw_info_drm.h
index 7883592..82fb175 100644
--- a/sdm/libs/core/drm/hw_info_drm.h
+++ b/sdm/libs/core/drm/hw_info_drm.h
@@ -67,8 +67,6 @@
   sde_drm::DRMManagerInterface *drm_mgr_intf_ = {};
   bool default_mode_ = false;
 
-  // TODO(user): Read Mdss version from the driver
-  static const int kHWMdssVersion5 = 500;  // MDSS_V5
   static const int kMaxStringLength = 1024;
   static const int kKiloUnit = 1000;
 
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
new file mode 100644
index 0000000..92669e1
--- /dev/null
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -0,0 +1,170 @@
+/*
+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 <utils/debug.h>
+
+#include "hw_peripheral_drm.h"
+
+#define __CLASS__ "HWPeripheralDRM"
+
+using sde_drm::DRMDisplayType;
+using sde_drm::DRMOps;
+using sde_drm::DRMTopology;
+using sde_drm::DRMPowerMode;
+
+namespace sdm {
+
+HWPeripheralDRM::HWPeripheralDRM(BufferSyncHandler *buffer_sync_handler,
+                                 BufferAllocator *buffer_allocator,
+                                 HWInfoInterface *hw_info_intf)
+  : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
+  disp_type_ = DRMDisplayType::PERIPHERAL;
+  device_name_ = "Peripheral Display";
+}
+
+DisplayError HWPeripheralDRM::Init() {
+  DisplayError ret = HWDeviceDRM::Init();
+  if (ret != kErrorNone) {
+    DLOGE("Init failed for %s", device_name_);
+    return ret;
+  }
+
+  scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
+
+  if (connector_info_.topology == DRMTopology::UNKNOWN) {
+    connector_info_.topology = DRMTopology::DUAL_LM;
+  }
+
+  InitializeConfigs();
+  PopulateHWPanelInfo();
+  UpdateMixerAttributes();
+
+  return kErrorNone;
+}
+
+DisplayError HWPeripheralDRM::Validate(HWLayers *hw_layers) {
+  // Hijack the first validate to setup pipeline. This is a stopgap solution
+  HWLayersInfo &hw_layer_info = hw_layers->info;
+  if (first_cycle_) {
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, token_.crtc_id);
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id,
+                              &connector_info_.modes[current_mode_index_]);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
+    if (drm_atomic_intf_->Commit(true /* synchronous */, false /* retain pipes*/)) {
+      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_);
+    PopulateDisplayAttributes(current_mode_index_);
+    PopulateHWPanelInfo();
+    first_cycle_ = false;
+  }
+  SetDestScalarData(hw_layer_info);
+
+  return HWDeviceDRM::Validate(hw_layers);
+}
+
+DisplayError HWPeripheralDRM::Commit(HWLayers *hw_layers) {
+  HWLayersInfo &hw_layer_info = hw_layers->info;
+  SetDestScalarData(hw_layer_info);
+
+  return HWDeviceDRM::Commit(hw_layers);
+}
+
+DisplayError HWPeripheralDRM::PowerOn() {
+  if (first_cycle_) {
+    return kErrorNone;
+  }
+
+  return HWDeviceDRM::PowerOn();
+}
+
+void HWPeripheralDRM::ResetDisplayParams() {
+  sde_dest_scalar_data_ = {};
+  for (uint32_t j = 0; j < scalar_data_.size(); j++) {
+    scalar_data_[j] = {};
+  }
+}
+
+void HWPeripheralDRM::SetDestScalarData(HWLayersInfo hw_layer_info) {
+  if (!hw_resource_.hw_dest_scalar_info.count) {
+    return;
+  }
+
+  uint32_t index = 0;
+  for (uint32_t i = 0; i < hw_resource_.hw_dest_scalar_info.count; i++) {
+    DestScaleInfoMap::iterator it = hw_layer_info.dest_scale_info_map.find(i);
+
+    if (it == hw_layer_info.dest_scale_info_map.end()) {
+      continue;
+    }
+
+    HWDestScaleInfo *dest_scale_info = it->second;
+    SDEScaler *scale = &scalar_data_[index];
+    hw_scale_->SetScaler(dest_scale_info->scale_data, scale);
+    sde_drm_dest_scaler_cfg *dest_scalar_data = &sde_dest_scalar_data_.ds_cfg[index];
+    dest_scalar_data->flags = 0;
+    if (scale->scaler_v2.enable) {
+      dest_scalar_data->flags |= SDE_DRM_DESTSCALER_ENABLE;
+    }
+    if (scale->scaler_v2.de.enable) {
+      dest_scalar_data->flags |= SDE_DRM_DESTSCALER_ENHANCER_UPDATE;
+    }
+    if (dest_scale_info->scale_update) {
+      dest_scalar_data->flags |= SDE_DRM_DESTSCALER_SCALE_UPDATE;
+    }
+    dest_scalar_data->index = i;
+    dest_scalar_data->lm_width = dest_scale_info->mixer_width;
+    dest_scalar_data->lm_height = dest_scale_info->mixer_height;
+    dest_scalar_data->scaler_cfg = reinterpret_cast<uint64_t>(&scale->scaler_v2);
+    if (hw_panel_info_.partial_update) {
+      dest_scalar_data->flags |= SDE_DRM_DESTSCALER_PU_ENABLE;
+    }
+    index++;
+  }
+  sde_dest_scalar_data_.num_dest_scaler = UINT32(hw_layer_info.dest_scale_info_map.size());
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DEST_SCALER_CONFIG, token_.crtc_id,
+                            reinterpret_cast<uint64_t>(&sde_dest_scalar_data_));
+}
+
+DisplayError HWPeripheralDRM::Flush() {
+  DisplayError err = HWDeviceDRM::Flush();
+  if (err != kErrorNone) {
+    return err;
+  }
+
+  ResetDisplayParams();
+  return kErrorNone;
+}
+
+
+}  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.h b/sdm/libs/core/drm/hw_peripheral_drm.h
new file mode 100644
index 0000000..0b596ad
--- /dev/null
+++ b/sdm/libs/core/drm/hw_peripheral_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_PERIPHERAL_DRM_H__
+#define __HW_PERIPHERAL_DRM_H__
+
+#include <vector>
+#include "hw_device_drm.h"
+
+namespace sdm {
+
+class HWPeripheralDRM : public HWDeviceDRM {
+ public:
+  explicit HWPeripheralDRM(BufferSyncHandler *buffer_sync_handler,
+                           BufferAllocator *buffer_allocator,
+                           HWInfoInterface *hw_info_intf);
+  virtual ~HWPeripheralDRM() {}
+
+ protected:
+  virtual DisplayError Init();
+  virtual DisplayError Validate(HWLayers *hw_layers);
+  virtual DisplayError Commit(HWLayers *hw_layers);
+  virtual DisplayError PowerOn();
+  virtual DisplayError Flush();
+ private:
+  void SetDestScalarData(HWLayersInfo hw_layer_info);
+  void ResetDisplayParams();
+  sde_drm_dest_scaler_data sde_dest_scalar_data_ = {};
+  std::vector<SDEScaler> scalar_data_ = {};
+};
+
+}  // namespace sdm
+
+#endif  // __HW_PERIPHERAL_DRM_H__
diff --git a/sdm/libs/core/drm/hw_scale_drm.cpp b/sdm/libs/core/drm/hw_scale_drm.cpp
index de0ccb2..b2f6d3b 100644
--- a/sdm/libs/core/drm/hw_scale_drm.cpp
+++ b/sdm/libs/core/drm/hw_scale_drm.cpp
@@ -66,19 +66,24 @@
   }
 }
 
-void HWScaleDRM::SetPlaneScaler(const HWScaleData &scale_data, SDEScaler *scaler) {
+void HWScaleDRM::SetScaler(const HWScaleData &scale_data, SDEScaler *scaler) {
   if (version_ == Version::V2) {
-    SetPlaneScalerV2(scale_data, &scaler->scaler_v2);
+    SetScalerV2(scale_data, &scaler->scaler_v2);
   }
 }
 
-void HWScaleDRM::SetPlaneScalerV2(const HWScaleData &scale_data, sde_drm_scaler_v2 *scaler) {
+void HWScaleDRM::SetScalerV2(const HWScaleData &scale_data, sde_drm_scaler_v2 *scaler) {
   if (!scale_data.enable.scale && !scale_data.enable.direction_detection &&
       !scale_data.enable.detail_enhance) {
+    scaler->enable = 0;
+    scaler->dir_en = 0;
+    scaler->de.enable = 0;
     return;
   }
 
-  scaler->enable = scale_data.enable.scale;
+  scaler->enable = scale_data.enable.scale | scale_data.enable.direction_detection |
+                   scale_data.detail_enhance.enable;
+
   scaler->dir_en = scale_data.enable.direction_detection;
   scaler->de.enable = scale_data.detail_enhance.enable;
 
@@ -132,7 +137,6 @@
   scaler->y_rgb_sep_lut_idx = scale_data.y_rgb_sep_lut_idx;
   scaler->uv_sep_lut_idx = scale_data.uv_sep_lut_idx;
 
-  /* TODO(user): Uncomment when de support is added
   if (scaler->de.enable) {
     sde_drm_de_v1 *det_enhance = &scaler->de;
     det_enhance->sharpen_level1 = scale_data.detail_enhance.sharpen_level1;
@@ -151,7 +155,6 @@
       det_enhance->adjust_c[i] = scale_data.detail_enhance.adjust_c[i];
     }
   }
-  */
 
   return;
 }
diff --git a/sdm/libs/core/drm/hw_scale_drm.h b/sdm/libs/core/drm/hw_scale_drm.h
index 8a4be70..6f96eca 100644
--- a/sdm/libs/core/drm/hw_scale_drm.h
+++ b/sdm/libs/core/drm/hw_scale_drm.h
@@ -50,11 +50,10 @@
  public:
   enum class Version { V2 };
   explicit HWScaleDRM(Version v) : version_(v) {}
-  void SetPlaneScaler(const HWScaleData &scale, SDEScaler *scaler);
+  void SetScaler(const HWScaleData &scale, SDEScaler *scaler);
 
  private:
-  void SetPlaneScalerV2(const HWScaleData &scale, sde_drm_scaler_v2 *scaler_v2);
-
+  void SetScalerV2(const HWScaleData &scale, sde_drm_scaler_v2 *scaler_v2);
   Version version_ = Version::V2;
 };
 
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index bd9ddc2..1eef1e8 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -67,35 +67,14 @@
   device_name_ = "TV Display Device";
 }
 
-// TODO(user) : split function in base class and avoid code duplicacy
-// by using base implementation for this basic stuff
 DisplayError HWTVDRM::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();
+  DisplayError error = HWDeviceDRM::Init();
+  if (error != kErrorNone) {
+    DLOGE("Init failed for %s", device_name_);
+    return error;
   }
 
-  hw_info_intf_->GetHWResourceInfo(&hw_resource_);
-
-  // TODO(user): In future, remove has_qseed3 member, add version and pass version to constructor
-  if (hw_resource_.has_qseed3) {
-    hw_scale_ = new HWScaleDRM(HWScaleDRM::Version::V2);
-  }
+  InitializeConfigs();
 
   return error;
 }
@@ -106,6 +85,10 @@
     return kErrorNotSupported;
   }
 
+  if (first_cycle_) {
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, token_.crtc_id);
+  }
+
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &connector_info_.modes[index]);
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
 
@@ -116,15 +99,16 @@
     return kErrorResources;
   }
 
-  // Reload connector info for updated info after 1st commit and validate
+  DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_);
+  first_cycle_ = false;
+
+  // Reload connector info for updated info after 1st commit
   drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
   if (index >= connector_info_.modes.size()) {
     DLOGE("Invalid mode index %d mode size %d", index, UINT32(connector_info_.modes.size()));
     return kErrorNotSupported;
   }
 
-  DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_);
-
   current_mode_index_ = index;
   PopulateDisplayAttributes(index);
   PopulateHWPanelInfo();
@@ -167,13 +151,6 @@
   return kErrorNone;
 }
 
-/* overriding display state funcs to have special or NO OP implementation for TVs */
-DisplayError HWTVDRM::Deinit() {
-  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
-
-  return HWDeviceDRM::Deinit();
-}
-
 DisplayError HWTVDRM::PowerOff() {
   DTRACE_SCOPED();
 
diff --git a/sdm/libs/core/drm/hw_tv_drm.h b/sdm/libs/core/drm/hw_tv_drm.h
index 985499e..ff07ac2 100644
--- a/sdm/libs/core/drm/hw_tv_drm.h
+++ b/sdm/libs/core/drm/hw_tv_drm.h
@@ -41,7 +41,6 @@
 
  protected:
   virtual DisplayError Init();
-  virtual DisplayError Deinit();
   virtual DisplayError SetDisplayAttributes(uint32_t index);
   virtual DisplayError GetConfigIndex(char *mode, uint32_t *index);
   virtual DisplayError PowerOff();
diff --git a/sdm/libs/core/drm/hw_virtual_drm.cpp b/sdm/libs/core/drm/hw_virtual_drm.cpp
index 7c7e348..626beea 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.cpp
+++ b/sdm/libs/core/drm/hw_virtual_drm.cpp
@@ -31,6 +31,8 @@
 #include <ctype.h>
 #include <drm_logger.h>
 #include <utils/debug.h>
+#include <algorithm>
+#include <vector>
 #include "hw_device_drm.h"
 #include "hw_virtual_drm.h"
 #include "hw_info_drm.h"
@@ -49,24 +51,28 @@
                            BufferAllocator *buffer_allocator,
                            HWInfoInterface *hw_info_intf)
                            : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
-  HWDeviceDRM::deferred_initialize_ = true;
   HWDeviceDRM::device_name_ = "Virtual Display Device";
-  HWDeviceDRM::hw_info_intf_ = hw_info_intf;
   HWDeviceDRM::disp_type_ = DRMDisplayType::VIRTUAL;
 }
 
 DisplayError HWVirtualDRM::Init() {
-  display_attributes_.push_back(HWDisplayAttributes());
-  return kErrorNone;
-}
-
-DisplayError HWVirtualDRM::DeferredInit() {
-  if (HWDeviceDRM::Init() != kErrorNone)
-    return kErrorResources;
-
-  drm_mgr_intf_->SetScalerLUT(drm_lut_info_);
-  DLOGI_IF(kTagDriverConfig, "Setup CRTC %d, Connector %d for %s",
-            token_.crtc_id, token_.conn_id, device_name_);
+  DisplayError err = HWDeviceDRM::Init();
+  if (err != kErrorNone) {
+    return err;
+  }
+  // TODO(user): Remove this code once driver populates appropriate topology based on virtual
+  // display configuration
+  if (connector_info_.topology == sde_drm::DRMTopology::UNKNOWN) {
+    uint32_t max_width = 0;
+    for (uint32_t i = 0; i < (uint32_t)connector_info_.modes.size(); i++) {
+      max_width = std::max(max_width, UINT32(connector_info_.modes[i].hdisplay));
+    }
+    connector_info_.topology = sde_drm::DRMTopology::SINGLE_LM;
+    if (max_width > hw_resource_.max_mixer_width) {
+      connector_info_.topology = sde_drm::DRMTopology::DUAL_LM_MERGE;
+    }
+  }
+  InitializeConfigs();
 
   return kErrorNone;
 }
@@ -79,9 +85,9 @@
 void HWVirtualDRM::ConfigureWbConnectorDestRect() {
   DRMRect dst = {};
   dst.left = 0;
-  dst.bottom = height_;
+  dst.bottom = display_attributes_[current_mode_index_].y_pixels;
   dst.top = 0;
-  dst.right = width_;
+  dst.right = display_attributes_[current_mode_index_].x_pixels;
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_OUTPUT_RECT, token_.conn_id, dst);
   return;
 }
@@ -92,51 +98,66 @@
 }
 
 void HWVirtualDRM::InitializeConfigs() {
-  drmModeModeInfo mode = {};
-  mode.hdisplay = mode.hsync_start = mode.hsync_end = mode.htotal = (uint16_t) width_;
-  mode.vdisplay = mode.vsync_start = mode.vsync_end = mode.vtotal = (uint16_t) height_;
-  // Not sure SF has a way to configure refresh rate. Hardcoding to 60 fps for now.
-  // TODO(user): Make this configurable.
-  mode.vrefresh = 60;
-  mode.clock = (mode.htotal * mode.vtotal * mode.vrefresh) / 1000;
-
-  struct sde_drm_wb_cfg wb_cfg;
-  wb_cfg.connector_id = token_.conn_id;
-  wb_cfg.flags |= SDE_DRM_WB_CFG_FLAGS_CONNECTED;
-  wb_cfg.count_modes = 1;
-  wb_cfg.modes = (uint64_t)&mode;
-  #ifdef DRM_IOCTL_SDE_WB_CONFIG
-  int ret = drmIoctl(dev_fd_, DRM_IOCTL_SDE_WB_CONFIG, &wb_cfg);
-  #endif
-  if (ret) {
-    DLOGE("WB config failed\n");
-  } else {
-    drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
-    DumpConfigs();
+  display_attributes_.resize(connector_info_.modes.size());
+  for (uint32_t i = 0; i < connector_info_.modes.size(); i++) {
+    PopulateDisplayAttributes(i);
   }
-
-  // TODO(user): Remove this code once driver populates appropriate topology based on virtual
-  // display configuration
-  if (connector_info_.topology == sde_drm::DRMTopology::UNKNOWN) {
-    connector_info_.topology = sde_drm::DRMTopology::SINGLE_LM;
-    if (width_ > hw_resource_.max_mixer_width) {
-      connector_info_.topology = sde_drm::DRMTopology::DUAL_LM_MERGE;
-    }
-  }
-  PopulateDisplayAttributes(current_mode_index_);
 }
 
-void HWVirtualDRM::DumpConfigs() {
+DisplayError HWVirtualDRM::SetWbConfigs(const HWDisplayAttributes &display_attributes) {
+  int ret = -EINVAL;
+  int mode_index = -1;
+  // Add new connector mode to the list
+  drmModeModeInfo mode = {};
+  mode.hdisplay = mode.hsync_start = mode.hsync_end = mode.htotal =
+                                       UINT16(display_attributes.x_pixels);
+  mode.vdisplay = mode.vsync_start = mode.vsync_end = mode.vtotal =
+                                       UINT16(display_attributes.y_pixels);
+  mode.vrefresh = UINT32(display_attributes.fps);
+  mode.clock = (mode.htotal * mode.vtotal * mode.vrefresh) / 1000;
+  connector_info_.modes.push_back(mode);
+
+  // Inform the updated mode list to the driver
+  struct sde_drm_wb_cfg wb_cfg = {};
+  wb_cfg.connector_id = token_.conn_id;
+  wb_cfg.flags = SDE_DRM_WB_CFG_FLAGS_CONNECTED;
+  wb_cfg.count_modes = UINT32(connector_info_.modes.size());
+  wb_cfg.modes = (uint64_t)connector_info_.modes.data();
+#ifdef DRM_IOCTL_SDE_WB_CONFIG
+  ret = drmIoctl(dev_fd_, DRM_IOCTL_SDE_WB_CONFIG, &wb_cfg);
+#endif
+  if (ret) {
+    DLOGE("Dump WBConfig: mode_count %d flags %x", wb_cfg.count_modes, wb_cfg.flags);
+    DumpConnectorModeInfo();
+    return kErrorHardware;
+  }
+  // Reload connector info for updated info after null commit
+  drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+  InitializeConfigs();
+
+  GetModeIndex(display_attributes, &mode_index);
+  if (mode_index < 0) {
+    DLOGE("Mode not found for resolution %dx%d fps %d", display_attributes.x_pixels,
+          display_attributes.y_pixels, UINT32(display_attributes.fps));
+    DumpConnectorModeInfo();
+    return kErrorNotSupported;
+  }
+  current_mode_index_ = UINT32(mode_index);
+
+  DumpConnectorModeInfo();
+
+  return kErrorNone;
+}
+
+void HWVirtualDRM::DumpConnectorModeInfo() {
   for (uint32_t i = 0; i < (uint32_t)connector_info_.modes.size(); i++) {
-  DLOGI(
-    "Name: %s\tvref: %d\thdisp: %d\t hsync_s: %d\thsync_e:%d\thtotal: %d\t"
-    "vdisp: %d\tvsync_s: %d\tvsync_e: %d\tvtotal: %d\n",
-    connector_info_.modes[i].name, connector_info_.modes[i].vrefresh,
-    connector_info_.modes[i].hdisplay,
-    connector_info_.modes[i].hsync_start, connector_info_.modes[i].hsync_end,
-    connector_info_.modes[i].htotal, connector_info_.modes[i].vdisplay,
-    connector_info_.modes[i].vsync_start, connector_info_.modes[i].vsync_end,
-    connector_info_.modes[i].vtotal);
+    DLOGI("Mode[%d]: Name: %s\tvref: %d\thdisp: %d\t hsync_s: %d\thsync_e:%d\thtotal: %d\t" \
+          "vdisp: %d\tvsync_s: %d\tvsync_e: %d\tvtotal: %d\n", i, connector_info_.modes[i].name,
+          connector_info_.modes[i].vrefresh, connector_info_.modes[i].hdisplay,
+          connector_info_.modes[i].hsync_start, connector_info_.modes[i].hsync_end,
+          connector_info_.modes[i].htotal, connector_info_.modes[i].vdisplay,
+          connector_info_.modes[i].vsync_start, connector_info_.modes[i].vsync_end,
+          connector_info_.modes[i].vtotal);
   }
 }
 
@@ -144,6 +165,12 @@
   LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
   DisplayError err = kErrorNone;
 
+  if (first_cycle_) {
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, token_.crtc_id);
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
+    first_cycle_ = false;
+  }
+
   registry_.RegisterCurrent(hw_layers);
   registry_.MapBufferToFbId(output_buffer);
   uint32_t fb_id = registry_.GetFbId(output_buffer->planes[0].fd);
@@ -153,13 +180,30 @@
   ConfigureWbConnectorSecureMode(output_buffer->flags.secure);
 
   err = HWDeviceDRM::AtomicCommit(hw_layers);
+  if (err != kErrorNone) {
+    DLOGE("Atomic commit failed for crtc_id %d conn_id %d", token_.crtc_id, token_.conn_id);
+  }
   registry_.UnregisterNext();
+
   return(err);
 }
 
 DisplayError HWVirtualDRM::Validate(HWLayers *hw_layers) {
-  // TODO(user) : Add validate support
-  return kErrorNone;
+  LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
+
+  if (first_cycle_) {
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, token_.crtc_id);
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
+  }
+
+  registry_.MapBufferToFbId(output_buffer);
+  uint32_t fb_id = registry_.GetFbId(output_buffer->planes[0].fd);
+
+  ConfigureWbConnectorFbId(fb_id);
+  ConfigureWbConnectorDestRect();
+  ConfigureWbConnectorSecureMode(output_buffer->flags.secure);
+
+  return HWDeviceDRM::Validate(hw_layers);
 }
 
 DisplayError HWVirtualDRM::SetDisplayAttributes(const HWDisplayAttributes &display_attributes) {
@@ -167,57 +211,46 @@
     return kErrorParameters;
   }
 
-  uint32_t index = current_mode_index_;
-  width_ = display_attributes.x_pixels;
-  height_ = display_attributes.y_pixels;
-
-  DisplayError error = DeferredInit();
-  if (error != kErrorNone) {
-    width_ = display_attributes_[index].x_pixels;
-    height_ = display_attributes_[index].y_pixels;
-    return error;
+  int mode_index = -1;
+  GetModeIndex(display_attributes, &mode_index);
+  if (mode_index < 0) {
+    DisplayError error = SetWbConfigs(display_attributes);
+    if (error != kErrorNone) {
+      return error;
+    }
+  } else {
+    current_mode_index_ = UINT32(mode_index);
   }
-  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &connector_info_.modes[index]);
-  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
-
-  display_attributes_[index] = display_attributes;
-  if (display_attributes_[index].x_pixels > hw_resource_.max_mixer_width) {
-    display_attributes_[index].is_device_split = true;
-  }
+  PopulateHWPanelInfo();
   UpdateMixerAttributes();
 
+  DLOGI("New WB Resolution: %dx%d cur_mode_index %d", display_attributes.x_pixels,
+        display_attributes.y_pixels, current_mode_index_);
   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;
-}
+  if (first_cycle_) {
+    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;
+  return HWDeviceDRM::PowerOn();
 }
 
 DisplayError HWVirtualDRM::GetPPFeaturesVersion(PPFeatureVersion *vers) {
   return kErrorNone;
 }
 
-DisplayError HWVirtualDRM::SetScaleLutConfig(HWScaleLutInfo *lut_info) {
-  drm_lut_info_.cir_lut = lut_info->cir_lut;
-  drm_lut_info_.dir_lut = lut_info->dir_lut;
-  drm_lut_info_.sep_lut = lut_info->sep_lut;
-  drm_lut_info_.cir_lut_size = lut_info->cir_lut_size;
-  drm_lut_info_.dir_lut_size = lut_info->dir_lut_size;
-  drm_lut_info_.sep_lut_size = lut_info->sep_lut_size;
-
-  // Due to differed Init in WB case, we cannot set scaler config immediately as we
-  // won't have SDE DRM initialized at this point. Hence have to cache LUT info here
-  // and set it in ::DeferredInit
-
-  return kErrorNone;
+void HWVirtualDRM::GetModeIndex(const HWDisplayAttributes &display_attributes, int *mode_index) {
+  *mode_index = -1;
+  for (uint32_t i = 0; i < connector_info_.modes.size(); i++) {
+    if (display_attributes.x_pixels == connector_info_.modes[i].hdisplay &&
+        display_attributes.y_pixels == connector_info_.modes[i].vdisplay &&
+        display_attributes.fps == connector_info_.modes[i].vrefresh) {
+      *mode_index = INT32(i);
+      break;
+    }
+  }
 }
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_virtual_drm.h b/sdm/libs/core/drm/hw_virtual_drm.h
index 7fa6c54..53e5b56 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.h
+++ b/sdm/libs/core/drm/hw_virtual_drm.h
@@ -33,6 +33,7 @@
 #include "hw_device_drm.h"
 #include <drm/msm_drm.h>
 #include <drm/sde_drm.h>
+#include <vector>
 
 namespace sdm {
 
@@ -46,26 +47,22 @@
     return kErrorNotSupported;
   }
   virtual DisplayError SetDisplayAttributes(const HWDisplayAttributes &display_attributes);
+  virtual DisplayError PowerOn();
 
  protected:
   virtual DisplayError Init();
   virtual DisplayError Validate(HWLayers *hw_layers);
-  virtual DisplayError DeferredInit();
-  virtual void InitializeConfigs();
   virtual DisplayError Commit(HWLayers *hw_layers);
   virtual DisplayError GetPPFeaturesVersion(PPFeatureVersion *vers);
-  virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info);
-  virtual DisplayError PowerOn();
-  virtual DisplayError PowerOff();
+
+ private:
   void ConfigureWbConnectorFbId(uint32_t fb_id);
   void ConfigureWbConnectorDestRect();
   void ConfigureWbConnectorSecureMode(bool secure);
-  void DumpConfigs();
-
- private:
-  uint32_t width_ = 0;
-  uint32_t height_ = 0;
-  sde_drm::DRMScalerLUTInfo drm_lut_info_ = {};
+  void InitializeConfigs();
+  void DumpConnectorModeInfo();
+  DisplayError SetWbConfigs(const HWDisplayAttributes &display_attributes);
+  void GetModeIndex(const HWDisplayAttributes &display_attributes, int *mode_index);
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/hw_events_interface.h b/sdm/libs/core/hw_events_interface.h
index 090ff71..828dcda 100644
--- a/sdm/libs/core/hw_events_interface.h
+++ b/sdm/libs/core/hw_events_interface.h
@@ -44,6 +44,7 @@
   THERMAL_LEVEL,
   IDLE_POWER_COLLAPSE,
   PINGPONG_TIMEOUT,
+  PANEL_DEAD,
 };
 
 class HWEventsInterface {
diff --git a/sdm/libs/core/hw_interface.cpp b/sdm/libs/core/hw_interface.cpp
index 2d8d41e..902dcbc 100644
--- a/sdm/libs/core/hw_interface.cpp
+++ b/sdm/libs/core/hw_interface.cpp
@@ -35,7 +35,7 @@
 #include "fb/hw_primary.h"
 #include "fb/hw_hdmi.h"
 #include "fb/hw_virtual.h"
-#include "drm/hw_device_drm.h"
+#include "drm/hw_peripheral_drm.h"
 #include "drm/hw_virtual_drm.h"
 #include "drm/hw_tv_drm.h"
 
@@ -55,7 +55,7 @@
       if (driver_type == DriverType::FB) {
         hw = new HWPrimary(buffer_sync_handler, hw_info_intf);
       } else {
-        hw = new HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
+        hw = new HWPeripheralDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
       }
       break;
     case kHDMI:
diff --git a/sdm/libs/core/hw_interface.h b/sdm/libs/core/hw_interface.h
index 6774159..9bb825e 100644
--- a/sdm/libs/core/hw_interface.h
+++ b/sdm/libs/core/hw_interface.h
@@ -62,6 +62,7 @@
   virtual void CECMessage(char *message) = 0;
   virtual void IdlePowerCollapse() = 0;
   virtual void PingPongTimeout() = 0;
+  virtual void PanelDead() = 0;
 
  protected:
   virtual ~HWEventHandler() { }
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index b451d2c..9db57ab 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -36,7 +36,8 @@
                                  hwc_tonemapper.cpp \
                                  display_null.cpp \
                                  hwc_socket_handler.cpp \
-                                 hwc_buffer_allocator.cpp
+                                 hwc_buffer_allocator.cpp \
+                                 hwc_display_external_test.cpp
 
 ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY), true)
     LOCAL_CFLAGS += -DFEATURE_WIDE_COLOR
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
index fa88c28..cde9991 100644
--- a/sdm/libs/hwc2/display_null.h
+++ b/sdm/libs/hwc2/display_null.h
@@ -95,6 +95,8 @@
   MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &))
   MAKE_NO_OP(GetDisplayPort(DisplayPort *))
   MAKE_NO_OP(SetCompositionState(LayerComposition, bool))
+  MAKE_NO_OP(GetClientTargetSupport(uint32_t, uint32_t, LayerBufferFormat,
+                                    const ColorMetaData &))
 
  private:
   bool active_ = false;
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
index 62b64be..e41a267 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
@@ -77,6 +77,8 @@
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_SET_PRODUCER_USAGE));
   LockBuffer_ = reinterpret_cast<GRALLOC1_PFN_LOCK>(
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_LOCK));
+  UnlockBuffer_ = reinterpret_cast<GRALLOC1_PFN_UNLOCK>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_UNLOCK));
   Perform_ = reinterpret_cast<GRALLOC1_PFN_PERFORM>(
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_PERFORM));
 
@@ -165,6 +167,8 @@
   hnd = (private_handle_t *)buf;  // NOLINT
   alloc_buffer_info->fd = hnd->fd;
   alloc_buffer_info->stride = UINT32(hnd->width);
+  alloc_buffer_info->aligned_width = UINT32(hnd->width);
+  alloc_buffer_info->aligned_height = UINT32(hnd->height);
   alloc_buffer_info->size = hnd->size;
 
   buffer_info->private_data = reinterpret_cast<void *>(hnd);
@@ -442,4 +446,8 @@
   return kErrorNone;
 }
 
+DisplayError HWCBufferAllocator::UnmapBuffer(const private_handle_t *handle, int* release_fence) {
+  return (DisplayError)(UnlockBuffer_(gralloc_device_, handle, release_fence));
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.h b/sdm/libs/hwc2/hwc_buffer_allocator.h
index 8a73ccb..7df88a4 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.h
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.h
@@ -61,6 +61,7 @@
                                uint32_t *num_planes);
   int SetBufferInfo(LayerBufferFormat format, int *target, uint64_t *flags);
   DisplayError MapBuffer(const private_handle_t *handle, int acquire_fence);
+  DisplayError UnmapBuffer(const private_handle_t *handle, int* release_fence);
 
  private:
   gralloc1_device_t *gralloc_device_ = nullptr;
@@ -74,6 +75,7 @@
   GRALLOC1_PFN_SET_CONSUMER_USAGE SetConsumerUsage_ = nullptr;
   GRALLOC1_PFN_SET_PRODUCER_USAGE SetProducerUsage_ = nullptr;
   GRALLOC1_PFN_LOCK LockBuffer_ = nullptr;
+  GRALLOC1_PFN_UNLOCK UnlockBuffer_ = nullptr;
   GRALLOC1_PFN_PERFORM Perform_ = nullptr;
 };
 
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 9c8ae07..fb077bb 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -54,8 +54,6 @@
 
 namespace sdm {
 
-std::bitset<kDisplayMax> HWCDisplay::validated_ = 0;
-
 // This weight function is needed because the color primaries are not sorted by gamut size
 static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) {
   int weight = 10;
@@ -96,11 +94,12 @@
 HWC2::Error HWCColorMode::GetColorModes(uint32_t *out_num_modes,
                                         android_color_mode_t *out_modes) {
   auto it = color_mode_transform_map_.begin();
-  for (auto i = 0; it != color_mode_transform_map_.end(); it++, i++) {
+  *out_num_modes = std::min(*out_num_modes, UINT32(color_mode_transform_map_.size()));
+  for (uint32_t i = 0; i < *out_num_modes; it++, i++) {
     out_modes[i] = it->first;
     DLOGI("Supports color mode[%d] = %d", i, it->first);
   }
-  *out_num_modes = UINT32(color_mode_transform_map_.size());
+
   return HWC2::Error::None;
 }
 
@@ -357,7 +356,7 @@
     return -EINVAL;
   }
 
-  validated_.reset();
+  validated_ = false;
   HWCDebugHandler::Get()->GetProperty("sys.hwc_disable_hdr", &disable_hdr_handling_);
   if (disable_hdr_handling_) {
     DLOGI("HDR Handling disabled");
@@ -420,7 +419,7 @@
   layer_map_.emplace(std::make_pair(layer->GetId(), layer));
   *out_layer_id = layer->GetId();
   geometry_changes_ |= GeometryChanges::kAdded;
-  validated_.reset();
+  validated_ = false;
   return HWC2::Error::None;
 }
 
@@ -452,7 +451,7 @@
   }
 
   geometry_changes_ |= GeometryChanges::kRemoved;
-  validated_.reset();
+  validated_ = false;
   return HWC2::Error::None;
 }
 
@@ -596,6 +595,7 @@
   layer_stack_.flags.geometry_changed = UINT32(geometry_changes_ > 0);
   // Append client target to the layer stack
   Layer *sdm_client_target = client_target_->GetSDMLayer();
+  sdm_client_target->flags.updating = IsLayerUpdating(sdm_client_target);
   layer_stack_.layers.push_back(sdm_client_target);
   // fall back frame composition to GPU when client target is 10bit
   // TODO(user): clarify the behaviour from Client(SF) and SDM Extn -
@@ -718,7 +718,7 @@
 
   ATRACE_INT("SetPowerMode ", state);
   DisplayError error = display_intf_->SetDisplayState(state);
-  validated_.reset();
+  validated_ = false;
 
   if (error == kErrorNone) {
     flush_on_error_ = flush_on_error;
@@ -736,48 +736,43 @@
 
 HWC2::Error HWCDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format,
                                                int32_t dataspace) {
-  DisplayConfigVariableInfo variable_config;
-  HWC2::Error supported = HWC2::Error::None;
-  display_intf_->GetFrameBufferConfig(&variable_config);
-  if (format != HAL_PIXEL_FORMAT_RGBA_8888 && format != HAL_PIXEL_FORMAT_RGBA_1010102) {
-     DLOGW("Unsupported format = %d", format);
-    supported = HWC2::Error::Unsupported;
-  } else if (width != variable_config.x_pixels || height != variable_config.y_pixels) {
-    DLOGW("Unsupported width = %d height = %d", width, height);
-    supported = HWC2::Error::Unsupported;
-  } else if (dataspace != HAL_DATASPACE_UNKNOWN) {
-    ColorMetaData color_metadata = {};
-    if (sdm::GetSDMColorSpace(dataspace, &color_metadata) == false) {
-      DLOGW("Unsupported dataspace = %d", dataspace);
-      supported = HWC2::Error::Unsupported;
-    }
-    if (sdm::IsBT2020(color_metadata.colorPrimaries)) {
-      DLOGW("Unsupported color Primary BT2020");
-      supported = HWC2::Error::Unsupported;
-    }
+  ColorMetaData color_metadata = {};
+  LayerBufferFormat sdm_format = GetSDMFormat(format, 0);
+  GetColorPrimary(dataspace, &(color_metadata.colorPrimaries));
+  GetTransfer(dataspace, &(color_metadata.transfer));
+  GetRange(dataspace, &(color_metadata.range));
+
+  if (display_intf_->GetClientTargetSupport(width, height, sdm_format,
+                                            color_metadata) != kErrorNone) {
+    return HWC2::Error::Unsupported;
   }
 
-  return supported;
+  return HWC2::Error::None;
 }
 
 HWC2::Error HWCDisplay::GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes) {
-  if (out_modes) {
+  if (out_modes == nullptr) {
+    *out_num_modes = 1;
+  } else if (out_modes && *out_num_modes > 0) {
+    *out_num_modes = 1;
     out_modes[0] = HAL_COLOR_MODE_NATIVE;
   }
-  *out_num_modes = 1;
 
   return HWC2::Error::None;
 }
 
 HWC2::Error HWCDisplay::GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs) {
+  if (out_num_configs == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+
   if (out_configs == nullptr) {
     *out_num_configs = num_configs_;
     return HWC2::Error::None;
   }
 
-  *out_num_configs = num_configs_;
-
-  for (uint32_t i = 0; i < num_configs_; i++) {
+  *out_num_configs = std::min(*out_num_configs, num_configs_);
+  for (uint32_t i = 0; i < *out_num_configs; i++) {
     out_configs[i] = i;
   }
 
@@ -828,27 +823,38 @@
 
 HWC2::Error HWCDisplay::GetDisplayName(uint32_t *out_size, char *out_name) {
   // TODO(user): Get panel name and EDID name and populate it here
-  if (out_name == nullptr) {
-    *out_size = 32;
-  } else {
-    std::string name;
-    switch (id_) {
-      case HWC_DISPLAY_PRIMARY:
-        name = "Primary Display";
-        break;
-      case HWC_DISPLAY_EXTERNAL:
-        name = "External Display";
-        break;
-      case HWC_DISPLAY_VIRTUAL:
-        name = "Virtual Display";
-        break;
-      default:
-        name = "Unknown";
-        break;
-    }
-    std::strncpy(out_name, name.c_str(), name.size());
-    *out_size = UINT32(name.size());
+  if (out_size == nullptr) {
+    return HWC2::Error::BadParameter;
   }
+
+  std::string name;
+  switch (id_) {
+    case HWC_DISPLAY_PRIMARY:
+      name = "Primary Display";
+      break;
+    case HWC_DISPLAY_EXTERNAL:
+      name = "External Display";
+      break;
+    case HWC_DISPLAY_VIRTUAL:
+      name = "Virtual Display";
+      break;
+    default:
+      name = "Unknown";
+      break;
+  }
+
+  if (out_name == nullptr) {
+    *out_size = UINT32(name.size()) + 1;
+  } else {
+    *out_size = std::min((UINT32(name.size()) + 1), *out_size);
+    if (*out_size > 0) {
+      std::strncpy(out_name, name.c_str(), *out_size);
+      out_name[*out_size - 1] = '\0';
+    } else {
+      DLOGW("Invalid size requested");
+    }
+  }
+
   return HWC2::Error::None;
 }
 
@@ -895,6 +901,8 @@
     return HWC2::Error::BadParameter;
   }
 
+  Layer *sdm_layer = client_target_->GetSDMLayer();
+  sdm_layer->frame_rate = current_refresh_rate_;
   client_target_->SetLayerBuffer(target, acquire_fence);
   client_target_->SetLayerSurfaceDamage(damage);
   if (client_target_->GetLayerDataspace() != dataspace) {
@@ -912,7 +920,7 @@
     return HWC2::Error::BadConfig;
   }
 
-  validated_.reset();
+  validated_ = false;
   return HWC2::Error::None;
 }
 
@@ -920,7 +928,7 @@
   return kErrorNotSupported;
 }
 
-void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+HWC2::Error HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
   dump_frame_count_ = count;
   dump_frame_index_ = 0;
   dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0);
@@ -930,7 +938,8 @@
   }
 
   DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
-  validated_.reset();
+  validated_ = false;
+  return HWC2::Error::None;
 }
 
 HWC2::PowerMode HWCDisplay::GetLastPowerMode() {
@@ -961,9 +970,10 @@
     case kIdleTimeout:
     case kThermalEvent:
     case kIdlePowerCollapse:
-      HWCSession::WaitForSequence(id_);
-      validated_.reset();
-      break;
+    case kPanelDeadEvent: {
+      SEQUENCE_WAIT_SCOPE_LOCK(HWCSession::locker_[type_]);
+      validated_ = false;
+    } break;
     default:
       DLOGW("Unknown event: %d", event);
       break;
@@ -992,7 +1002,7 @@
       }
       return HWC2::Error::BadDisplay;
     } else {
-      validated_.set(type_);
+      validated_ = true;
     }
   } else {
     // Skip is not set
@@ -1039,7 +1049,7 @@
     return HWC2::Error::None;
   }
 
-  if (!validated_.test(type_)) {
+  if (!validated_) {
     return HWC2::Error::NotValidated;
   }
 
@@ -1061,7 +1071,7 @@
     return HWC2::Error::None;
   }
 
-  if (!validated_.test(type_)) {
+  if (!validated_) {
     DLOGW("Display is not validated");
     return HWC2::Error::NotValidated;
   }
@@ -1080,15 +1090,22 @@
 
 HWC2::Error HWCDisplay::GetReleaseFences(uint32_t *out_num_elements, hwc2_layer_t *out_layers,
                                          int32_t *out_fences) {
+  if (out_num_elements == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+
   if (out_layers != nullptr && out_fences != nullptr) {
-    int i = 0;
-    for (auto hwc_layer : layer_set_) {
+    *out_num_elements = std::min(*out_num_elements, UINT32(layer_set_.size()));
+    auto it = layer_set_.begin();
+    for (uint32_t i = 0; i < *out_num_elements; i++, it++) {
+      auto hwc_layer = *it;
       out_layers[i] = hwc_layer->GetId();
       out_fences[i] = hwc_layer->PopReleaseFence();
-      i++;
     }
+  } else {
+    *out_num_elements = UINT32(layer_set_.size());
   }
-  *out_num_elements = UINT32(layer_set_.size());
+
   return HWC2::Error::None;
 }
 
@@ -1099,24 +1116,29 @@
     return HWC2::Error::None;
   }
 
+  if (out_display_requests == nullptr || out_num_elements == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+
   // No display requests for now
   // Use for sharing blit buffers and
   // writing wfd buffer directly to output if there is full GPU composition
   // and no color conversion needed
-  if (!validated_.test(type_)) {
+  if (!validated_) {
     DLOGW("Display is not validated");
     return HWC2::Error::NotValidated;
   }
 
   *out_display_requests = 0;
-  *out_num_elements = UINT32(layer_requests_.size());
   if (out_layers != nullptr && out_layer_requests != nullptr) {
-    int i = 0;
-    for (auto &request : layer_requests_) {
-      out_layers[i] = request.first;
-      out_layer_requests[i] = INT32(request.second);
-      i++;
+    *out_num_elements = std::min(*out_num_elements, UINT32(layer_requests_.size()));
+    auto it = layer_requests_.begin();
+    for (uint32_t i = 0; i < *out_num_elements; i++, it++) {
+      out_layers[i] = it->first;
+      out_layer_requests[i] = INT32(it->second);
     }
+  } else {
+    *out_num_elements = UINT32(layer_requests_.size());
   }
 
   auto client_target_layer = client_target_->GetSDMLayer();
@@ -1131,6 +1153,11 @@
                                            float *out_max_luminance,
                                            float *out_max_average_luminance,
                                            float *out_min_luminance) {
+  if (out_num_types == nullptr || out_max_luminance == nullptr ||
+      out_max_average_luminance == nullptr || out_min_luminance == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+
   DisplayConfigFixedInfo fixed_info = {};
   display_intf_->GetConfig(&fixed_info);
 
@@ -1163,10 +1190,10 @@
   }
 
   if (skip_validate_ && !CanSkipValidate()) {
-    validated_.reset(type_);
+    validated_ = false;
   }
 
-  if (!validated_.test(type_)) {
+  if (!validated_) {
     DLOGV_IF(kTagCompManager, "Display %d is not validated", id_);
     return HWC2::Error::NotValidated;
   }
@@ -1196,7 +1223,7 @@
         shutdown_pending_ = true;
         return HWC2::Error::Unsupported;
       } else if (error == kErrorNotValidated) {
-        validated_.reset(type_);
+        validated_ = false;
         return HWC2::Error::NotValidated;
       } else if (error != kErrorPermission) {
         DLOGE("Commit failed. Error = %d", error);
@@ -1217,7 +1244,7 @@
   // Do no call flush on errors, if a successful buffer is never submitted.
   if (flush_ && flush_on_error_) {
     display_intf_->Flush();
-    validated_.reset();
+    validated_ = false;
   }
 
   if (tone_mapper_ && tone_mapper_->IsActive()) {
@@ -1295,7 +1322,7 @@
 
   if (display_intf_) {
     error = display_intf_->SetMaxMixerStages(max_mixer_stages);
-    validated_.reset();
+    validated_ = false;
   }
 
   return error;
@@ -1445,6 +1472,7 @@
     return;
   }
 
+  DLOGI("dump_frame_count %d dump_input_layers %d", dump_frame_count_, dump_input_layers_);
   snprintf(dir_path, sizeof(dir_path), "%s/frame_dump_%s", HWCDebugHandler::DumpDir(),
            GetDisplayString());
 
@@ -1473,22 +1501,43 @@
       }
     }
 
-    if (pvt_handle && pvt_handle->base) {
-      char dump_file_name[PATH_MAX];
-      size_t result = 0;
+    DLOGI("Dump layer[%d] of %d pvt_handle %x pvt_handle->base %x", i, layer_stack_.layers.size(),
+          pvt_handle, pvt_handle? pvt_handle->base : 0);
 
-      snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw",
-               dir_path, i, pvt_handle->width, pvt_handle->height,
-               qdutils::GetHALPixelFormatString(pvt_handle->format), dump_frame_index_);
-
-      FILE *fp = fopen(dump_file_name, "w+");
-      if (fp) {
-        result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp);
-        fclose(fp);
-      }
-
-      DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed");
+    if (!pvt_handle) {
+      DLOGE("Buffer handle is null");
+      return;
     }
+
+    if (!pvt_handle->base) {
+      DisplayError error = buffer_allocator_->MapBuffer(pvt_handle, -1);
+      if (error != kErrorNone) {
+        DLOGE("Failed to map buffer, error = %d", error);
+        return;
+      }
+    }
+
+    char dump_file_name[PATH_MAX];
+    size_t result = 0;
+
+    snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw",
+             dir_path, i, pvt_handle->width, pvt_handle->height,
+             qdutils::GetHALPixelFormatString(pvt_handle->format), dump_frame_index_);
+
+    FILE *fp = fopen(dump_file_name, "w+");
+    if (fp) {
+      result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp);
+      fclose(fp);
+    }
+
+    int release_fence = -1;
+    DisplayError error = buffer_allocator_->UnmapBuffer(pvt_handle, &release_fence);
+    if (error != kErrorNone) {
+      DLOGE("Failed to unmap buffer, error = %d", error);
+      return;
+    }
+
+    DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed");
   }
 }
 
@@ -1658,7 +1707,7 @@
 
   if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) {
     callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
-    validated_.reset();
+    validated_ = false;
   }
 
   return status;
@@ -1676,7 +1725,7 @@
   if (hwc_layer->GetDeviceSelectedCompositionType() != HWC2::Composition::Cursor) {
     return HWC2::Error::None;
   }
-  if (!skip_validate_ && validated_.test(type_)) {
+  if (!skip_validate_ && validated_) {
     // the device is currently in the middle of the validate/present sequence,
     // cannot set the Position(as per HWC2 spec)
     return HWC2::Error::NotValidated;
@@ -1714,7 +1763,7 @@
     return -1;
   }
 
-  validated_.reset();
+  validated_ = false;
   return 0;
 }
 
@@ -1723,7 +1772,7 @@
     auto layer = hwc_layer->GetSDMLayer();
     layer->composition = kCompositionSDE;
   }
-  validated_.set(type_);
+  validated_ = true;
 }
 
 void HWCDisplay::MarkLayersForClientComposition() {
@@ -1743,7 +1792,7 @@
   int ret = 0;
   if (display_intf_) {
     ret = display_intf_->SetPanelBrightness(level);
-    validated_.reset();
+    validated_ = false;
   } else {
     ret = -EINVAL;
   }
@@ -1758,7 +1807,7 @@
 int HWCDisplay::ToggleScreenUpdates(bool enable) {
   display_paused_ = enable ? false : true;
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
-  validated_.reset();
+  validated_ = false;
   return 0;
 }
 
@@ -1862,7 +1911,7 @@
 
 int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
   int status = (display_intf_->SetActiveConfig(config) == kErrorNone) ? 0 : -1;
-  validated_.reset();
+  validated_ = false;
   return status;
 }
 
@@ -1931,22 +1980,6 @@
   return display_class_;
 }
 
-void HWCDisplay::CloseAcquireFds() {
-  for (auto hwc_layer : layer_set_) {
-    auto layer = hwc_layer->GetSDMLayer();
-    if (layer->input_buffer.acquire_fence_fd >= 0) {
-      close(layer->input_buffer.acquire_fence_fd);
-      layer->input_buffer.acquire_fence_fd = -1;
-    }
-  }
-  int32_t &client_target_acquire_fence =
-      client_target_->GetSDMLayer()->input_buffer.acquire_fence_fd;
-  if (client_target_acquire_fence >= 0) {
-    close(client_target_acquire_fence);
-    client_target_acquire_fence = -1;
-  }
-}
-
 void HWCDisplay::ClearRequestFlags() {
   for (Layer *layer : layer_stack_.layers) {
     layer->request.flags = {};
@@ -1983,6 +2016,10 @@
 }
 
 bool HWCDisplay::CanSkipValidate() {
+  if (solid_fill_enable_) {
+    return false;
+  }
+
   // Layer Stack checks
   if (layer_stack_.flags.hdr_present && (tone_mapper_ && tone_mapper_->IsActive())) {
     return false;
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 7eefcd1..b3257f9 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -107,7 +107,7 @@
 
   // Framebuffer configurations
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
-  virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
+  virtual HWC2::Error SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
   virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
   virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending) {
     return kErrorNotSupported;
@@ -160,8 +160,8 @@
   int GetVisibleDisplayRect(hwc_rect_t *rect);
   void BuildLayerStack(void);
   void BuildSolidFillStack(void);
-  HWCLayer *GetHWCLayer(hwc2_layer_t layer);
-  void ResetValidation() { validated_.reset(); }
+  HWCLayer *GetHWCLayer(hwc2_layer_t layer_id);
+  void ResetValidation() { validated_ = false; }
   uint32_t GetGeometryChanges() { return geometry_changes_; }
 
   // HWC2 APIs
@@ -240,7 +240,6 @@
   bool IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions);
   bool IsLayerUpdating(const Layer *layer);
   uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
-  virtual void CloseAcquireFds();
   virtual void ClearRequestFlags();
   virtual void GetUnderScanConfig() { }
 
@@ -249,7 +248,7 @@
     OUTPUT_LAYER_DUMP,
   };
 
-  static std::bitset<kDisplayMax> validated_;
+  bool validated_ = false;
   CoreInterface *core_intf_ = nullptr;
   HWCCallbacks *callbacks_  = nullptr;
   HWCBufferAllocator *buffer_allocator_ = NULL;
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index 97507ee..2bc2d18 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -137,7 +137,6 @@
       status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
     }
   }
-  CloseAcquireFds();
   return status;
 }
 
@@ -180,7 +179,7 @@
 
     if (secure_display_active_) {
       DisplayError error = display_intf_->Flush();
-      validated_.reset();
+      validated_ = false;
       if (error != kErrorNone) {
         DLOGE("Flush failed. Error = %d", error);
       }
@@ -234,7 +233,7 @@
 
       display_null_.GetDisplayState(&state);
       display_intf_->SetDisplayState(state);
-      validated_.reset();
+      validated_ = false;
 
       SetVsyncEnabled(HWC2::Vsync::Enable);
 
diff --git a/sdm/libs/hwc2/hwc_display_external_test.cpp b/sdm/libs/hwc2/hwc_display_external_test.cpp
new file mode 100644
index 0000000..8551854
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_display_external_test.cpp
@@ -0,0 +1,751 @@
+/*
+* 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 <cutils/properties.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <utils/formats.h>
+#include <algorithm>
+#include <array>
+#include <sstream>
+#include <string>
+#include <fstream>
+
+#include "hwc_display_external_test.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplayExternalTest"
+
+namespace sdm {
+
+using std::array;
+
+int HWCDisplayExternalTest::Create(CoreInterface *core_intf,
+                                   HWCBufferAllocator *buffer_allocator,
+                                   HWCCallbacks *callbacks,
+                                   qService::QService *qservice, uint32_t panel_bpp,
+                                   uint32_t pattern_type, HWCDisplay **hwc_display) {
+  HWCDisplay *hwc_external_test = new HWCDisplayExternalTest(core_intf, buffer_allocator,
+                                                             callbacks, qservice,
+                                                             panel_bpp, pattern_type);
+
+  int status = static_cast<HWCDisplayExternalTest *>(hwc_external_test)->Init();
+  if (status) {
+    delete hwc_external_test;
+    return status;
+  }
+
+  *hwc_display = hwc_external_test;
+
+  DLOGE("EXTERNAL panel_bpp %d, pattern_type %d", panel_bpp, pattern_type);
+
+  return status;
+}
+
+void HWCDisplayExternalTest::Destroy(HWCDisplay *hwc_display) {
+  static_cast<HWCDisplayExternalTest *>(hwc_display)->Deinit();
+
+  delete hwc_display;
+}
+
+HWCDisplayExternalTest::HWCDisplayExternalTest(CoreInterface *core_intf,
+                                               HWCBufferAllocator *buffer_allocator,
+                                               HWCCallbacks *callbacks,
+                                               qService::QService *qservice, uint32_t panel_bpp,
+                                               uint32_t pattern_type)
+  : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice,
+               DISPLAY_CLASS_EXTERNAL, buffer_allocator), panel_bpp_(panel_bpp),
+               pattern_type_(pattern_type) {
+}
+
+int HWCDisplayExternalTest::Init() {
+  uint32_t external_width = 0;
+  uint32_t external_height = 0;
+
+  int status = HWCDisplay::Init();
+  if (status) {
+      DLOGE("HWCDisplayExternalTest::Init  status = %d ", status);
+    return status;
+  }
+
+  status = CreateLayerStack();
+  if (status) {
+    Deinit();
+    return status;
+  }
+
+  DisplayError error = HWCDisplay::GetMixerResolution(&external_width, &external_height);
+  if (error != kErrorNone) {
+    Deinit();
+    return -EINVAL;
+  }
+
+  status = HWCDisplay::SetFrameBufferResolution(external_width, external_height);
+  if (status) {
+    Deinit();
+    DLOGE("HWCDisplayExternalTest:: set fb resolution status = %d ", status);
+    return status;
+  }
+
+  return status;
+}
+
+int HWCDisplayExternalTest::Deinit() {
+  DestroyLayerStack();
+  return HWCDisplay::Deinit();
+}
+
+
+HWC2::Error HWCDisplayExternalTest::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
+  auto status = HWC2::Error::None;
+  if (secure_display_active_) {
+    MarkLayersForGPUBypass();
+    return status;
+  }
+
+  if (layer_set_.empty()) {
+      flush_ = true;
+      return status;
+  }
+
+  if (shutdown_pending_) {
+    return status;
+  }
+  DisplayError error = display_intf_->Prepare(&layer_stack_);
+  if (error != kErrorNone) {
+    if (error == kErrorShutDown) {
+      shutdown_pending_ = true;
+    } else if (error != kErrorPermission) {
+      DLOGE("Prepare failed. Error = %d", error);
+      // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
+      // so that previous buffer and fences are released, and override the error.
+      flush_ = true;
+    }
+  }
+
+  MarkLayersForGPUBypass();
+
+  return  status;
+}
+
+HWC2::Error HWCDisplayExternalTest::Present(int32_t *out_retire_fence) {
+  auto status = HWC2::Error::None;
+
+  if (secure_display_active_) {
+    return status;
+  }
+
+  if (shutdown_pending_) {
+    return status;
+  }
+
+  DumpInputBuffer();
+
+  if (!flush_) {
+    DisplayError error = kErrorUndefined;
+    error = display_intf_->Commit(&layer_stack_);
+    if (error == kErrorNone) {
+      // A commit is successfully submitted, start flushing on failure now onwards.
+      flush_on_error_ = true;
+    } else if (error == kErrorShutDown) {
+      shutdown_pending_ = true;
+      status = HWC2::Error::Unsupported;
+    } else if (error == kErrorNotValidated) {
+      status = HWC2::Error::NotValidated;
+    } else if (error != kErrorPermission) {
+      DLOGE("Commit failed. Error = %d", error);
+        // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
+        // so that previous buffer and fences are released, and override the error.
+        flush_ = true;
+    }
+  }
+  PostCommit(out_retire_fence);
+  return status;
+}
+
+void HWCDisplayExternalTest::SetSecureDisplay(bool secure_display_active) {
+  if (secure_display_active_ != secure_display_active) {
+    secure_display_active_ = secure_display_active;
+
+    if (secure_display_active_) {
+      DisplayError error = display_intf_->Flush();
+      if (error != kErrorNone) {
+        DLOGE("Flush failed. Error = %d", error);
+      }
+    }
+  }
+  return;
+}
+
+int HWCDisplayExternalTest::Perform(uint32_t operation, ...) {
+  return 0;
+}
+
+void HWCDisplayExternalTest::DumpInputBuffer() {
+  if (!dump_frame_count_ || flush_ || !dump_input_layers_) {
+    return;
+  }
+
+  const char *dir_path = "/data/vendor/display/frame_dump_external";
+  uint32_t width = buffer_info_.alloc_buffer_info.aligned_width;
+  uint32_t height = buffer_info_.alloc_buffer_info.aligned_height;
+  string format_str = GetFormatString(buffer_info_.buffer_config.format);
+
+  char *buffer = reinterpret_cast<char *>(mmap(NULL, buffer_info_.alloc_buffer_info.size,
+                                                PROT_READ|PROT_WRITE, MAP_SHARED,
+                                                buffer_info_.alloc_buffer_info.fd, 0));
+  if (buffer == MAP_FAILED) {
+    DLOGW("mmap failed. err = %d", errno);
+    return;
+  }
+
+  if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) {
+    DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
+    return;
+  }
+
+  // if directory exists already, need to explicitly change the permission.
+  if (errno == EEXIST && chmod(dir_path, 0777) != 0) {
+    DLOGW("Failed to change permissions on %s directory", dir_path);
+    return;
+  }
+
+  if (buffer) {
+    std::stringstream dump_file_name;
+    dump_file_name << dir_path;
+    dump_file_name << "/input_layer_" << width << "x" << height << "_" << format_str << ".raw";
+
+    std::fstream fs;
+    fs.open(dump_file_name.str().c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
+    if (!fs.is_open()) {
+      DLOGI("File open failed %s", dump_file_name.str().c_str());
+      return;
+    }
+
+    fs.write(buffer, (std::streamsize)buffer_info_.alloc_buffer_info.size);
+    fs.close();
+
+    DLOGI("Frame Dump %s: is successful", dump_file_name.str().c_str());
+  }
+
+  // Dump only once as the content is going to be same for all draw cycles
+  if (dump_frame_count_) {
+    dump_frame_count_ = 0;
+  }
+
+  if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) {
+    DLOGW("munmap failed. err = %d", errno);
+    return;
+  }
+}
+
+void HWCDisplayExternalTest::CalcCRC(uint32_t color_val, std::bitset<16> *crc_data) {
+  std::bitset<16> color = {};
+  std::bitset<16> temp_crc = {};
+
+  switch (panel_bpp_) {
+    case kDisplayBpp18:
+      color = (color_val & 0xFC) << 8;
+      break;
+    case kDisplayBpp24:
+      color = color_val << 8;
+      break;
+    case kDisplayBpp30:
+      color = color_val << 6;
+      break;
+    default:
+      return;
+  }
+
+  temp_crc[15] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^
+                 (*crc_data)[4] ^ (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^
+                 (*crc_data)[8] ^ (*crc_data)[9] ^ (*crc_data)[10] ^ (*crc_data)[11] ^
+                 (*crc_data)[12] ^ (*crc_data)[14] ^ (*crc_data)[15] ^ color[0] ^ color[1] ^
+                 color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ color[7] ^ color[8] ^
+                 color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[14] ^ color[15];
+
+  temp_crc[14] = (*crc_data)[12] ^ (*crc_data)[13] ^ color[12] ^ color[13];
+  temp_crc[13] = (*crc_data)[11] ^ (*crc_data)[12] ^ color[11] ^ color[12];
+  temp_crc[12] = (*crc_data)[10] ^ (*crc_data)[11] ^ color[10] ^ color[11];
+  temp_crc[11] = (*crc_data)[9] ^ (*crc_data)[10] ^ color[9] ^ color[10];
+  temp_crc[10] = (*crc_data)[8] ^ (*crc_data)[9] ^ color[8] ^ color[9];
+  temp_crc[9] = (*crc_data)[7] ^ (*crc_data)[8] ^ color[7] ^ color[8];
+  temp_crc[8] = (*crc_data)[6] ^ (*crc_data)[7] ^ color[6] ^ color[7];
+  temp_crc[7] = (*crc_data)[5] ^ (*crc_data)[6] ^ color[5] ^ color[6];
+  temp_crc[6] = (*crc_data)[4] ^ (*crc_data)[5] ^ color[4] ^ color[5];
+  temp_crc[5] = (*crc_data)[3] ^ (*crc_data)[4] ^ color[3] ^ color[4];
+  temp_crc[4] = (*crc_data)[2] ^ (*crc_data)[3] ^ color[2] ^ color[3];
+  temp_crc[3] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[15] ^ color[1] ^ color[2] ^ color[15];
+  temp_crc[2] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[14] ^ color[0] ^ color[1] ^ color[14];
+
+  temp_crc[1] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ (*crc_data)[5] ^
+                (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^
+                (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^
+                (*crc_data)[14] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^
+                color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[13] ^
+                color[14];
+
+  temp_crc[0] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^
+                (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^
+                (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^
+                (*crc_data)[15] ^ color[0] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^
+                color[6] ^ color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^
+                color[13] ^ color[15];
+
+  (*crc_data) = temp_crc;
+}
+
+int HWCDisplayExternalTest::FillBuffer() {
+  uint8_t *buffer = reinterpret_cast<uint8_t *>(mmap(NULL, buffer_info_.alloc_buffer_info.size,
+                                                PROT_READ|PROT_WRITE, MAP_SHARED,
+                                                buffer_info_.alloc_buffer_info.fd, 0));
+  if (buffer == MAP_FAILED) {
+    DLOGE("mmap failed. err = %d", errno);
+    return -EFAULT;
+  }
+
+  switch (pattern_type_) {
+    case kPatternColorRamp:
+      GenerateColorRamp(buffer);
+      break;
+    case kPatternBWVertical:
+      GenerateBWVertical(buffer);
+      break;
+    case kPatternColorSquare:
+      GenerateColorSquare(buffer);
+      break;
+    default:
+      DLOGW("Invalid Pattern type %d", pattern_type_);
+      return -EINVAL;
+  }
+
+  if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) {
+    DLOGE("munmap failed. err = %d", errno);
+    return -EFAULT;
+  }
+
+  return 0;
+}
+
+int HWCDisplayExternalTest::GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride) {
+  switch (format) {
+  case kFormatRGBA8888:
+  case kFormatRGBA1010102:
+    *stride = width * 4;
+    break;
+  case kFormatRGB888:
+    *stride = width * 3;
+    break;
+  default:
+    DLOGE("Unsupported format type %d", format);
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+void HWCDisplayExternalTest::PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha,
+                                       uint8_t **buffer) {
+  LayerBufferFormat format = buffer_info_.buffer_config.format;
+
+  switch (format) {
+    case kFormatRGBA8888:
+      *(*buffer)++ = UINT8(red & 0xFF);
+      *(*buffer)++ = UINT8(green & 0xFF);
+      *(*buffer)++ = UINT8(blue & 0xFF);
+      *(*buffer)++ = UINT8(alpha & 0xFF);
+      break;
+    case kFormatRGB888:
+      *(*buffer)++ = UINT8(red & 0xFF);
+      *(*buffer)++ = UINT8(green & 0xFF);
+      *(*buffer)++ = UINT8(blue & 0xFF);
+      break;
+    case kFormatRGBA1010102:
+      // Lower 8 bits of red
+      *(*buffer)++ = UINT8(red & 0xFF);
+
+      // Upper 2 bits of Red + Lower 6 bits of green
+      *(*buffer)++ = UINT8(((green & 0x3F) << 2) | ((red >> 0x8) & 0x3));
+
+      // Upper 4 bits of green + Lower 4 bits of blue
+      *(*buffer)++ = UINT8(((blue & 0xF) << 4) | ((green >> 6) & 0xF));
+
+      // Upper 6 bits of blue + Lower 2 bits of alpha
+      *(*buffer)++ = UINT8(((alpha & 0x3) << 6) | ((blue >> 4) & 0x3F));
+      break;
+    default:
+      DLOGW("format not supported format = %d", format);
+      break;
+  }
+}
+
+void HWCDisplayExternalTest::GenerateColorRamp(uint8_t *buffer) {
+  uint32_t width = buffer_info_.buffer_config.width;
+  uint32_t height = buffer_info_.buffer_config.height;
+  LayerBufferFormat format = buffer_info_.buffer_config.format;
+  uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width;
+  uint32_t buffer_stride = 0;
+
+  uint32_t color_ramp = 0;
+  uint32_t start_color_val = 0;
+  uint32_t step_size = 1;
+  uint32_t ramp_width = 0;
+  uint32_t ramp_height = 0;
+  uint32_t shift_by = 0;
+
+  std::bitset<16> crc_red = {};
+  std::bitset<16> crc_green = {};
+  std::bitset<16> crc_blue = {};
+
+  switch (panel_bpp_) {
+    case kDisplayBpp18:
+      ramp_height = 64;
+      ramp_width = 64;
+      shift_by = 2;
+      break;
+    case kDisplayBpp24:
+      ramp_height = 64;
+      ramp_width = 256;
+      break;
+    case kDisplayBpp30:
+      ramp_height = 32;
+      ramp_width = 256;
+      start_color_val = 0x180;
+      break;
+    default:
+      return;
+  }
+
+  GetStride(format, aligned_width, &buffer_stride);
+
+  for (uint32_t loop_height = 0; loop_height < height; loop_height++) {
+    uint32_t color_value = start_color_val;
+    uint8_t *temp = buffer + (loop_height * buffer_stride);
+
+    for (uint32_t loop_width = 0; loop_width < width; loop_width++) {
+      if (color_ramp == kColorRedRamp) {
+        PixelCopy(color_value, 0, 0, 0, &temp);
+        CalcCRC(color_value, &crc_red);
+        CalcCRC(0, &crc_green);
+        CalcCRC(0, &crc_blue);
+      }
+      if (color_ramp == kColorGreenRamp) {
+        PixelCopy(0, color_value, 0, 0, &temp);
+        CalcCRC(0, &crc_red);
+        CalcCRC(color_value, &crc_green);
+        CalcCRC(0, &crc_blue);
+      }
+      if (color_ramp == kColorBlueRamp) {
+        PixelCopy(0, 0, color_value, 0, &temp);
+        CalcCRC(0, &crc_red);
+        CalcCRC(0, &crc_green);
+        CalcCRC(color_value, &crc_blue);
+      }
+      if (color_ramp == kColorWhiteRamp) {
+        PixelCopy(color_value, color_value, color_value, 0, &temp);
+        CalcCRC(color_value, &crc_red);
+        CalcCRC(color_value, &crc_green);
+        CalcCRC(color_value, &crc_blue);
+      }
+
+      color_value = (start_color_val + (((loop_width + 1) % ramp_width) * step_size)) << shift_by;
+    }
+
+    if (panel_bpp_ == kDisplayBpp30 && ((loop_height + 1) % ramp_height) == 0) {
+      if (start_color_val == 0x180) {
+        start_color_val = 0;
+        step_size = 4;
+      } else {
+        start_color_val = 0x180;
+        step_size = 1;
+        color_ramp = (color_ramp + 1) % 4;
+      }
+      continue;
+    }
+
+    if (((loop_height + 1) % ramp_height) == 0) {
+      color_ramp = (color_ramp + 1) % 4;
+    }
+  }
+
+  DLOGI("CRC red %x", crc_red.to_ulong());
+  DLOGI("CRC green %x", crc_green.to_ulong());
+  DLOGI("CRC blue %x", crc_blue.to_ulong());
+}
+
+void HWCDisplayExternalTest::GenerateBWVertical(uint8_t *buffer) {
+  uint32_t width = buffer_info_.buffer_config.width;
+  uint32_t height = buffer_info_.buffer_config.height;
+  LayerBufferFormat format = buffer_info_.buffer_config.format;
+  uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width;
+  uint32_t buffer_stride = 0;
+  uint32_t bits_per_component = panel_bpp_ / 3;
+  uint32_t max_color_val = (1 << bits_per_component) - 1;
+
+  std::bitset<16> crc_red = {};
+  std::bitset<16> crc_green = {};
+  std::bitset<16> crc_blue = {};
+
+  if (panel_bpp_ == kDisplayBpp18) {
+    max_color_val <<= 2;
+  }
+
+  GetStride(format, aligned_width, &buffer_stride);
+
+  for (uint32_t loop_height = 0; loop_height < height; loop_height++) {
+    uint32_t color = 0;
+    uint8_t *temp = buffer + (loop_height * buffer_stride);
+
+    for (uint32_t loop_width = 0; loop_width < width; loop_width++) {
+      if (color == kColorBlack) {
+        PixelCopy(0, 0, 0, 0, &temp);
+        CalcCRC(0, &crc_red);
+        CalcCRC(0, &crc_green);
+        CalcCRC(0, &crc_blue);
+      }
+      if (color == kColorWhite) {
+        PixelCopy(max_color_val, max_color_val, max_color_val, 0, &temp);
+        CalcCRC(max_color_val, &crc_red);
+        CalcCRC(max_color_val, &crc_green);
+        CalcCRC(max_color_val, &crc_blue);
+      }
+
+      color = (color + 1) % 2;
+    }
+  }
+
+  DLOGI("CRC red %x", crc_red.to_ulong());
+  DLOGI("CRC green %x", crc_green.to_ulong());
+  DLOGI("CRC blue %x", crc_blue.to_ulong());
+}
+
+void HWCDisplayExternalTest::GenerateColorSquare(uint8_t *buffer) {
+  uint32_t width = buffer_info_.buffer_config.width;
+  uint32_t height = buffer_info_.buffer_config.height;
+  LayerBufferFormat format = buffer_info_.buffer_config.format;
+  uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width;
+  uint32_t buffer_stride = 0;
+  uint32_t max_color_val = 0;
+  uint32_t min_color_val = 0;
+
+  std::bitset<16> crc_red = {};
+  std::bitset<16> crc_green = {};
+  std::bitset<16> crc_blue = {};
+
+  switch (panel_bpp_) {
+    case kDisplayBpp18:
+      max_color_val = 63 << 2;  // CEA Dynamic range for 18bpp 0 - 63
+      min_color_val = 0;
+      break;
+    case kDisplayBpp24:
+      max_color_val = 235;  // CEA Dynamic range for 24bpp 16 - 235
+      min_color_val = 16;
+      break;
+    case kDisplayBpp30:
+      max_color_val = 940;  // CEA Dynamic range for 30bpp 64 - 940
+      min_color_val = 64;
+      break;
+    default:
+      return;
+  }
+
+  array<array<uint32_t, 3>, 8> colors = {{
+    {{max_color_val, max_color_val, max_color_val}},  // White Color
+    {{max_color_val, max_color_val, min_color_val}},  // Yellow Color
+    {{min_color_val, max_color_val, max_color_val}},  // Cyan Color
+    {{min_color_val, max_color_val, min_color_val}},  // Green Color
+    {{max_color_val, min_color_val, max_color_val}},  // Megenta Color
+    {{max_color_val, min_color_val, min_color_val}},  // Red Color
+    {{min_color_val, min_color_val, max_color_val}},  // Blue Color
+    {{min_color_val, min_color_val, min_color_val}},  // Black Color
+  }};
+
+  GetStride(format, aligned_width, &buffer_stride);
+
+  for (uint32_t loop_height = 0; loop_height < height; loop_height++) {
+    uint32_t color = 0;
+    uint8_t *temp = buffer + (loop_height * buffer_stride);
+
+    for (uint32_t loop_width = 0; loop_width < width; loop_width++) {
+      PixelCopy(colors[color][0], colors[color][1], colors[color][2], 0, &temp);
+      CalcCRC(colors[color][0], &crc_red);
+      CalcCRC(colors[color][1], &crc_green);
+      CalcCRC(colors[color][2], &crc_blue);
+
+      if (((loop_width + 1) % 64) == 0) {
+        color = (color + 1) % colors.size();
+      }
+    }
+
+    if (((loop_height + 1) % 64) == 0) {
+      std::reverse(colors.begin(), (colors.end() - 1));
+    }
+  }
+
+  DLOGI("CRC red %x", crc_red.to_ulong());
+  DLOGI("CRC green %x", crc_green.to_ulong());
+  DLOGI("CRC blue %x", crc_blue.to_ulong());
+}
+
+int HWCDisplayExternalTest::InitLayer(Layer *layer) {
+  uint32_t active_config = 0;
+  DisplayConfigVariableInfo var_info = {};
+
+  GetActiveDisplayConfig(&active_config);
+
+  GetDisplayAttributesForConfig(INT32(active_config), &var_info);
+
+  layer->flags.updating = 1;
+  layer->src_rect = LayerRect(0, 0, var_info.x_pixels, var_info.y_pixels);
+  layer->dst_rect = layer->src_rect;
+  layer->frame_rate = var_info.fps;
+  layer->blending = kBlendingPremultiplied;
+
+  layer->input_buffer.unaligned_width = var_info.x_pixels;
+  layer->input_buffer.unaligned_height = var_info.y_pixels;
+  buffer_info_.buffer_config.format = kFormatRGBA8888;
+
+  if (layer->composition != kCompositionGPUTarget) {
+    buffer_info_.buffer_config.width = var_info.x_pixels;
+    buffer_info_.buffer_config.height = var_info.y_pixels;
+    switch (panel_bpp_) {
+      case kDisplayBpp18:
+      case kDisplayBpp24:
+        buffer_info_.buffer_config.format = kFormatRGB888;
+        break;
+      case kDisplayBpp30:
+        buffer_info_.buffer_config.format = kFormatRGBA1010102;
+        break;
+      default:
+        DLOGW("panel bpp not supported %d", panel_bpp_);
+        return -EINVAL;
+    }
+    buffer_info_.buffer_config.buffer_count = 1;
+
+    int ret = buffer_allocator_->AllocateBuffer(&buffer_info_);
+    if (ret != 0) {
+      DLOGE("Buffer allocation failed. ret: %d", ret);
+      return -ENOMEM;
+    }
+
+    ret = FillBuffer();
+    if (ret != 0) {
+      buffer_allocator_->FreeBuffer(&buffer_info_);
+      return ret;
+    }
+
+    layer->input_buffer.width = buffer_info_.alloc_buffer_info.aligned_width;
+    layer->input_buffer.height = buffer_info_.alloc_buffer_info.aligned_height;
+    layer->input_buffer.size = buffer_info_.alloc_buffer_info.size;
+    layer->input_buffer.planes[0].fd = buffer_info_.alloc_buffer_info.fd;
+    layer->input_buffer.planes[0].stride = buffer_info_.alloc_buffer_info.stride;
+    layer->input_buffer.format = buffer_info_.buffer_config.format;
+
+    DLOGI("Input buffer WxH %dx%d format %s size %d fd %d stride %d", layer->input_buffer.width,
+          layer->input_buffer.height, GetFormatString(layer->input_buffer.format),
+          layer->input_buffer.size, layer->input_buffer.planes[0].fd,
+          layer->input_buffer.planes[0].stride);
+  }
+
+  return 0;
+}
+
+int HWCDisplayExternalTest::DeinitLayer(Layer *layer) {
+  if (layer->composition != kCompositionGPUTarget) {
+    int ret = buffer_allocator_->FreeBuffer(&buffer_info_);
+    if (ret != 0) {
+      DLOGE("Buffer deallocation failed. ret: %d", ret);
+      return -ENOMEM;
+    }
+  }
+
+  return 0;
+}
+
+int HWCDisplayExternalTest::CreateLayerStack() {
+  for (uint32_t i = 0; i < (kTestLayerCnt + 1 /* one dummy gpu_target layer */); i++) {
+    Layer *layer = new Layer();
+
+    if (i == kTestLayerCnt) {
+      layer->composition = kCompositionGPUTarget;
+    }
+    DLOGE("External :: CreateLayerStack %d", i);
+    int ret = InitLayer(layer);
+    if (ret != 0) {
+      delete layer;
+      return ret;
+    }
+    layer_stack_.layers.push_back(layer);
+  }
+
+  return 0;
+}
+
+int HWCDisplayExternalTest::DestroyLayerStack() {
+  for (uint32_t i = 0; i < UINT32(layer_stack_.layers.size()); i++) {
+    Layer *layer = layer_stack_.layers.at(i);
+    int ret = DeinitLayer(layer);
+    if (ret != 0) {
+      return ret;
+    }
+    delete layer;
+  }
+  layer_stack_.layers = {};
+
+  return 0;
+}
+
+HWC2::Error HWCDisplayExternalTest::PostCommit(int32_t *out_retire_fence) {
+  auto status = HWC2::Error::None;
+  // Do no call flush on errors, if a successful buffer is never submitted.
+  if (flush_ && flush_on_error_) {
+    display_intf_->Flush();
+  }
+  if (!flush_) {
+    for (size_t i = 0; i < layer_stack_.layers.size(); i++) {
+      Layer *layer = layer_stack_.layers.at(i);
+      LayerBuffer &layer_buffer = layer->input_buffer;
+
+      close(layer_buffer.release_fence_fd);
+      layer_buffer.release_fence_fd = -1;
+    }
+    close(layer_stack_.retire_fence_fd);
+    layer_stack_.retire_fence_fd = -1;
+    *out_retire_fence = -1;
+  }
+  flush_ = false;
+
+  return status;
+}
+
+}  // namespace sdm
+
diff --git a/sdm/libs/hwc2/hwc_display_external_test.h b/sdm/libs/hwc2/hwc_display_external_test.h
new file mode 100644
index 0000000..ef8027b
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_display_external_test.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 __HWC_DISPLAY_EXTERNAL_TEST_H__
+#define __HWC_DISPLAY_EXTERNAL_TEST_H__
+
+#include <bitset>
+
+#include "hwc_display.h"
+#include "hwc_buffer_allocator.h"
+
+namespace sdm {
+
+class HWCDisplayExternalTest : public HWCDisplay {
+ public:
+  static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+                    HWCCallbacks *callbacks, qService::QService *qservice,
+                    uint32_t panel_bpp, uint32_t pattern_type, HWCDisplay **hwc_display);
+  static void Destroy(HWCDisplay *hwc_display);
+  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 Perform(uint32_t operation, ...);
+
+ protected:
+  BufferInfo buffer_info_ = {};
+  uint32_t panel_bpp_ = 0;
+  uint32_t pattern_type_ = 0;
+
+  enum ColorPatternType {
+    kPatternNone = 0,
+    kPatternColorRamp,
+    kPatternBWVertical,
+    kPatternColorSquare,
+  };
+
+  enum DisplayBpp {
+    kDisplayBpp18 = 18,
+    kDisplayBpp24 = 24,
+    kDisplayBpp30 = 30,
+  };
+
+  enum ColorRamp {
+    kColorRedRamp = 0,
+    kColorGreenRamp = 1,
+    kColorBlueRamp = 2,
+    kColorWhiteRamp = 3,
+  };
+
+  enum Colors {
+    kColorBlack = 0,
+    kColorWhite = 1,
+  };
+
+ private:
+  HWCDisplayExternalTest(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+                         HWCCallbacks *callbacks, qService::QService *qservice,
+                         uint32_t panel_bpp, uint32_t pattern_type);
+  int Init();
+  int Deinit();
+  void DumpInputBuffer();
+  void CalcCRC(uint32_t color_value, std::bitset<16> *crc_data);
+  int FillBuffer();
+  int GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride);
+  void PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, uint8_t **buffer);
+  void GenerateColorRamp(uint8_t *buffer);
+  void GenerateBWVertical(uint8_t *buffer);
+  void GenerateColorSquare(uint8_t *buffer);
+  int InitLayer(Layer *layer);
+  int DeinitLayer(Layer *layer);
+  int CreateLayerStack();
+  int DestroyLayerStack();
+  HWC2::Error PostCommit(int32_t *out_retire_fence);
+
+  static const uint32_t kTestLayerCnt = 1;
+};
+
+}  // namespace sdm
+
+#endif  // __HWC_DISPLAY_EXTERNAL_TEST_H__
+
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index d4917f6..50f5aeb 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -220,7 +220,7 @@
     // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
     // Revisit this when validating display_paused
     DisplayError error = display_intf_->Flush();
-    validated_.reset();
+    validated_ = false;
     if (error != kErrorNone) {
       DLOGE("Flush failed. Error = %d", error);
     }
@@ -233,7 +233,6 @@
     }
   }
 
-  CloseAcquireFds();
   return status;
 }
 
@@ -256,7 +255,7 @@
   }
 
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
-  validated_.reset();
+  validated_ = false;
 
   return status;
 }
@@ -269,7 +268,7 @@
   }
 
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
-  validated_.reset();
+  validated_ = false;
 
   return status;
 }
@@ -289,7 +288,7 @@
 
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
   color_tranform_failed_ = false;
-  validated_.reset();
+  validated_ = false;
 
   return status;
 }
@@ -332,7 +331,7 @@
       return -EINVAL;
   }
   va_end(args);
-  validated_.reset();
+  validated_ = false;
 
   return 0;
 }
@@ -419,7 +418,7 @@
 
 void HWCDisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
   display_intf_->SetIdleTimeoutMs(timeout_ms);
-  validated_.reset();
+  validated_ = false;
 }
 
 static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
@@ -484,13 +483,13 @@
   }
 }
 
-void HWCDisplayPrimary::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+HWC2::Error HWCDisplayPrimary::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
   HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
   dump_output_to_file_ = bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP);
   DLOGI("output_layer_dump_enable %d", dump_output_to_file_);
 
   if (!count || !dump_output_to_file_) {
-    return;
+    return HWC2::Error::None;
   }
 
   // Allocate and map output buffer
@@ -503,7 +502,7 @@
   if (buffer_allocator_->AllocateBuffer(&output_buffer_info_) != 0) {
     DLOGE("Buffer allocation failed");
     output_buffer_info_ = {};
-    return;
+    return HWC2::Error::NoResources;
   }
 
   void *buffer = mmap(NULL, output_buffer_info_.alloc_buffer_info.size, PROT_READ | PROT_WRITE,
@@ -513,13 +512,14 @@
     DLOGE("mmap failed with err %d", errno);
     buffer_allocator_->FreeBuffer(&output_buffer_info_);
     output_buffer_info_ = {};
-    return;
+    return HWC2::Error::NoResources;
   }
 
   output_buffer_base_ = buffer;
   post_processed_output_ = true;
   DisablePartialUpdateOneFrame();
-  validated_.reset();
+  validated_ = false;
+  return HWC2::Error::None;
 }
 
 int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
@@ -564,7 +564,7 @@
 
   if (display_intf_) {
     error = display_intf_->SetDetailEnhancerData(de_data);
-    validated_.reset();
+    validated_ = false;
   }
   return error;
 }
@@ -574,7 +574,7 @@
 
   if (display_intf_) {
     error = display_intf_->ControlPartialUpdate(enable, pending);
-    validated_.reset();
+    validated_ = false;
   }
 
   return error;
@@ -585,7 +585,7 @@
 
   if (display_intf_) {
     error = display_intf_->DisablePartialUpdateOneFrame();
-    validated_.reset();
+    validated_ = false;
   }
 
   return error;
@@ -594,7 +594,7 @@
 
 DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) {
   DisplayError error = display_intf_->SetMixerResolution(width, height);
-  validated_.reset();
+  validated_ = false;
   return error;
 }
 
diff --git a/sdm/libs/hwc2/hwc_display_primary.h b/sdm/libs/hwc2/hwc_display_primary.h
index 49840c5..daf832d 100644
--- a/sdm/libs/hwc2/hwc_display_primary.h
+++ b/sdm/libs/hwc2/hwc_display_primary.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
@@ -63,7 +63,7 @@
   virtual void SetSecureDisplay(bool secure_display_active);
   virtual DisplayError Refresh();
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
-  virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
+  virtual HWC2::Error SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
   virtual int FrameCaptureAsync(const BufferInfo &output_buffer_info, bool post_processed);
   virtual int GetFrameCaptureStatus() { return frame_capture_status_; }
   virtual DisplayError SetDetailEnhancerConfig(const DisplayDetailEnhancerData &de_data);
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index 8837ad0..8778942 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -123,15 +123,30 @@
 
   BuildLayerStack();
   layer_stack_.output_buffer = output_buffer_;
+  // If Output buffer of Virtual Display is not secure, set SKIP flag on the secure layers.
+  if (output_buffer_ && !output_buffer_->flags.secure && layer_stack_.flags.secure_present) {
+    for (auto hwc_layer : layer_set_) {
+      Layer *layer = hwc_layer->GetSDMLayer();
+      if (layer->input_buffer.flags.secure) {
+        layer_stack_.flags.skip_present = true;
+        layer->flags.skip = true;
+      }
+    }
+  }
   status = PrepareLayerStack(out_num_types, out_num_requests);
   return status;
 }
 
 HWC2::Error HWCDisplayVirtual::Present(int32_t *out_retire_fence) {
   auto status = HWC2::Error::None;
+
+  if (!output_buffer_->buffer_id) {
+    return HWC2::Error::NoResources;
+  }
+
   if (display_paused_) {
     DisplayError error = display_intf_->Flush();
-    validated_.reset();
+    validated_ = false;
     if (error != kErrorNone) {
       DLOGE("Flush failed. Error = %d", error);
     }
@@ -139,10 +154,18 @@
     status = HWCDisplay::CommitLayerStack();
     if (status == HWC2::Error::None) {
       if (dump_frame_count_ && !flush_ && dump_output_layer_) {
-        if (output_handle_ && output_handle_->base) {
+        if (output_handle_) {
           BufferInfo buffer_info;
           const private_handle_t *output_handle =
               reinterpret_cast<const private_handle_t *>(output_buffer_->buffer_id);
+          DisplayError error = kErrorNone;
+          if (!output_handle->base) {
+            error = buffer_allocator_->MapBuffer(output_handle, -1);
+            if (error != kErrorNone) {
+              DLOGE("Failed to map output buffer, error = %d", error);
+              return HWC2::Error::BadParameter;
+            }
+          }
           buffer_info.buffer_config.width = static_cast<uint32_t>(output_handle->width);
           buffer_info.buffer_config.height = static_cast<uint32_t>(output_handle->height);
           buffer_info.buffer_config.format =
@@ -150,14 +173,23 @@
           buffer_info.alloc_buffer_info.size = static_cast<uint32_t>(output_handle->size);
           DumpOutputBuffer(buffer_info, reinterpret_cast<void *>(output_handle->base),
                            layer_stack_.retire_fence_fd);
+
+          int release_fence = -1;
+          error = buffer_allocator_->UnmapBuffer(output_handle, &release_fence);
+          if (error != kErrorNone) {
+            DLOGE("Failed to unmap buffer, error = %d", error);
+            return HWC2::Error::BadParameter;
+          }
         }
       }
 
       status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
     }
   }
-  CloseAcquireFds();
-  close(output_buffer_->acquire_fence_fd);
+  if (output_buffer_->acquire_fence_fd >= 0) {
+    close(output_buffer_->acquire_fence_fd);
+    output_buffer_->acquire_fence_fd = -1;
+  }
   return status;
 }
 
@@ -167,7 +199,11 @@
   variable_info.y_pixels = height;
   // TODO(user): Need to get the framerate of primary display and update it.
   variable_info.fps = 60;
-  return display_intf_->SetActiveConfig(&variable_info);
+  DisplayError err = display_intf_->SetActiveConfig(&variable_info);
+  if (err != kErrorNone) {
+    return -EINVAL;
+  }
+  return 0;
 }
 
 HWC2::Error HWCDisplayVirtual::SetOutputBuffer(buffer_handle_t buf, int32_t release_fence) {
@@ -180,38 +216,53 @@
   output_buffer_->acquire_fence_fd = dup(release_fence);
 
   if (output_handle) {
-    output_handle_ = output_handle;
-    output_buffer_->buffer_id = reinterpret_cast<uint64_t>(output_handle);
     int output_handle_format = output_handle->format;
+    int active_aligned_w, active_aligned_h;
+    int new_width, new_height;
+    int new_aligned_w, new_aligned_h;
+    uint32_t active_width, active_height;
+    ColorMetaData color_metadata = {};
 
     if (output_handle_format == HAL_PIXEL_FORMAT_RGBA_8888) {
       output_handle_format = HAL_PIXEL_FORMAT_RGBX_8888;
     }
 
-    output_buffer_->format = GetSDMFormat(output_handle_format, output_handle->flags);
-
-    if (output_buffer_->format == kFormatInvalid) {
+    LayerBufferFormat new_sdm_format = GetSDMFormat(output_handle_format, output_handle->flags);
+    if (new_sdm_format == kFormatInvalid) {
       return HWC2::Error::BadParameter;
     }
 
-    int aligned_width, aligned_height;
-#ifdef USE_GRALLOC1
-    buffer_allocator_->GetCustomWidthAndHeight(output_handle, &aligned_width, &aligned_height);
-#else
-    AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(output_handle, aligned_width,
-                                                          aligned_height);
-#endif
+    if (sdm::SetCSC(output_handle, &color_metadata) != kErrorNone) {
+      return HWC2::Error::BadParameter;
+    }
 
-    output_buffer_->width = UINT32(aligned_width);
-    output_buffer_->height = UINT32(aligned_height);
-    output_buffer_->unaligned_width = UINT32(output_handle->unaligned_width);
-    output_buffer_->unaligned_height = UINT32(output_handle->unaligned_height);
+    GetMixerResolution(&active_width, &active_height);
+    buffer_allocator_->GetCustomWidthAndHeight(output_handle, &new_width, &new_height);
+    buffer_allocator_->GetAlignedWidthAndHeight(INT(new_width), INT(new_height),
+                                                output_handle_format, 0, &new_aligned_w,
+                                                &new_aligned_h);
+    buffer_allocator_->GetAlignedWidthAndHeight(INT(active_width), INT(active_height),
+                                                output_handle_format, 0, &active_aligned_w,
+                                                &active_aligned_h);
+    if (new_aligned_w != active_aligned_w  || new_aligned_h != active_aligned_h) {
+      int status = SetConfig(UINT32(new_width), UINT32(new_height));
+      if (status) {
+        DLOGE("SetConfig failed custom WxH %dx%d", new_width, new_height);
+        return HWC2::Error::BadParameter;
+      }
+      validated_ = false;
+    }
+
+    output_buffer_->width = UINT32(new_aligned_w);
+    output_buffer_->height = UINT32(new_aligned_h);
+    output_buffer_->unaligned_width = UINT32(new_width);
+    output_buffer_->unaligned_height = UINT32(new_height);
     output_buffer_->flags.secure = 0;
     output_buffer_->flags.video = 0;
-
-    if (sdm::SetCSC(output_handle, &output_buffer_->color_metadata) != kErrorNone) {
-      return HWC2::Error::BadParameter;
-    }
+    output_buffer_->buffer_id = reinterpret_cast<uint64_t>(output_handle);
+    output_buffer_->format = new_sdm_format;
+    output_buffer_->color_metadata = color_metadata;
+    output_handle_ = output_handle;
 
     // TZ Protected Buffer - L1
     if (output_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
@@ -227,11 +278,12 @@
   return HWC2::Error::None;
 }
 
-void HWCDisplayVirtual::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+HWC2::Error HWCDisplayVirtual::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
   HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
   dump_output_layer_ = ((bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP)) != 0);
 
   DLOGI("output_layer_dump_enable %d", dump_output_layer_);
+  return HWC2::Error::None;
 }
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_virtual.h b/sdm/libs/hwc2/hwc_display_virtual.h
index 36e8509..cf630fb 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.h
+++ b/sdm/libs/hwc2/hwc_display_virtual.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
@@ -46,7 +46,7 @@
   virtual int Deinit();
   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 SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
+  virtual HWC2::Error SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
   HWC2::Error SetOutputBuffer(buffer_handle_t buf, int32_t release_fence);
 
  private:
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index fee67b4..2466413 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -184,6 +184,9 @@
     release_fences_.pop();
   }
   if (layer_) {
+    if (layer_->input_buffer.acquire_fence_fd >= 0) {
+      close(layer_->input_buffer.acquire_fence_fd);
+    }
     delete layer_;
   }
 }
@@ -251,10 +254,13 @@
   layer_buffer->flags.secure_camera = secure_camera;
   layer_buffer->flags.secure_display = secure_display;
 
+  if (layer_buffer->acquire_fence_fd >= 0) {
+    close(layer_buffer->acquire_fence_fd);
+  }
+  layer_buffer->acquire_fence_fd = acquire_fence;
   layer_buffer->planes[0].fd = handle->fd;
   layer_buffer->planes[0].offset = handle->offset;
   layer_buffer->planes[0].stride = UINT32(handle->width);
-  layer_buffer->acquire_fence_fd = acquire_fence;
   layer_buffer->size = handle->size;
   layer_buffer->buffer_id = reinterpret_cast<uint64_t>(handle);
 
@@ -320,6 +326,10 @@
 }
 
 HWC2::Error HWCLayer::SetLayerCompositionType(HWC2::Composition type) {
+  // Validation is required when the client changes the composition type
+  if (client_requested_ != type) {
+    needs_validate_ = true;
+  }
   client_requested_ = type;
   switch (type) {
     case HWC2::Composition::Client:
@@ -406,8 +416,13 @@
 }
 
 HWC2::Error HWCLayer::SetLayerPlaneAlpha(float alpha) {
-  // Conversion of float alpha in range 0.0 to 1.0 similar to the HWC Adapter
+  if (alpha < 0.0f || alpha > 1.0f) {
+    return HWC2::Error::BadParameter;
+  }
+
+  //  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));
+
   if (layer_->plane_alpha != plane_alpha) {
     geometry_changes_ |= kPlaneAlpha;
     layer_->plane_alpha = plane_alpha;
@@ -457,8 +472,10 @@
       layer_transform.flip_vertical = true;
       break;
     case HWC2::Transform::None:
-      // do nothing
       break;
+    default:
+      //  bad transform
+      return HWC2::Error::BadParameter;
   }
 
   if (layer_transform_ != layer_transform) {
@@ -531,6 +548,12 @@
       case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
         format = kFormatYCbCr420SPVenusUbwc;
         break;
+      case HAL_PIXEL_FORMAT_RGBA_1010102:
+        format = kFormatRGBA1010102Ubwc;
+        break;
+      case HAL_PIXEL_FORMAT_RGBX_1010102:
+        format = kFormatRGBX1010102Ubwc;
+        break;
       case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC:
         format = kFormatYCbCr420TP10Ubwc;
         break;
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index e0396b6..a576734 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -32,6 +32,8 @@
 #include <utils/debug.h>
 #include <sync/sync.h>
 #include <profiler.h>
+#include <qd_utils.h>
+#include <utils/utils.h>
 #include <algorithm>
 #include <string>
 #include <bitset>
@@ -44,6 +46,7 @@
 #include "hwc_debugger.h"
 #include "hwc_display_primary.h"
 #include "hwc_display_virtual.h"
+#include "hwc_display_external_test.h"
 
 #define __CLASS__ "HWCSession"
 
@@ -192,8 +195,7 @@
     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]);
+      status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false);
     }
   } else {
     // Create and power on primary display
@@ -294,6 +296,10 @@
 
 void HWCSession::GetCapabilities(struct hwc2_device *device, uint32_t *outCount,
                                  int32_t *outCapabilities) {
+  if (!outCount) {
+    return;
+  }
+
   int value = 0;
   bool disable_skip_validate = false;
   if (Debug::Get()->GetProperty("sdm.debug.disable_skip_validate", &value) == kErrorNone) {
@@ -320,12 +326,21 @@
 // Defined in the same order as in the HWC2 header
 
 int32_t HWCSession::AcceptDisplayChanges(hwc2_device_t *device, hwc2_display_t display) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return  HWC2_ERROR_BAD_DISPLAY;
+  }
   SCOPE_LOCK(locker_[display]);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::AcceptDisplayChanges);
 }
 
 int32_t HWCSession::CreateLayer(hwc2_device_t *device, hwc2_display_t display,
                                 hwc2_layer_t *out_layer_id) {
+  if (!out_layer_id) {
+    return  HWC2_ERROR_BAD_PARAMETER;
+  }
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return  HWC2_ERROR_BAD_DISPLAY;
+  }
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::CreateLayer, out_layer_id);
 }
@@ -333,13 +348,17 @@
 int32_t HWCSession::CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
                                          int32_t *format, hwc2_display_t *out_display_id) {
   // TODO(user): Handle concurrency with HDMI
-  SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  if (!out_display_id || !width || !height || !format) {
+    return  HWC2_ERROR_BAD_PARAMETER;
+  }
+
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
   auto status = hwc_session->CreateVirtualDisplayObject(width, height, format);
+
   if (status == HWC2::Error::None) {
     *out_display_id = HWC_DISPLAY_VIRTUAL;
     DLOGI("Created virtual display id:% " PRIu64 " with res: %dx%d",
@@ -352,6 +371,9 @@
 
 int32_t HWCSession::DestroyLayer(hwc2_device_t *device, hwc2_display_t display,
                                  hwc2_layer_t layer) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return  HWC2_ERROR_BAD_DISPLAY;
+  }
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::DestroyLayer, layer);
 }
@@ -375,7 +397,7 @@
 }
 
 void HWCSession::Dump(hwc2_device_t *device, uint32_t *out_size, char *out_buffer) {
-  if (!device) {
+  if (!device || !out_size) {
     return;
   }
   auto *hwc_session = static_cast<HWCSession *>(device);
@@ -407,6 +429,10 @@
 static int32_t GetChangedCompositionTypes(hwc2_device_t *device, hwc2_display_t display,
                                           uint32_t *out_num_elements, hwc2_layer_t *out_layers,
                                           int32_t *out_types) {
+  // null_ptr check only for out_num_elements, as out_layers and out_types can be null.
+  if (!out_num_elements) {
+    return  HWC2_ERROR_BAD_PARAMETER;
+  }
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetChangedCompositionTypes,
                                          out_num_elements, out_layers, out_types);
 }
@@ -420,6 +446,9 @@
 static int32_t GetColorModes(hwc2_device_t *device, hwc2_display_t display, uint32_t *out_num_modes,
                              int32_t /*android_color_mode_t*/ *int_out_modes) {
   auto out_modes = reinterpret_cast<android_color_mode_t *>(int_out_modes);
+  if (out_num_modes == nullptr) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetColorModes, out_num_modes,
                                          out_modes);
 }
@@ -427,6 +456,10 @@
 static int32_t GetDisplayAttribute(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_config_t config, int32_t int_attribute,
                                    int32_t *out_value) {
+  if (out_value == nullptr || int_attribute < HWC2_ATTRIBUTE_INVALID ||
+      int_attribute > HWC2_ATTRIBUTE_DPI_Y) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
   auto attribute = static_cast<HWC2::Attribute>(int_attribute);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetDisplayAttribute, config,
                                          attribute, out_value);
@@ -457,14 +490,20 @@
 }
 
 static int32_t GetDozeSupport(hwc2_device_t *device, hwc2_display_t display, int32_t *out_support) {
+  if (!device || !out_support) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
   if (display == HWC_DISPLAY_PRIMARY) {
     *out_support = 1;
   } else {
-    // TODO(user): Port over connect_display_ from HWC1
-    // Return no error for connected displays
     *out_support = 0;
-    return HWC2_ERROR_BAD_DISPLAY;
   }
+
   return HWC2_ERROR_NONE;
 }
 
@@ -478,6 +517,10 @@
 }
 
 static uint32_t GetMaxVirtualDisplayCount(hwc2_device_t *device) {
+  if (device == nullptr) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
   return 1;
 }
 
@@ -496,7 +539,9 @@
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
-
+  if (out_retire_fence == nullptr) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
   auto status = HWC2::Error::BadDisplay;
   // TODO(user): Handle virtual display/HDMI concurrency
   if (hwc_session->hwc_display_[display]) {
@@ -637,14 +682,19 @@
 
 int32_t HWCSession::SetLayerZOrder(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_layer_t layer, uint32_t z) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
   SCOPE_LOCK(locker_[display]);
+
   return CallDisplayFunction(device, display, &HWCDisplay::SetLayerZOrder, layer, z);
 }
 
 int32_t HWCSession::SetOutputBuffer(hwc2_device_t *device, hwc2_display_t display,
                                     buffer_handle_t buffer, int32_t releaseFence) {
   if (!device) {
-    return HWC2_ERROR_BAD_DISPLAY;
+    return HWC2_ERROR_BAD_PARAMETER;
   }
 
   if (display != HWC_DISPLAY_VIRTUAL) {
@@ -663,24 +713,51 @@
 }
 
 int32_t HWCSession::SetPowerMode(hwc2_device_t *device, hwc2_display_t display, int32_t int_mode) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
+  //  validate device and also avoid undefined behavior in cast to HWC2::PowerMode
+  if (!device || int_mode < HWC2_POWER_MODE_OFF || int_mode > HWC2_POWER_MODE_DOZE_SUSPEND) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
   auto mode = static_cast<HWC2::PowerMode>(int_mode);
+
+  //  all displays support on/off. Check for doze modes
+  int support = 0;
+  GetDozeSupport(device, display, &support);
+  if (!support && (mode == HWC2::PowerMode::Doze || mode == HWC2::PowerMode::DozeSuspend)) {
+    return HWC2_ERROR_UNSUPPORTED;
+  }
+
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::SetPowerMode, mode);
 }
 
 static int32_t SetVsyncEnabled(hwc2_device_t *device, hwc2_display_t display, int32_t int_enabled) {
+  //  avoid undefined behavior in cast to HWC2::Vsync
+  if (int_enabled < HWC2_VSYNC_INVALID || int_enabled > HWC2_VSYNC_DISABLE) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
   auto enabled = static_cast<HWC2::Vsync>(int_enabled);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetVsyncEnabled, enabled);
 }
 
 int32_t HWCSession::ValidateDisplay(hwc2_device_t *device, hwc2_display_t display,
                                     uint32_t *out_num_types, uint32_t *out_num_requests) {
-  DTRACE_SCOPED();
-  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  //  out_num_types and out_num_requests will be non-NULL
   if (!device) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  DTRACE_SCOPED();
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
   // TODO(user): Handle secure session, handle QDCM solid fill
   // Handle external_pending_connect_ in CreateVirtualDisplay
   auto status = HWC2::Error::BadDisplay;
@@ -696,6 +773,7 @@
 
         if (hwc_session->need_invalidate_) {
           hwc_session->Refresh(display);
+          hwc_session->need_invalidate_ = false;
         }
 
         if (hwc_session->color_mgr_) {
@@ -815,18 +893,24 @@
   return nullptr;
 }
 
-// TODO(user): handle locking
-
 HWC2::Error HWCSession::CreateVirtualDisplayObject(uint32_t width, uint32_t height,
                                                    int32_t *format) {
-  if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
-    return HWC2::Error::NoResources;
+  {
+    SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
+    if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+      return HWC2::Error::NoResources;
+    }
+
+    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) {
+      return HWC2::Error::Unsupported;
+    }
   }
-  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)
-    return HWC2::Error::Unsupported;
+
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
+  hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
 
   return HWC2::Error::None;
 }
@@ -841,8 +925,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,
-                                        primary_height, qservice_, false, &hwc_display_[disp]);
+    status = CreateExternalDisplay(disp, primary_width, primary_height, false);
   } else {
     DLOGE("Invalid display type");
     return -1;
@@ -875,34 +958,59 @@
 // Qclient methods
 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
-  android::status_t status = 0;
+  android::status_t status = -EINVAL;
 
   switch (command) {
     case qService::IQService::DYNAMIC_DEBUG:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
+      status = 0;
       DynamicDebug(input_parcel);
       break;
 
     case qService::IQService::SCREEN_REFRESH:
-      refreshScreen();
+      status = refreshScreen();
       break;
 
     case qService::IQService::SET_IDLE_TIMEOUT:
-      setIdleTimeout(UINT32(input_parcel->readInt32()));
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
+      status = setIdleTimeout(UINT32(input_parcel->readInt32()));
       break;
 
     case qService::IQService::SET_FRAME_DUMP_CONFIG:
-      SetFrameDumpConfig(input_parcel);
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
+      status = SetFrameDumpConfig(input_parcel);
       break;
 
     case qService::IQService::SET_MAX_PIPES_PER_MIXER:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
       status = SetMaxMixerStages(input_parcel);
       break;
 
     case qService::IQService::SET_DISPLAY_MODE:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
       status = SetDisplayMode(input_parcel);
       break;
 
     case qService::IQService::SET_SECONDARY_DISPLAY_STATUS: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         int disp_id = INT(input_parcel->readInt32());
         HWCDisplay::DisplayStatus disp_status =
               static_cast<HWCDisplay::DisplayStatus>(input_parcel->readInt32());
@@ -912,13 +1020,22 @@
       break;
 
     case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
       status = ConfigureRefreshRate(input_parcel);
       break;
 
     case qService::IQService::SET_VIEW_FRAME:
+      status = 0;
       break;
 
     case qService::IQService::TOGGLE_SCREEN_UPDATES: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         int32_t input = input_parcel->readInt32();
         status = toggleScreenUpdate(input == 1);
         output_parcel->writeInt32(status);
@@ -926,10 +1043,18 @@
       break;
 
     case qService::IQService::QDCM_SVC_CMDS:
+      if (!input_parcel || !output_parcel) {
+        DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+        break;
+      }
       status = QdcmCMDHandler(input_parcel, output_parcel);
       break;
 
     case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         int disp_id = input_parcel->readInt32();
         uint32_t min_enc_level = UINT32(input_parcel->readInt32());
         status = MinHdcpEncryptionLevelChanged(disp_id, min_enc_level);
@@ -938,6 +1063,10 @@
       break;
 
     case qService::IQService::CONTROL_PARTIAL_UPDATE: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         int disp_id = input_parcel->readInt32();
         uint32_t enable = UINT32(input_parcel->readInt32());
         status = ControlPartialUpdate(disp_id, enable == 1);
@@ -946,6 +1075,10 @@
       break;
 
     case qService::IQService::SET_ACTIVE_CONFIG: {
+        if (!input_parcel) {
+          DLOGE("QService command = %d: input_parcel needed.", command);
+          break;
+        }
         uint32_t config = UINT32(input_parcel->readInt32());
         int disp_id = input_parcel->readInt32();
         status = SetActiveConfigIndex(disp_id, config);
@@ -953,6 +1086,10 @@
       break;
 
     case qService::IQService::GET_ACTIVE_CONFIG: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         int disp_id = input_parcel->readInt32();
         uint32_t config = 0;
         status = GetActiveConfigIndex(disp_id, &config);
@@ -961,6 +1098,10 @@
       break;
 
     case qService::IQService::GET_CONFIG_COUNT: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         int disp_id = input_parcel->readInt32();
         uint32_t count = 0;
         status = GetConfigCount(disp_id, &count);
@@ -969,10 +1110,18 @@
       break;
 
     case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
+      if (!input_parcel || !output_parcel) {
+        DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+        break;
+      }
       status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel);
       break;
 
     case qService::IQService::GET_PANEL_BRIGHTNESS: {
+        if (!output_parcel) {
+          DLOGE("QService command = %d: output_parcel needed.", command);
+          break;
+        }
         int level = 0;
         status = GetPanelBrightness(&level);
         output_parcel->writeInt32(level);
@@ -980,6 +1129,10 @@
       break;
 
     case qService::IQService::SET_PANEL_BRIGHTNESS: {
+        if (!input_parcel || !output_parcel) {
+          DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+          break;
+        }
         uint32_t level = UINT32(input_parcel->readInt32());
         status = setPanelBrightness(level);
         output_parcel->writeInt32(status);
@@ -987,16 +1140,28 @@
       break;
 
     case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
+      if (!input_parcel || !output_parcel) {
+        DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+        break;
+      }
       status = GetVisibleDisplayRect(input_parcel, output_parcel);
       break;
 
     case qService::IQService::SET_CAMERA_STATUS: {
+        if (!input_parcel) {
+          DLOGE("QService command = %d: input_parcel needed.", command);
+          break;
+        }
         uint32_t camera_status = UINT32(input_parcel->readInt32());
         status = setCameraLaunchStatus(camera_status);
       }
       break;
 
     case qService::IQService::GET_BW_TRANSACTION_STATUS: {
+        if (!output_parcel) {
+          DLOGE("QService command = %d: output_parcel needed.", command);
+          break;
+        }
         bool state = true;
         status = DisplayBWTransactionPending(&state);
         output_parcel->writeInt32(state);
@@ -1004,24 +1169,41 @@
       break;
 
     case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
       status = SetMixerResolution(input_parcel);
       break;
 
     case qService::IQService::SET_COLOR_MODE:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
       status = SetColorModeOverride(input_parcel);
       break;
 
     case qService::IQService::SET_COLOR_MODE_BY_ID:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
       status = SetColorModeById(input_parcel);
       break;
 
     case qService::IQService::GET_COMPOSER_STATUS:
+      if (!output_parcel) {
+        DLOGE("QService command = %d: output_parcel needed.", command);
+        break;
+      }
+      status = 0;
       output_parcel->writeInt32(getComposerStatus());
       break;
 
     default:
-      DLOGW("QService command = %d is not supported", command);
-      return -EINVAL;
+      DLOGW("QService command = %d is not supported.", command);
+      break;
   }
 
   return status;
@@ -1039,7 +1221,7 @@
   int error = android::BAD_VALUE;
   DisplayConfigVariableInfo display_attributes;
 
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
+  if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES || config < 0) {
     return android::BAD_VALUE;
   }
 
@@ -1065,6 +1247,11 @@
   uint32_t operation = UINT32(input_parcel->readInt32());
   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
 
+  if (!hwc_display) {
+    DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
+    return -ENODEV;
+  }
+
   switch (operation) {
     case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
       return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
@@ -1088,6 +1275,11 @@
 android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
+  if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
+    return -ENODEV;
+  }
+
   uint32_t mode = UINT32(input_parcel->readInt32());
   return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
 }
@@ -1096,65 +1288,56 @@
   DisplayError error = kErrorNone;
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
+  android::status_t status = 0;
 
-  if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
-    if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-      error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages);
-      if (error != kErrorNone) {
-        return -EINVAL;
+  for (uint32_t disp_id = HWC_DISPLAY_PRIMARY; disp_id < HWC_NUM_DISPLAY_TYPES; disp_id++) {
+    if (bit_mask_display_type[disp_id]) {
+      SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
+      if (hwc_display_[disp_id]) {
+        error = hwc_display_[disp_id]->SetMaxMixerStages(max_mixer_stages);
+        if (error != kErrorNone) {
+          status = -EINVAL;
+          continue;
+        }
+      } else {
+        DLOGW("Display = %d is not connected.", disp_id);
+        status = (status)? status : -ENODEV;  // Return higher priority error.
+        continue;
       }
     }
   }
 
-  if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]);
-    if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-      error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages);
-      if (error != kErrorNone) {
-        return -EINVAL;
-      }
-    }
-  }
-
-  if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
-    if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
-      error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages);
-      if (error != kErrorNone) {
-        return -EINVAL;
-      }
-    }
-  }
-
-  return 0;
+  return status;
 }
 
-void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
+android::status_t HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
   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());
+  android::status_t status = 0;
 
-  if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
-    if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-      hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+  for (uint32_t disp_id = HWC_DISPLAY_PRIMARY; disp_id < HWC_NUM_DISPLAY_TYPES; disp_id++) {
+    if (bit_mask_display_type[disp_id]) {
+      SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
+      if (hwc_display_[disp_id]) {
+        HWC2::Error error;
+        error = hwc_display_[disp_id]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+        if (HWC2::Error::None != error) {
+          if (HWC2::Error::NoResources == error)
+            status = -ENOMEM;
+          else
+            status = -EINVAL;
+          continue;
+        }
+      } else {
+        DLOGW("Display = %d is not connected.", disp_id);
+        status = (status)? status : -ENODEV;  // Return higher priority error.
+        continue;
+      }
     }
   }
 
-  if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]);
-    if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-      hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
-    }
-  }
-
-  if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
-    if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
-      hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
-    }
-  }
+  return status;
 }
 
 android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
@@ -1162,14 +1345,14 @@
   uint32_t dpy = UINT32(input_parcel->readInt32());
 
   if (dpy != HWC_DISPLAY_PRIMARY) {
-    DLOGI("Resoulution change not supported for this display %d", dpy);
+    DLOGW("Resolution change not supported for this display = %d", dpy);
     return -EINVAL;
   }
 
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    DLOGI("Primary display is not initialized");
-    return -EINVAL;
+    DLOGW("Primary display is not initialized");
+    return -ENODEV;
   }
 
   uint32_t width = UINT32(input_parcel->readInt32());
@@ -1188,6 +1371,10 @@
   auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32());
   auto device = static_cast<hwc2_device_t *>(this);
 
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return -EINVAL;
+  }
+
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   auto err = CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode);
   if (err != HWC2_ERROR_NONE)
@@ -1200,7 +1387,7 @@
   auto mode = input_parcel->readInt32();
   auto device = static_cast<hwc2_device_t *>(this);
 
-  if (display > HWC_DISPLAY_VIRTUAL) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
     return -EINVAL;
   }
 
@@ -1212,8 +1399,6 @@
 }
 
 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
-  // TODO(user): Do we really need a lock here?
-
   int type = input_parcel->readInt32();
   bool enable = (input_parcel->readInt32() > 0);
   DLOGI("type = %d enable = %d", type, enable);
@@ -1265,7 +1450,8 @@
   PPDisplayAPIPayload resp_payload, req_payload;
 
   if (!color_mgr_) {
-    return -1;
+    DLOGW("color_mgr_ not initialized.");
+    return -ENOENT;
   }
 
   pending_action.action = kNoAction;
@@ -1274,13 +1460,21 @@
   // Read display_id, payload_size and payload from in_parcel.
   ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload);
   if (!ret) {
-    if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY])
-      ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload, &resp_payload,
-                                                                    &pending_action);
+    if ((display_id >= HWC_NUM_DISPLAY_TYPES) || !hwc_display_[display_id]) {
+      DLOGW("Invalid display id or display = %d is not connected.", display_id);
+      ret = -ENODEV;
+    }
+  }
 
-    if (HWC_DISPLAY_EXTERNAL == display_id && hwc_display_[HWC_DISPLAY_EXTERNAL])
-      ret = hwc_display_[HWC_DISPLAY_EXTERNAL]->ColorSVCRequestRoute(req_payload, &resp_payload,
-                                                                     &pending_action);
+  if (!ret) {
+    if ((HWC_DISPLAY_PRIMARY == display_id) || (HWC_DISPLAY_EXTERNAL == display_id)) {
+      ret = hwc_display_[display_id]->ColorSVCRequestRoute(req_payload, &resp_payload,
+                                                           &pending_action);
+    } else {
+      // Virtual, Tertiary etc. not supported.
+      DLOGW("Operation not supported on display = %d.", display_id);
+      ret = -EINVAL;
+    }
   }
 
   if (ret) {
@@ -1290,7 +1484,14 @@
     return ret;
   }
 
-  switch (pending_action.action) {
+  if (kNoAction != pending_action.action) {
+    // Restrict pending actions to primary display.
+    if (HWC_DISPLAY_PRIMARY != display_id) {
+      DLOGW("Skipping pending action %d on display = %d.", pending_action.action, display_id);
+      pending_action.action = kNoAction;
+    }
+
+    switch (pending_action.action) {
     case kInvalidating:
       Refresh(HWC_DISPLAY_PRIMARY);
       break;
@@ -1314,10 +1515,10 @@
       brightness_value = reinterpret_cast<int32_t *>(resp_payload.payload);
       if (brightness_value == NULL) {
         DLOGE("Brightness value is Null");
-        return -EINVAL;
-      }
-      if (HWC_DISPLAY_PRIMARY == display_id)
+        ret = -EINVAL;
+      } else {
         ret = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(*brightness_value);
+      }
       break;
     case kEnableFrameCapture:
       ret = color_mgr_->SetFrameCapture(pending_action.params, true,
@@ -1338,6 +1539,7 @@
     default:
       DLOGW("Invalid pending action = %d!", pending_action.action);
       break;
+    }
   }
 
   // for display API getter case, marshall returned params into out_parcel.
@@ -1347,7 +1549,7 @@
   resp_payload.DestroyPayload();
   hwc_display_[display_id]->ResetValidation();
 
-  return (ret ? -EINVAL : 0);
+  return ret;
 }
 
 void HWCSession::UEventHandler(const char *uevent_data, int length) {
@@ -1391,18 +1593,27 @@
 
 void HWCSession::HandleExtHPD(const char *uevent_data, int length) {
   const char *pstr = GetTokenValue(uevent_data, length, "name=");
-  if (!pstr || (strcmp(pstr, "DP-1") != 0)) {
+  if (!pstr || (strncmp(pstr, "DP-1", strlen("DP-1")) != 0)) {
     return;
   }
 
   pstr = GetTokenValue(uevent_data, length, "status=");
   if (pstr) {
     bool connected = false;
-    if (strcmp(pstr, "connected") == 0) {
+    hpd_bpp_ = 0;
+    hpd_pattern_ = 0;
+    if (strncmp(pstr, "connected", strlen("connected")) == 0) {
       connected = true;
     }
+    int bpp = GetEventValue(uevent_data, length, "bpp=");
+    int pattern = GetEventValue(uevent_data, length, "pattern=");
+    if (bpp >=0 && pattern >= 0) {
+      hpd_bpp_ = bpp;
+      hpd_pattern_ = pattern;
+    }
 
-    DLOGI("Recived Ext HPD, connected:%d  status=%s", connected, pstr);
+    DLOGI("Recived Ext HPD, connected:%d  status=%s  bpp = %d pattern =%d ",
+          connected, pstr, hpd_bpp_, hpd_pattern_);
     HotPlugHandler(connected);
   }
 }
@@ -1460,8 +1671,7 @@
       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]);
+        status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false);
         notify_hotplug = true;
       }
 
@@ -1475,6 +1685,8 @@
         DLOGE("Primary display is not connected.");
         return -1;
       }
+
+      hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
     }
 
     if (connected) {
@@ -1544,7 +1756,7 @@
 android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                                     android::Parcel *output_parcel) {
   int dpy = input_parcel->readInt32();
-  if (dpy < HWC_DISPLAY_PRIMARY || dpy > HWC_DISPLAY_VIRTUAL) {
+  if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES) {
     return android::BAD_VALUE;
   }
 
@@ -1585,4 +1797,27 @@
   }
 }
 
+int HWCSession::CreateExternalDisplay(int disp_id, uint32_t primary_width,
+                                      uint32_t primary_height, bool use_primary_res) {
+  uint32_t panel_bpp = 0;
+  uint32_t pattern_type = 0;
+
+  if (GetDriverType() == DriverType::FB) {
+    qdutils::getDPTestConfig(&panel_bpp, &pattern_type);
+  } else {
+    panel_bpp = static_cast<uint32_t>(hpd_bpp_);
+    pattern_type = static_cast<uint32_t>(hpd_pattern_);
+  }
+
+  if (panel_bpp && pattern_type) {
+    return HWCDisplayExternalTest::Create(core_intf_, &buffer_allocator_, &callbacks_,
+                                          qservice_, panel_bpp, pattern_type,
+                                          &hwc_display_[disp_id]);
+  }
+
+  return  HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
+                                     primary_width, primary_height, qservice_,
+                                     use_primary_res, &hwc_display_[disp_id]);
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 18c652d..fe69515 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -78,6 +78,10 @@
   static int32_t CallDisplayFunction(hwc2_device_t *device, hwc2_display_t display,
                                      HWC2::Error (HWCDisplay::*member)(Args...), Args... args) {
     if (!device) {
+      return HWC2_ERROR_BAD_PARAMETER;
+    }
+
+    if (display >= HWC_NUM_DISPLAY_TYPES) {
       return HWC2_ERROR_BAD_DISPLAY;
     }
 
@@ -95,6 +99,10 @@
                                    hwc2_layer_t layer, HWC2::Error (HWCLayer::*member)(Args...),
                                    Args... args) {
     if (!device) {
+      return HWC2_ERROR_BAD_PARAMETER;
+    }
+
+    if (display >= HWC_NUM_DISPLAY_TYPES) {
       return HWC2_ERROR_BAD_DISPLAY;
     }
 
@@ -140,11 +148,7 @@
   static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
                                    const float *matrix, int32_t /*android_color_transform_t*/ hint);
 
-  // Meant to be called by HWCDisplay to preserve sequence of validate/present during events from
-  // polling thread
-  static void WaitForSequence(hwc2_display_t display) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
-  }
+  static Locker locker_[HWC_NUM_DISPLAY_TYPES];
 
  private:
   static const int kExternalConnectionTimeoutMs = 500;
@@ -174,6 +178,8 @@
   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);
+  int32_t CreateExternalDisplay(int disp_id, uint32_t primary_width, uint32_t primary_height,
+                                bool use_primary_res);
 
   // service methods
   void StartServices();
@@ -209,7 +215,7 @@
   virtual android::status_t notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                            android::Parcel *output_parcel);
   void DynamicDebug(const android::Parcel *input_parcel);
-  void SetFrameDumpConfig(const android::Parcel *input_parcel);
+  android::status_t 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 ConfigureRefreshRate(const android::Parcel *input_parcel);
@@ -228,7 +234,6 @@
   void Refresh(hwc2_display_t display);
   void HotPlug(hwc2_display_t display, HWC2::Connection state);
 
-  static Locker locker_[HWC_NUM_DISPLAY_TYPES];
   CoreInterface *core_intf_ = nullptr;
   HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
   HWCCallbacks callbacks_;
@@ -246,6 +251,8 @@
   bool hdmi_is_primary_ = false;
   bool is_composer_up_ = false;
   Locker callbacks_lock_;
+  int hpd_bpp_ = 0;
+  int hpd_pattern_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index a5cf66a..64ac57c 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -94,22 +94,25 @@
                                             isDisplayConnected_cb _hidl_cb) {
   int32_t error = -EINVAL;
   bool connected = false;
-
   int disp_id = MapDisplayType(dpy);
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
 
-  if (disp_id >= 0) {
-    connected = hwc_display_[disp_id];
-    error = 0;
+  if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
+    _hidl_cb(error, connected);
+    return Void();
   }
 
-  _hidl_cb(error, connected);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
 
+  connected = hwc_display_[disp_id];
+  error = 0;
+
+  _hidl_cb(error, connected);
   return Void();
 }
 
 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
-  if (disp_id < 0) {
+  if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
+    DLOGE("Invalid display = %d", disp_id);
     return -EINVAL;
   }
 
@@ -383,7 +386,8 @@
     return 0;
   }
 
-  return -EINVAL;
+  DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
+  return -ENODEV;
 }
 
 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
@@ -391,9 +395,14 @@
   int32_t error = -EINVAL;
   IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
 
+  if (!_hidl_cb) {
+    DLOGE("_hidl_cb callback not provided.");
+    return Void();
+  }
+
   do {
     int disp_id = MapDisplayType(dpy);
-    if (disp_id < 0) {
+    if ((disp_id < 0) || (disp_id >= HWC_NUM_DISPLAY_TYPES)) {
       DLOGE("Invalid display id = %d", disp_id);
       break;
     }
@@ -401,7 +410,8 @@
     SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
     HWCDisplay *hwc_display = hwc_display_[disp_id];
     if (!hwc_display) {
-      DLOGE("Display = %d is not connected.", disp_id);
+      DLOGW("Display = %d is not connected.", disp_id);
+      error = -ENODEV;
       break;
     }
 
@@ -439,6 +449,16 @@
 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
+  if (!core_intf_) {
+    DLOGW("core_intf_ not initialized.");
+    return -ENOENT;
+  }
+
+  if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
+    return -ENODEV;
+  }
+
   HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
 
   // trigger invalidate to apply new bw caps.
@@ -467,12 +487,18 @@
     return 0;
   }
 
-  return -EINVAL;
+  DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
+  return -ENODEV;
 }
 
 Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
   bool status = true;
 
+  if (!_hidl_cb) {
+      DLOGE("_hidl_cb callback not provided.");
+      return Void();
+  }
+
   int32_t error = DisplayBWTransactionPending(&status);
 
   _hidl_cb(error, status);