display: Move sde-drm to open source

- Update make file to compile sde-drm files.
- Update copyright and year of sde-drm files.

Change-Id: I8f3b60e79b0e8680e63bf4a076b43a30c5daf68b
CRs-Fixed: 2366253
diff --git a/Android.mk b/Android.mk
index e8cab37..214843c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,6 +8,7 @@
 endif
 
 display-hals += gralloc
+display-hals += sde-drm
 
 ifeq ($(call is-vendor-board-platform,QCOM),true)
     include $(call all-named-subdir-makefiles,$(display-hals))
diff --git a/sde-drm/Android.mk b/sde-drm/Android.mk
new file mode 100644
index 0000000..a2202bd
--- /dev/null
+++ b/sde-drm/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+common_header_export_path := qcom/display
+
+LOCAL_MODULE              := libsdedrm
+LOCAL_MODULE_TAGS         := optional
+LOCAL_SHARED_LIBRARIES    := libdrm libdrmutils libdisplaydebug
+LOCAL_HEADER_LIBRARIES    := display_headers display_proprietary_headers
+LOCAL_C_INCLUDES          := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include/ \
+                             -isystem external/libdrm
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_CFLAGS              := -Wno-missing-field-initializers -Wall -Werror -fno-operator-names \
+                             -Wno-unused-parameter -std=c++11 -DLOG_TAG=\"SDE_DRM\"
+LOCAL_CLANG               := true
+LOCAL_SRC_FILES           := drm_manager.cpp \
+                             drm_connector.cpp \
+                             drm_encoder.cpp \
+                             drm_crtc.cpp \
+                             drm_plane.cpp \
+                             drm_atomic_req.cpp \
+                             drm_utils.cpp \
+                             drm_pp_manager.cpp \
+                             drm_property.cpp \
+                             drm_dpps_mgr_imp.cpp
+
+ifeq ($(TARGET_USES_DRM_PP),true)
+LOCAL_CFLAGS              += -DPP_DRM_ENABLE
+endif
+
+ifeq ($(LLVM_SA), true)
+LOCAL_CFLAGS += --compile-and-analyze --analyzer-perf
+endif
+
+LOCAL_PROPRIETARY_MODULE  := true
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sde-drm/Makefile.am b/sde-drm/Makefile.am
new file mode 100644
index 0000000..6f48ed0
--- /dev/null
+++ b/sde-drm/Makefile.am
@@ -0,0 +1,23 @@
+AM_CFLAGS    = -Wno-missing-field-initializers -Wconversion \
+               -std=c++11 -DLOG_TAG=\"SDE_DRM\" -DUNIX_OS
+
+
+cpp_sources  = drm_manager.cpp \
+               drm_connector.cpp \
+               drm_crtc.cpp \
+               drm_plane.cpp \
+               drm_encoder.cpp \
+               drm_atomic_req.cpp \
+               drm_utils.cpp \
+               drm_pp_manager.cpp \
+               drm_property.cpp \
+               drm_dpps_mgr_imp.cpp
+
+
+lib_LTLIBRARIES = libsdedrm.la
+libsdedrm_la_CC = @CC@
+libsdedrm_la_SOURCES = $(cpp_sources)
+libsdedrm_la_CFLAGS = $(AM_CFLAGS) -DLOG_TAG=\"SDE_DRM\"
+libsdedrm_la_CPPFLAGS = $(AM_CPPFLAGS)
+libsdedrm_la_LIBADD = -ldrm -ldrmutils -ldisplaydebug
+libsdedrm_la_LDFLAGS = -shared -avoid-version
diff --git a/sde-drm/drm_atomic_req.cpp b/sde-drm/drm_atomic_req.cpp
new file mode 100644
index 0000000..74a7ce3
--- /dev/null
+++ b/sde-drm/drm_atomic_req.cpp
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <drm_logger.h>
+
+#include "drm_atomic_req.h"
+#include "drm_connector.h"
+#include "drm_crtc.h"
+#include "drm_manager.h"
+#include "drm_plane.h"
+#include "string.h"
+
+#define __CLASS__ "DRMAtomicReq"
+
+namespace sde_drm {
+
+DRMAtomicReq::DRMAtomicReq(int fd, DRMManager *drm_mgr) : drm_mgr_(drm_mgr), fd_(fd) {}
+
+DRMAtomicReq::~DRMAtomicReq() {
+  if (drm_atomic_req_) {
+    drmModeAtomicFree(drm_atomic_req_);
+    drm_atomic_req_ = nullptr;
+  }
+}
+
+int DRMAtomicReq::Init(const DRMDisplayToken &tok) {
+  token_ = tok;
+  drm_atomic_req_ = drmModeAtomicAlloc();
+  if (!drm_atomic_req_) {
+    return -ENOMEM;
+  }
+
+  return 0;
+}
+
+int DRMAtomicReq::Perform(DRMOps opcode, uint32_t obj_id, ...) {
+  va_list args;
+  va_start(args, obj_id);
+  switch (opcode) {
+    case DRMOps::PLANE_SET_SRC_RECT:
+    case DRMOps::PLANE_SET_DST_RECT:
+    case DRMOps::PLANE_SET_ZORDER:
+    case DRMOps::PLANE_SET_ROTATION:
+    case DRMOps::PLANE_SET_ALPHA:
+    case DRMOps::PLANE_SET_BLEND_TYPE:
+    case DRMOps::PLANE_SET_H_DECIMATION:
+    case DRMOps::PLANE_SET_V_DECIMATION:
+    case DRMOps::PLANE_SET_FB_ID:
+    case DRMOps::PLANE_SET_ROT_FB_ID:
+    case DRMOps::PLANE_SET_CRTC:
+    case DRMOps::PLANE_SET_SRC_CONFIG:
+    case DRMOps::PLANE_SET_INPUT_FENCE:
+    case DRMOps::PLANE_SET_SCALER_CONFIG:
+    case DRMOps::PLANE_SET_FB_SECURE_MODE:
+    case DRMOps::PLANE_SET_CSC_CONFIG:
+    case DRMOps::PLANE_SET_MULTIRECT_MODE:
+    case DRMOps::PLANE_SET_EXCL_RECT:
+    case DRMOps::PLANE_SET_INVERSE_PMA:
+    case DRMOps::PLANE_SET_DGM_CSC_CONFIG:
+    case DRMOps::PLANE_SET_POST_PROC: {
+      drm_mgr_->GetPlaneMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
+    } break;
+    case DRMOps::CRTC_SET_POST_PROC:
+    case DRMOps::CRTC_SET_MODE:
+    case DRMOps::CRTC_SET_ACTIVE:
+    case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET:
+    case DRMOps::CRTC_SET_CORE_CLK:
+    case DRMOps::CRTC_SET_CORE_AB:
+    case DRMOps::CRTC_SET_CORE_IB:
+    case DRMOps::CRTC_SET_LLCC_AB:
+    case DRMOps::CRTC_SET_LLCC_IB:
+    case DRMOps::CRTC_SET_DRAM_AB:
+    case DRMOps::CRTC_SET_DRAM_IB:
+    case DRMOps::CRTC_SET_ROT_PREFILL_BW:
+    case DRMOps::CRTC_SET_ROT_CLK:
+    case DRMOps::CRTC_GET_RELEASE_FENCE:
+    case DRMOps::CRTC_SET_ROI:
+    case DRMOps::CRTC_SET_SECURITY_LEVEL:
+    case DRMOps::CRTC_SET_SOLIDFILL_STAGES:
+    case DRMOps::CRTC_SET_IDLE_TIMEOUT:
+    case DRMOps::CRTC_SET_DEST_SCALER_CONFIG:
+    case DRMOps::CRTC_SET_CAPTURE_MODE:
+    case DRMOps::CRTC_SET_IDLE_PC_STATE: {
+      drm_mgr_->GetCrtcMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
+    } break;
+    case DRMOps::CONNECTOR_SET_CRTC:
+    case DRMOps::CONNECTOR_GET_RETIRE_FENCE:
+    case DRMOps::CONNECTOR_SET_OUTPUT_RECT:
+    case DRMOps::CONNECTOR_SET_OUTPUT_FB_ID:
+    case DRMOps::CONNECTOR_SET_POWER_MODE:
+    case DRMOps::CONNECTOR_SET_ROI:
+    case DRMOps::CONNECTOR_SET_AUTOREFRESH:
+    case DRMOps::CONNECTOR_SET_FB_SECURE_MODE:
+    case DRMOps::CONNECTOR_SET_POST_PROC:
+    case DRMOps::CONNECTOR_SET_HDR_METADATA:
+    case DRMOps::CONNECTOR_SET_QSYNC_MODE:
+    case DRMOps::CONNECTOR_SET_TOPOLOGY_CONTROL: {
+      drm_mgr_->GetConnectorMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
+    } break;
+    case DRMOps::DPPS_CACHE_FEATURE: {
+      drm_mgr_->GetDppsMgrIntf()->CacheDppsFeature(obj_id, args);
+    } break;
+    case DRMOps::DPPS_COMMIT_FEATURE: {
+      drm_mgr_->GetDppsMgrIntf()->CommitDppsFeatures(drm_atomic_req_, token_);
+    } break;
+    default:
+      DRM_LOGE("Invalid opcode %d", opcode);
+  }
+  va_end(args);
+  return 0;
+}
+
+int DRMAtomicReq::Validate() {
+  // Call UnsetUnusedPlanes to find planes that need to be unset. Do not call CommitPlaneState,
+  // because we just want to validate, not actually mark planes as removed
+  drm_mgr_->GetPlaneMgr()->UnsetUnusedPlanes(token_.crtc_id, drm_atomic_req_);
+  int ret = drmModeAtomicCommit(fd_, drm_atomic_req_,
+                                DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_TEST_ONLY, nullptr);
+  if (ret) {
+    DRM_LOGE("drmModeAtomicCommit failed with error %d (%s).", errno, strerror(errno));
+  }
+
+  drm_mgr_->GetPlaneMgr()->PostValidate(token_.crtc_id, !ret);
+  drm_mgr_->GetCrtcMgr()->PostValidate(token_.crtc_id, !ret);
+  drmModeAtomicSetCursor(drm_atomic_req_, 0);
+
+  return ret;
+}
+
+int DRMAtomicReq::Commit(bool synchronous, bool retain_planes) {
+  if (retain_planes) {
+    // It is not enough to simply avoid calling UnsetUnusedPlanes, since state transitons have to
+    // be correct when CommitPlaneState is called
+    drm_mgr_->GetPlaneMgr()->RetainPlanes(token_.crtc_id);
+  }
+
+  drm_mgr_->GetPlaneMgr()->UnsetUnusedPlanes(token_.crtc_id, drm_atomic_req_);
+  uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+
+  if (!synchronous) {
+    flags |= DRM_MODE_ATOMIC_NONBLOCK;
+  }
+
+  int ret = drmModeAtomicCommit(fd_, drm_atomic_req_, flags, nullptr);
+  if (ret) {
+    DRM_LOGE("drmModeAtomicCommit failed with error %d (%s).", errno, strerror(errno));
+  }
+
+  drm_mgr_->GetPlaneMgr()->PostCommit(token_.crtc_id, !ret);
+  drm_mgr_->GetCrtcMgr()->PostCommit(token_.crtc_id, !ret);
+  drmModeAtomicSetCursor(drm_atomic_req_, 0);
+
+  return ret;
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_atomic_req.h b/sde-drm/drm_atomic_req.h
new file mode 100644
index 0000000..f0a3dce
--- /dev/null
+++ b/sde-drm/drm_atomic_req.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2019, 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 __DRM_ATOMIC_REQ_H__
+#define __DRM_ATOMIC_REQ_H__
+
+#include <drm_interface.h>
+#include <drm_utils.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <vector>
+
+namespace sde_drm {
+
+class DRMManager;
+
+class DRMAtomicReq : public DRMAtomicReqInterface {
+ public:
+  DRMAtomicReq(int fd, DRMManager *drm_manager);
+  virtual ~DRMAtomicReq();
+  virtual int Perform(DRMOps op_code, uint32_t obj_id, ...);
+  virtual int Commit(bool synchronous, bool retain_planes);
+  virtual int Validate();
+  int Init(const DRMDisplayToken &tok);
+
+ private:
+  drmModeAtomicReq *drm_atomic_req_ = {};
+  DRMManager *drm_mgr_ = {};
+  int fd_ = -1;
+  DRMDisplayToken token_ = {};
+};
+
+}  // namespace sde_drm
+#endif  // __DRM_ATOMIC_REQ_H__
diff --git a/sde-drm/drm_connector.cpp b/sde-drm/drm_connector.cpp
new file mode 100644
index 0000000..5e8e811
--- /dev/null
+++ b/sde-drm/drm_connector.cpp
@@ -0,0 +1,769 @@
+/*
+* Copyright (c) 2019, 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 <stdint.h>
+#include <stdlib.h>
+#include <drm.h>
+#include <drm/sde_drm.h>
+#include <drm/msm_drm.h>
+#include <drm_logger.h>
+#include <errno.h>
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+#include <mutex>
+
+#include "drm_utils.h"
+#include "drm_property.h"
+#include "drm_connector.h"
+
+namespace sde_drm {
+
+using std::string;
+using std::stringstream;
+using std::pair;
+using std::vector;
+using std::unique_ptr;
+using std::map;
+using std::mutex;
+using std::lock_guard;
+
+static uint8_t ON = 0;
+static uint8_t DOZE = 1;
+static uint8_t DOZE_SUSPEND = 2;
+static uint8_t OFF = 5;
+
+// Connector FB Secure Modes
+static uint8_t NON_SECURE = 0;
+static uint8_t SECURE = 1;
+
+static uint8_t QSYNC_MODE_NONE = 0;
+static uint8_t QSYNC_MODE_CONTINUOUS = 1;
+
+static void PopulatePowerModes(drmModePropertyRes *prop) {
+  for (auto i = 0; i < prop->count_enums; i++) {
+    string enum_name(prop->enums[i].name);
+    if (enum_name == "ON") {
+      ON = prop->enums[i].value;
+    } else if (enum_name == "LP1") {
+      DOZE = prop->enums[i].value;
+    } else if (enum_name == "LP2") {
+      DOZE_SUSPEND = prop->enums[i].value;
+    } else if (enum_name == "OFF") {
+      OFF = prop->enums[i].value;
+    }
+  }
+}
+
+static void PopulateSecureModes(drmModePropertyRes *prop) {
+  for (auto i = 0; i < prop->count_enums; i++) {
+    string enum_name(prop->enums[i].name);
+    if (enum_name == "non_sec") {
+      NON_SECURE = prop->enums[i].value;
+    } else if (enum_name == "sec") {
+      SECURE = prop->enums[i].value;
+    }
+  }
+}
+
+static DRMTopology GetTopologyEnum(const string &topology) {
+  if (topology == "sde_singlepipe") return DRMTopology::SINGLE_LM;
+  if (topology == "sde_singlepipe_dsc") return DRMTopology::SINGLE_LM_DSC;
+  if (topology == "sde_dualpipe") return DRMTopology::DUAL_LM;
+  if (topology == "sde_dualpipe_dsc") return DRMTopology::DUAL_LM_DSC;
+  if (topology == "sde_dualpipemerge") return DRMTopology::DUAL_LM_MERGE;
+  if (topology == "sde_dualpipemerge_dsc") return DRMTopology::DUAL_LM_MERGE_DSC;
+  if (topology == "sde_dualpipe_dscmerge") return DRMTopology::DUAL_LM_DSCMERGE;
+  if (topology == "sde_ppsplit") return DRMTopology::PPSPLIT;
+  return DRMTopology::UNKNOWN;
+}
+
+static void PopulateQsyncModes(drmModePropertyRes *prop) {
+  for (auto i = 0; i < prop->count_enums; i++) {
+    string enum_name(prop->enums[i].name);
+    if (enum_name == "none") {
+      QSYNC_MODE_NONE = prop->enums[i].value;
+    } else if (enum_name == "continuous") {
+      QSYNC_MODE_CONTINUOUS = prop->enums[i].value;
+    }
+  }
+}
+
+#define __CLASS__ "DRMConnectorManager"
+
+void DRMConnectorManager::Init(drmModeRes *resource) {
+  lock_guard<mutex> lock(lock_);
+  for (int i = 0; i < resource->count_connectors; i++) {
+    unique_ptr<DRMConnector> conn(new DRMConnector(fd_));
+    drmModeConnector *libdrm_conn = drmModeGetConnector(fd_, resource->connectors[i]);
+    if (libdrm_conn) {
+      conn->InitAndParse(libdrm_conn);
+      connector_pool_[resource->connectors[i]] = std::move(conn);
+    } else {
+      DRM_LOGE("Critical error: drmModeGetConnector() failed for connector %d.",
+               resource->connectors[i]);
+    }
+  }
+}
+
+void DRMConnectorManager::Update() {
+  lock_guard<mutex> lock(lock_);
+  drmModeRes *resource = drmModeGetResources(fd_);
+
+  if (NULL == resource) {
+    DRM_LOGE("drmModeGetResources() failed. Connector status not updated.");
+    return;
+  }
+
+  // Build a map of the updated list of connector ids.
+  std::map<uint32_t, uint32_t> drm_connectors;
+  for (int i = 0; i < resource->count_connectors; i++) {
+    drm_connectors[resource->connectors[i]] = resource->connectors[i];
+  }
+
+  // Delete connectors in connector pool.
+  for (auto conn = connector_pool_.cbegin(); conn != connector_pool_.cend();) {
+    auto drmconn = drm_connectors.find(conn->first);
+    if (drmconn == drm_connectors.end()) {
+      // A DRM Connector in our pool was deleted.
+      if (conn->second->GetStatus() == DRMStatus::FREE) {
+        DRM_LOGD("Removing connector id %d from pool.", conn->first);
+        conn = connector_pool_.erase(conn);
+      } else {
+        // Physically removed DRM Connectors (displays) first go to disconnected state. When its
+        // reserved resources are freed up, they are removed from the driver's connector list. Do
+        // not remove DRM Connectors that are DRMStatus::BUSY.
+        DRM_LOGW("In-use connector id %d removed by DRM.", conn->first);
+        conn++;
+      }
+    } else {
+      // Remove DRM Connector present in both lists to ensure that only new connector ids remain.
+      drm_connectors.erase(drmconn);
+      conn++;
+    }
+  }
+
+  // Add new connectors in connector pool.
+  for (auto &drmconn : drm_connectors) {
+    DRM_LOGD("Adding connector id %d to pool.", drmconn.first);
+    unique_ptr<DRMConnector> conn(new DRMConnector(fd_));
+    drmModeConnector *libdrm_conn = drmModeGetConnector(fd_, drmconn.first);
+    if (libdrm_conn) {
+      conn->InitAndParse(libdrm_conn);
+      connector_pool_[drmconn.first] = std::move(conn);
+    } else {
+      DRM_LOGE("Critical error: drmModeGetConnector() failed for connector %d.", drmconn.first);
+    }
+  }
+
+  drmModeFreeResources(resource);
+}
+
+void DRMConnectorManager::DumpByID(uint32_t id) {
+  lock_guard<mutex> lock(lock_);
+  connector_pool_[id]->Dump();
+}
+
+void DRMConnectorManager::DumpAll() {
+  lock_guard<mutex> lock(lock_);
+  for (auto &conn : connector_pool_) {
+    conn.second->Dump();
+  }
+}
+
+void DRMConnectorManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req,
+                                  va_list args) {
+  lock_guard<mutex> lock(lock_);
+  auto it = connector_pool_.find(obj_id);
+  if (it == connector_pool_.end()) {
+    DRM_LOGE("Invalid connector id %d", obj_id);
+    return;
+  }
+
+  it->second->Perform(code, req, args);
+}
+
+int DRMConnectorManager::GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info) {
+  lock_guard<mutex> lock(lock_);
+  int ret = -ENODEV;
+  auto iter = connector_pool_.find(conn_id);
+
+  if (iter !=  connector_pool_.end()) {
+    ret = connector_pool_[conn_id]->GetInfo(info);
+  }
+
+  return ret;
+}
+
+void DRMConnectorManager::GetConnectorList(std::vector<uint32_t> *conn_ids) {
+  lock_guard<mutex> lock(lock_);
+  if (!conn_ids) {
+    DRM_LOGE("No output parameter provided.");
+    return;
+  }
+  conn_ids->clear();
+  for (auto &conn : connector_pool_) {
+    conn_ids->push_back(conn.first);
+  }
+}
+
+static bool IsTVConnector(uint32_t type) {
+  return (type == DRM_MODE_CONNECTOR_TV || type == DRM_MODE_CONNECTOR_HDMIA ||
+          type == DRM_MODE_CONNECTOR_HDMIB || type == DRM_MODE_CONNECTOR_DisplayPort ||
+          type == DRM_MODE_CONNECTOR_VGA);
+}
+
+int DRMConnectorManager::Reserve(DRMDisplayType disp_type, DRMDisplayToken *token) {
+  lock_guard<mutex> lock(lock_);
+  int ret = -ENODEV;
+  token->conn_id = 0;
+
+  for (auto &conn : connector_pool_) {
+    if (conn.second->GetStatus() == DRMStatus::FREE) {
+      uint32_t conn_type;
+      conn.second->GetType(&conn_type);
+      if ((disp_type == DRMDisplayType::PERIPHERAL && conn_type == DRM_MODE_CONNECTOR_DSI) ||
+          (disp_type == DRMDisplayType::VIRTUAL && conn_type == DRM_MODE_CONNECTOR_VIRTUAL) ||
+          (disp_type == DRMDisplayType::TV && IsTVConnector(conn_type))) {
+        if (conn.second->IsConnected()) {
+          // Free-up previously reserved connector, if any.
+          if (token->conn_id) {
+            connector_pool_[token->conn_id]->Unlock();
+          }
+          conn.second->Lock();
+          token->conn_id = conn.first;
+          ret = 0;
+          break;
+        } else {
+          // Hold on to the first reserved connector.
+          if (token->conn_id) {
+            continue;
+          }
+          // Prefer a connector that is connected. Continue search.
+          conn.second->Lock();
+          token->conn_id = conn.first;
+          ret = 0;
+        }
+      }
+    }
+  }
+
+  return ret;
+}
+
+int DRMConnectorManager::Reserve(uint32_t conn_id, DRMDisplayToken *token) {
+  lock_guard<mutex> lock(lock_);
+  int ret = -ENODEV;
+
+  auto iter = connector_pool_.find(conn_id);
+  if ((iter != connector_pool_.end()) && (iter->second->GetStatus() == DRMStatus::FREE)) {
+    iter->second->Lock();
+    token->conn_id = iter->first;
+    ret = 0;
+  }
+
+  return ret;
+}
+
+void DRMConnectorManager::Free(const DRMDisplayToken &token) {
+  lock_guard<mutex> lock(lock_);
+  connector_pool_[token.conn_id]->Unlock();
+}
+
+// ==============================================================================================//
+
+#undef __CLASS__
+#define __CLASS__ "DRMConnector"
+
+DRMConnector::~DRMConnector() {
+  if (drm_connector_) {
+    drmModeFreeConnector(drm_connector_);
+  }
+}
+
+void DRMConnector::ParseProperties() {
+  drmModeObjectProperties *props =
+      drmModeObjectGetProperties(fd_, drm_connector_->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+  if (!props || !props->props || !props->prop_values) {
+    drmModeFreeObjectProperties(props);
+    return;
+  }
+
+  for (uint32_t j = 0; j < props->count_props; j++) {
+    drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
+    if (!info) {
+      continue;
+    }
+
+    string property_name(info->name);
+    DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
+
+    if (prop_enum == DRMProperty::INVALID) {
+      DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
+      drmModeFreeProperty(info);
+      continue;
+    }
+
+    if (prop_enum == DRMProperty::LP) {
+      PopulatePowerModes(info);
+    } else if (prop_enum == DRMProperty::FB_TRANSLATION_MODE) {
+      PopulateSecureModes(info);
+    } else if (prop_enum == DRMProperty::QSYNC_MODE) {
+      PopulateQsyncModes(info);
+    }
+
+    prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
+    drmModeFreeProperty(info);
+  }
+
+  drmModeFreeObjectProperties(props);
+}
+
+void DRMConnector::ParseCapabilities(uint64_t blob_id, DRMConnectorInfo *info) {
+  drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+  if (!blob) {
+    return;
+  }
+
+  const char *fmt_str = reinterpret_cast<const char *>(blob->data);
+  stringstream stream(fmt_str);
+  string line = {};
+  const string display_type = "display type=";
+  const string panel_name = "panel name=";
+  const string panel_mode = "panel mode=";
+  const string dfps_support = "dfps support=";
+  const string pixel_formats = "pixel_formats=";
+  const string max_linewidth = "maxlinewidth=";
+  const string panel_orientation = "panel orientation=";
+  const string mdp_transfer_time_us = "mdp_transfer_time_us=";
+  const string qsync_support = "qsync support=";
+  const string wb_ubwc = "wb_ubwc";
+
+  while (std::getline(stream, line)) {
+    if (line.find(pixel_formats) != string::npos) {
+      vector<pair<uint32_t, uint64_t>> formats_supported;
+      ParseFormats(line.erase(0, pixel_formats.length()), &formats_supported);
+      info->formats_supported = move(formats_supported);
+    } else if (line.find(max_linewidth) != string::npos) {
+      info->max_linewidth = std::stoi(string(line, max_linewidth.length()));
+    } else if (line.find(display_type) != string::npos) {
+      info->is_primary = (string(line, display_type.length()) == "primary");
+    } else if (line.find(panel_name) != string::npos) {
+      info->panel_name = string(line, panel_name.length());
+    } else if (line.find(panel_mode) != string::npos) {
+      info->panel_mode = (string(line, panel_mode.length()) == "video") ? DRMPanelMode::VIDEO
+                                                                        : DRMPanelMode::COMMAND;
+    } else if (line.find(dfps_support) != string::npos) {
+      info->dynamic_fps = (string(line, dfps_support.length()) == "true");
+    } else if (line.find(panel_orientation) != string::npos) {
+      if (string(line, panel_orientation.length()) == "horz flip") {
+        info->panel_orientation = DRMRotation::FLIP_H;
+      } else if (string(line, panel_orientation.length()) == "vert flip") {
+        info->panel_orientation = DRMRotation::FLIP_V;
+      } else if (string(line, panel_orientation.length()) == "horz & vert flip") {
+        info->panel_orientation = DRMRotation::ROT_180;
+      }
+    } else if (line.find(mdp_transfer_time_us) != string::npos) {
+      info->transfer_time_us = std::stoi(string(line, mdp_transfer_time_us.length()));
+    } else if (line.find(qsync_support) != string::npos) {
+      info->qsync_support = (string(line, qsync_support.length()) == "true");
+    } else if (line.find(wb_ubwc) != string::npos) {
+      info->is_wb_ubwc_supported = true;
+    }
+  }
+
+  drmModeFreePropertyBlob(blob);
+}
+
+void DRMConnector::ParseCapabilities(uint64_t blob_id, drm_panel_hdr_properties *hdr_info) {
+  drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+  if (!blob) {
+    return;
+  }
+
+  struct drm_panel_hdr_properties *hdr_data = (struct drm_panel_hdr_properties*)(blob->data);
+
+  if (hdr_data) {
+    hdr_info->hdr_enabled = hdr_data->hdr_enabled;
+    hdr_info->peak_brightness = hdr_data->peak_brightness;
+    hdr_info->blackness_level = hdr_data->blackness_level;
+    for (int i = 0; i < DISPLAY_PRIMARIES_MAX; i++) {
+      hdr_info->display_primaries[i] = hdr_data->display_primaries[i];
+    }
+  }
+  drmModeFreePropertyBlob(blob);
+}
+
+void DRMConnector::ParseModeProperties(uint64_t blob_id, DRMConnectorInfo *info) {
+  drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+  if (!blob) {
+    return;
+  }
+
+  const char *fmt_str = reinterpret_cast<const char *>(blob->data);
+  stringstream stream(fmt_str);
+  string line = {};
+  const string mode_name = "mode_name=";
+  const string topology = "topology=";
+  const string pu_num_roi = "partial_update_num_roi=";
+  const string pu_xstart = "partial_update_xstart=";
+  const string pu_ystart = "partial_update_ystart=";
+  const string pu_walign = "partial_update_walign=";
+  const string pu_halign = "partial_update_halign=";
+  const string pu_wmin = "partial_update_wmin=";
+  const string pu_hmin = "partial_update_hmin=";
+  const string pu_roimerge = "partial_update_roimerge=";
+
+  // Map of parsed mode_name to mode_properties
+  map<string, DRMModeInfo> mode_props_map {};
+  auto it = mode_props_map.end();
+  while (std::getline(stream, line)) {
+    if (line.find(mode_name) != string::npos) {
+      string name(line, mode_name.length());
+      it = mode_props_map.insert(make_pair(name, DRMModeInfo())).first;
+    } else if (line.find(topology) != string::npos) {
+      it->second.topology = GetTopologyEnum(string(line, topology.length()));
+    } else if (line.find(pu_num_roi) != string::npos) {
+      it->second.num_roi = std::stoi(string(line, pu_num_roi.length()));
+    } else if (line.find(pu_xstart) != string::npos) {
+      it->second.xstart = std::stoi(string(line, pu_xstart.length()));
+    } else if (line.find(pu_ystart) != string::npos) {
+      it->second.ystart = std::stoi(string(line, pu_ystart.length()));
+    } else if (line.find(pu_walign) != string::npos) {
+      it->second.walign = std::stoi(string(line, pu_walign.length()));
+    } else if (line.find(pu_halign) != string::npos) {
+      it->second.halign = std::stoi(string(line, pu_halign.length()));
+    } else if (line.find(pu_wmin) != string::npos) {
+      it->second.wmin = std::stoi(string(line, pu_wmin.length()));
+    } else if (line.find(pu_hmin) != string::npos) {
+      it->second.hmin = std::stoi(string(line, pu_hmin.length()));
+    } else if (line.find(pu_roimerge) != string::npos) {
+      it->second.roi_merge = std::stoi(string(line, pu_roimerge.length()));
+    }
+  }
+
+  for (uint32_t i = 0; i < info->modes.size(); i++) {
+    DRMModeInfo &mode_item = info->modes.at(i);
+    auto it = mode_props_map.find(string(mode_item.mode.name));
+    if (it != mode_props_map.end()) {
+      mode_item.topology = it->second.topology;
+      mode_item.num_roi = it->second.num_roi;
+      mode_item.roi_merge = it->second.roi_merge;
+      mode_item.xstart = it->second.xstart;
+      mode_item.ystart = it->second.ystart;
+      mode_item.wmin = it->second.wmin;
+      mode_item.hmin = it->second.hmin;
+      mode_item.walign = it->second.walign;
+      mode_item.halign = it->second.halign;
+    }
+  }
+
+  drmModeFreePropertyBlob(blob);
+}
+
+void DRMConnector::ParseCapabilities(uint64_t blob_id, drm_msm_ext_hdr_properties *hdr_info) {
+  drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+  if (!blob) {
+    return;
+  }
+
+  struct drm_msm_ext_hdr_properties *hdr_cdata = (struct drm_msm_ext_hdr_properties*)(blob->data);
+
+  if(hdr_cdata) {
+   hdr_info->hdr_supported = hdr_cdata->hdr_supported;
+   hdr_info->hdr_eotf = hdr_cdata->hdr_eotf;
+   hdr_info->hdr_metadata_type_one = hdr_cdata->hdr_metadata_type_one;
+   hdr_info->hdr_max_luminance = hdr_cdata->hdr_max_luminance;
+   hdr_info->hdr_avg_luminance = hdr_cdata->hdr_avg_luminance;
+   hdr_info->hdr_min_luminance = hdr_cdata->hdr_min_luminance;
+   DRM_LOGI("hdr_supported=%d , hdr_eotf= %d , hdr_metadata_type_one= %d,"
+            "hdr_max_luminance= %d , hdr_avg_luminance= %d , hdr_min_luminance %d\n",
+            hdr_info->hdr_supported,hdr_info->hdr_eotf, hdr_info->hdr_metadata_type_one,
+            hdr_info->hdr_max_luminance, hdr_info->hdr_avg_luminance, hdr_info->hdr_min_luminance);
+  }
+  drmModeFreePropertyBlob(blob);
+}
+
+int DRMConnector::GetInfo(DRMConnectorInfo *info) {
+  // Reload each time since for some connectors like Virtual, modes may change
+  uint32_t conn_id = drm_connector_->connector_id;
+  drmModeConnectorPtr drm_connector = drmModeGetConnector(fd_, conn_id);
+  if (!drm_connector) {
+    // Connector resource not found. This could happen if a connector is removed before a commit was
+    // done on it. Mark the connector as disconnected for graceful teardown. Update 'info' with
+    // basic information from previously initialized drm_connector_ for graceful teardown.
+    info->is_connected = false;
+    info->modes.clear();
+    info->type = drm_connector_->connector_type;
+    DLOGW("Connector %u not found. Possibly removed.", conn_id);
+    return 0;
+  }
+
+  drmModeFreeConnector(drm_connector_);
+  drm_connector_ = drm_connector;
+
+  info->modes.clear();
+  if (!drm_connector_->count_modes) {
+    DRM_LOGW("Zero modes on connector %u.", conn_id);
+  }
+  for (auto i = 0; i < drm_connector_->count_modes; i++) {
+    DRMModeInfo modes_item {};
+    modes_item.mode = drm_connector_->modes[i];
+    info->modes.push_back(modes_item);
+  }
+  info->mmWidth = drm_connector_->mmWidth;
+  info->mmHeight = drm_connector_->mmHeight;
+  info->type = drm_connector_->connector_type;
+  info->is_connected = IsConnected();
+
+  drmModeObjectProperties *props =
+      drmModeObjectGetProperties(fd_, drm_connector_->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+  if (!props || !props->props || !props->prop_values) {
+    drmModeFreeObjectProperties(props);
+    return -ENODEV;
+  }
+
+  uint32_t index = UINT32_MAX;
+
+  if (prop_mgr_.IsPropertyAvailable(DRMProperty::HDR_PROPERTIES)) {
+    index = std::distance(props->props,
+                          std::find(props->props, props->props + props->count_props,
+                                    prop_mgr_.GetPropertyId(DRMProperty::HDR_PROPERTIES)));
+    if (index < props->count_props)
+      ParseCapabilities(props->prop_values[index], &info->panel_hdr_prop);
+  }
+
+  if (prop_mgr_.IsPropertyAvailable(DRMProperty::CAPABILITIES)) {
+    index = std::distance(props->props,
+                          std::find(props->props, props->props + props->count_props,
+                                    prop_mgr_.GetPropertyId(DRMProperty::CAPABILITIES)));
+    if (index < props->count_props)
+      ParseCapabilities(props->prop_values[index], info);
+  }
+
+  if (prop_mgr_.IsPropertyAvailable(DRMProperty::MODE_PROPERTIES)) {
+    index = std::distance(props->props,
+                          std::find(props->props, props->props + props->count_props,
+                                    prop_mgr_.GetPropertyId(DRMProperty::MODE_PROPERTIES)));
+    if (index < props->count_props)
+      ParseModeProperties(props->prop_values[index], info);
+  }
+
+  if (prop_mgr_.IsPropertyAvailable(DRMProperty::EXT_HDR_PROPERTIES)) {
+    index = std::distance(props->props,
+                          std::find(props->props, props->props + props->count_props,
+                                    prop_mgr_.GetPropertyId(DRMProperty::EXT_HDR_PROPERTIES)));
+    if (index < props->count_props)
+      ParseCapabilities(props->prop_values[index], &info->ext_hdr_prop);
+  }
+
+  if (prop_mgr_.IsPropertyAvailable(DRMProperty::TOPOLOGY_CONTROL)) {
+    index = std::distance(props->props,
+                          std::find(props->props, props->props + props->count_props,
+                                    prop_mgr_.GetPropertyId(DRMProperty::TOPOLOGY_CONTROL)));
+    info->topology_control = props->prop_values[index];
+  }
+
+  drmModeFreeObjectProperties(props);
+
+  return 0;
+}
+
+void DRMConnector::InitAndParse(drmModeConnector *conn) {
+  drm_connector_ = conn;
+  ParseProperties();
+  pp_mgr_ = std::unique_ptr<DRMPPManager>(new DRMPPManager(fd_));
+  pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_CONNECTOR);
+}
+
+void DRMConnector::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
+  uint32_t obj_id = drm_connector_->connector_id;
+
+  switch (code) {
+    case DRMOps::CONNECTOR_SET_CRTC: {
+      uint32_t crtc = va_arg(args, uint32_t);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::CRTC_ID), crtc);
+      DRM_LOGD("Connector %d: Setting CRTC %d", obj_id, crtc);
+    } break;
+
+    case DRMOps::CONNECTOR_GET_RETIRE_FENCE: {
+      int64_t *fence = va_arg(args, int64_t *);
+      *fence = -1;
+      uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::RETIRE_FENCE);
+      drmModeAtomicAddProperty(req, obj_id, prop_id, reinterpret_cast<uint64_t>(fence));
+    } break;
+
+    case DRMOps::CONNECTOR_SET_OUTPUT_RECT: {
+      DRMRect rect = va_arg(args, DRMRect);
+      drmModeAtomicAddProperty(req, obj_id,
+                               prop_mgr_.GetPropertyId(DRMProperty::DST_X), rect.left);
+      drmModeAtomicAddProperty(req, obj_id,
+                               prop_mgr_.GetPropertyId(DRMProperty::DST_Y), rect.top);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::DST_W),
+                               rect.right - rect.left);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::DST_H),
+                               rect.bottom - rect.top);
+      DRM_LOGD("Connector %d: Setting dst [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
+                  rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
+    } break;
+
+    case DRMOps::CONNECTOR_SET_OUTPUT_FB_ID: {
+      uint32_t fb_id = va_arg(args, uint32_t);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::FB_ID), fb_id);
+      DRM_LOGD("Connector %d: Setting fb_id %d", obj_id, fb_id);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_POWER_MODE: {
+      int drm_power_mode = va_arg(args, int);
+      uint32_t power_mode = ON;
+      switch (drm_power_mode) {
+        case (int)DRMPowerMode::ON:
+          power_mode = ON;
+          break;
+        case (int)DRMPowerMode::DOZE:
+          power_mode = DOZE;
+          break;
+        case (int)DRMPowerMode::DOZE_SUSPEND:
+          power_mode = DOZE_SUSPEND;
+          break;
+        case (int)DRMPowerMode::OFF:
+          power_mode = OFF;
+          break;
+        default:
+          DRM_LOGE("Invalid power mode %d to set on connector %d", drm_power_mode, obj_id);
+          break;
+      }
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::LP), power_mode);
+      DRM_LOGD("Connector %d: Setting power_mode %d", obj_id, power_mode);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_ROI: {
+      uint32_t num_roi = va_arg(args, uint32_t);
+      DRMRect *conn_rois = va_arg(args, DRMRect*);
+      SetROI(req, obj_id, num_roi, conn_rois);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_AUTOREFRESH: {
+      uint32_t enable = va_arg(args, uint32_t);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::AUTOREFRESH),
+                               enable);
+      DRM_LOGD("Connector %d: Setting autorefresh %d", obj_id, enable);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_FB_SECURE_MODE: {
+      int secure_mode = va_arg(args, int);
+      uint32_t fb_secure_mode = (secure_mode == (int)DRMSecureMode::SECURE) ? SECURE : NON_SECURE;
+      drmModeAtomicAddProperty(req, obj_id,
+                               prop_mgr_.GetPropertyId(DRMProperty::FB_TRANSLATION_MODE),
+                               fb_secure_mode);
+      DRM_LOGD("Connector %d: Setting FB secure mode %d", obj_id, fb_secure_mode);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_POST_PROC: {
+      DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
+      if (data)
+        pp_mgr_->SetPPFeature(req, obj_id, *data);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_HDR_METADATA: {
+      drm_msm_ext_hdr_metadata *hdr_metadata = va_arg(args, drm_msm_ext_hdr_metadata *);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::HDR_METADATA),
+                               reinterpret_cast<uint64_t>(hdr_metadata));
+    } break;
+
+    case DRMOps::CONNECTOR_SET_QSYNC_MODE: {
+      if (!prop_mgr_.IsPropertyAvailable(DRMProperty::QSYNC_MODE)) {
+        return;
+      }
+      int drm_qsync_mode = va_arg(args, int);
+      uint32_t qsync_mode =
+        (drm_qsync_mode == (int)DRMQsyncMode::NONE) ? QSYNC_MODE_NONE : QSYNC_MODE_CONTINUOUS;
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::QSYNC_MODE),
+                               qsync_mode);
+      DRM_LOGD("Connector %d: Setting Qsync mode %d", obj_id, qsync_mode);
+    } break;
+
+    case DRMOps::CONNECTOR_SET_TOPOLOGY_CONTROL: {
+      uint32_t topology_control = va_arg(args, uint32_t);
+      drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::TOPOLOGY_CONTROL),
+                               topology_control);
+    } break;
+
+    default:
+      DRM_LOGE("Invalid opcode %d to set on connector %d", code, obj_id);
+      break;
+  }
+}
+
+void DRMConnector::SetROI(drmModeAtomicReq *req, uint32_t obj_id, uint32_t num_roi,
+                          DRMRect *conn_rois) {
+#ifdef SDE_MAX_ROI_V1
+  if (!num_roi || num_roi > SDE_MAX_ROI_V1 ||
+      !prop_mgr_.IsPropertyAvailable(DRMProperty::ROI_V1)) {
+    return;
+  }
+
+  static struct sde_drm_roi_v1 roi_v1 {};
+  roi_v1.num_rects = num_roi;
+
+  for (uint32_t i = 0; i < num_roi; i++) {
+    roi_v1.roi[i].x1 = conn_rois[i].left;
+    roi_v1.roi[i].x2 = conn_rois[i].right;
+    roi_v1.roi[i].y1 = conn_rois[i].top;
+    roi_v1.roi[i].y2 = conn_rois[i].bottom;
+    DRM_LOGD("Conn %d, ROI[l,t,b,r][%d %d %d %d]", obj_id,
+             roi_v1.roi[i].x1,roi_v1.roi[i].y1,roi_v1.roi[i].x2,roi_v1.roi[i].y2);
+  }
+  drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::ROI_V1),
+                           reinterpret_cast<uint64_t>(&roi_v1));
+#endif
+}
+
+void DRMConnector::Dump() {
+  DRM_LOGE("id: %d\tenc_id: %d\tconn: %d\ttype: %d\tPhy: %dx%d\n", drm_connector_->connector_id,
+           drm_connector_->encoder_id, drm_connector_->connection, drm_connector_->connector_type,
+           drm_connector_->mmWidth, drm_connector_->mmHeight);
+  DRM_LOGE("Modes: \n");
+  for (uint32_t i = 0; i < (uint32_t)drm_connector_->count_modes; i++) {
+    DRM_LOGE(
+        "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",
+        drm_connector_->modes[i].name, drm_connector_->modes[i].vrefresh,
+        drm_connector_->modes[i].hdisplay, drm_connector_->modes[i].hsync_start,
+        drm_connector_->modes[i].hsync_end, drm_connector_->modes[i].htotal,
+        drm_connector_->modes[i].vdisplay, drm_connector_->modes[i].vsync_start,
+        drm_connector_->modes[i].vsync_end, drm_connector_->modes[i].vtotal);
+  }
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_connector.h b/sde-drm/drm_connector.h
new file mode 100644
index 0000000..f947f73
--- /dev/null
+++ b/sde-drm/drm_connector.h
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2019, 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 __DRM_CONNECTOR_H__
+#define __DRM_CONNECTOR_H__
+
+#include <drm_interface.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <map>
+#include <memory>
+#include <memory>
+#include <drm/msm_drm.h>
+#include <mutex>
+#include "drm_pp_manager.h"
+
+#include "drm_utils.h"
+#include "drm_property.h"
+
+namespace sde_drm {
+
+class DRMConnector {
+ public:
+  explicit DRMConnector(int fd) : fd_(fd) {}
+  ~DRMConnector();
+  void InitAndParse(drmModeConnector *conn);
+  void Lock() { status_ = DRMStatus::BUSY; }
+  void Unlock() { status_ = DRMStatus::FREE; }
+  DRMStatus GetStatus() { return status_; }
+  int GetInfo(DRMConnectorInfo *info);
+  void GetType(uint32_t *conn_type) { *conn_type = drm_connector_->connector_type; }
+  void Perform(DRMOps code, drmModeAtomicReq *req, va_list args);
+  int IsConnected() { return (DRM_MODE_CONNECTED == drm_connector_->connection); }
+  void Dump();
+
+ private:
+  void ParseProperties();
+  void ParseCapabilities(uint64_t blob_id, DRMConnectorInfo *info);
+  void ParseCapabilities(uint64_t blob_id, drm_panel_hdr_properties *hdr_info);
+  void ParseModeProperties(uint64_t blob_id, DRMConnectorInfo *info);
+  void ParseCapabilities(uint64_t blob_id, drm_msm_ext_hdr_properties *hdr_info);
+  void SetROI(drmModeAtomicReq *req, uint32_t obj_id, uint32_t num_roi,
+              DRMRect *conn_rois);
+
+  int fd_ = -1;
+  drmModeConnector *drm_connector_ = {};
+  DRMPropertyManager prop_mgr_ {};
+  DRMStatus status_ = DRMStatus::FREE;
+  std::unique_ptr<DRMPPManager> pp_mgr_{};
+};
+
+class DRMConnectorManager {
+ public:
+  explicit DRMConnectorManager(int fd) : fd_(fd) {}
+  void Init(drmModeRes *res);
+  void Update();
+  void DeInit() {}
+  void DumpAll();
+  void DumpByID(uint32_t id);
+  int Reserve(DRMDisplayType disp_type, DRMDisplayToken *token);
+  int Reserve(uint32_t conn_id, DRMDisplayToken *token);
+  void Free(const DRMDisplayToken &token);
+  void Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args);
+  int GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info);
+  void GetConnectorList(std::vector<uint32_t> *conn_ids);
+  ~DRMConnectorManager() {}
+
+ private:
+  int fd_ = -1;
+  std::mutex lock_;
+  // Map of connector id to DRMConnector *
+  std::map<uint32_t, std::unique_ptr<DRMConnector>> connector_pool_{};
+};
+
+}  // namespace sde_drm
+
+#endif  // __DRM_CONNECTOR_H__
diff --git a/sde-drm/drm_crtc.cpp b/sde-drm/drm_crtc.cpp
new file mode 100644
index 0000000..d5b6734
--- /dev/null
+++ b/sde-drm/drm_crtc.cpp
@@ -0,0 +1,799 @@
+/*
+* Copyright (c) 2019, 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 <stdint.h>
+#include <stdlib.h>
+#include <drm.h>
+#include <drm/sde_drm.h>
+#include <drm_logger.h>
+#include <drm/drm_fourcc.h>
+
+#include <algorithm>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <utility>
+
+#include "drm_utils.h"
+#include "drm_crtc.h"
+#include "drm_property.h"
+
+namespace sde_drm {
+
+using std::string;
+using std::stringstream;
+using std::unique_ptr;
+using std::map;
+
+// CRTC Security Levels
+static uint8_t SECURE_NON_SECURE = 0;
+static uint8_t SECURE_ONLY = 1;
+
+// CWB Capture Modes
+static uint8_t CAPTURE_MIXER_OUT = 0;
+static uint8_t CAPTURE_DSPP_OUT = 1;
+
+// Idle PC states
+static uint8_t IDLE_PC_STATE_NONE = 0;
+static uint8_t IDLE_PC_STATE_ENABLE = 1;
+static uint8_t IDLE_PC_STATE_DISABLE = 2;
+
+static void PopulateSecurityLevels(drmModePropertyRes *prop) {
+  static bool security_levels_populated = false;
+  if (!security_levels_populated) {
+    for (auto i = 0; i < prop->count_enums; i++) {
+      string enum_name(prop->enums[i].name);
+      if (enum_name == "sec_and_non_sec") {
+        SECURE_NON_SECURE = prop->enums[i].value;
+      } else if (enum_name == "sec_only") {
+        SECURE_ONLY = prop->enums[i].value;
+      }
+    }
+    security_levels_populated = true;
+  }
+}
+
+static void PopulateCWbCaptureModes(drmModePropertyRes *prop) {
+  static bool capture_modes_populated = false;
+  if (!capture_modes_populated) {
+    for (auto i = 0; i < prop->count_enums; i++) {
+      string enum_name(prop->enums[i].name);
+      if (enum_name == "capture_mixer_out") {
+        CAPTURE_MIXER_OUT = prop->enums[i].value;
+      } else if (enum_name == "capture_pp_out") {
+        CAPTURE_DSPP_OUT = prop->enums[i].value;
+      }
+    }
+    capture_modes_populated = true;
+  }
+}
+
+static void PopulateIdlePCStates(drmModePropertyRes *prop) {
+  static bool idle_pc_state_populated = false;
+  if (!idle_pc_state_populated) {
+    for (auto i = 0; i < prop->count_enums; i++) {
+      string enum_name(prop->enums[i].name);
+      if (enum_name == "idle_pc_none") {
+        IDLE_PC_STATE_NONE = prop->enums[i].value;
+      } else if (enum_name == "idle_pc_enable") {
+        IDLE_PC_STATE_ENABLE = prop->enums[i].value;
+      } else if (enum_name == "idle_pc_disable") {
+        IDLE_PC_STATE_DISABLE = prop->enums[i].value;
+      }
+    }
+    idle_pc_state_populated = true;
+  }
+}
+
+#define __CLASS__ "DRMCrtcManager"
+
+void DRMCrtcManager::Init(drmModeRes *resource) {
+  for (int i = 0; i < resource->count_crtcs; i++) {
+    unique_ptr<DRMCrtc> crtc(new DRMCrtc(fd_, i));
+    drmModeCrtc *libdrm_crtc = drmModeGetCrtc(fd_, resource->crtcs[i]);
+    if (libdrm_crtc) {
+      crtc->InitAndParse(libdrm_crtc);
+      crtc_pool_[resource->crtcs[i]] = std::move(crtc);
+    } else {
+      DRM_LOGE("Critical error: drmModeGetCrtc() failed for crtc %d.", resource->crtcs[i]);
+    }
+  }
+}
+
+void DRMCrtcManager::DumpByID(uint32_t id) {
+  crtc_pool_.at(id)->Dump();
+}
+
+void DRMCrtcManager::DumpAll() {
+  for (auto &crtc : crtc_pool_) {
+    crtc.second->Dump();
+  }
+}
+
+void DRMCrtcManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req,
+                             va_list args) {
+  auto it = crtc_pool_.find(obj_id);
+  if (it == crtc_pool_.end()) {
+    DRM_LOGE("Invalid crtc id %d", obj_id);
+    return;
+  }
+
+  if (code == DRMOps::CRTC_SET_DEST_SCALER_CONFIG) {
+    if (crtc_pool_.at(obj_id)->ConfigureScalerLUT(req, dir_lut_blob_id_, cir_lut_blob_id_,
+                                                  sep_lut_blob_id_)) {
+      DRM_LOGD("CRTC %d: Configuring scaler LUTs", obj_id);
+    }
+  }
+
+  it->second->Perform(code, req, args);
+}
+
+void DRMCrtcManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
+  // qseed3lite lut is hardcoded in HW. No need to program from sw.
+  DRMCrtcInfo info;
+  crtc_pool_.begin()->second->GetInfo(&info);
+  if (info.qseed_version == QSEEDVersion::V3LITE) {
+    return;
+  }
+
+  if (lut_info.dir_lut_size) {
+    drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.dir_lut),
+                              lut_info.dir_lut_size, &dir_lut_blob_id_);
+  }
+  if (lut_info.cir_lut_size) {
+    drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.cir_lut),
+                              lut_info.cir_lut_size, &cir_lut_blob_id_);
+  }
+  if (lut_info.sep_lut_size) {
+    drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.sep_lut),
+                              lut_info.sep_lut_size, &sep_lut_blob_id_);
+  }
+}
+
+void DRMCrtcManager::UnsetScalerLUT() {
+  if (dir_lut_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_);
+    dir_lut_blob_id_ = 0;
+  }
+  if (cir_lut_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_);
+    cir_lut_blob_id_ = 0;
+  }
+  if (sep_lut_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_);
+    sep_lut_blob_id_ = 0;
+  }
+}
+
+int DRMCrtcManager::GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info) {
+  if (crtc_id == 0) {
+    crtc_pool_.begin()->second->GetInfo(info);
+  } else {
+    auto iter = crtc_pool_.find(crtc_id);
+    if (iter ==  crtc_pool_.end()) {
+      DRM_LOGE("Invalid crtc id %d", crtc_id);
+      return -ENODEV;
+    } else {
+      iter->second->GetInfo(info);
+    }
+  }
+
+  return 0;
+}
+
+void DRMCrtcManager::GetPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info) {
+  auto it = crtc_pool_.find(crtc_id);
+  if (it == crtc_pool_.end()) {
+    DRM_LOGE("Invalid crtc id %d", crtc_id);
+    return;
+  }
+
+  it->second->GetPPInfo(info);
+}
+
+int DRMCrtcManager::Reserve(DRMDisplayType disp_type, DRMDisplayToken *token) {
+  for (auto &item : crtc_pool_) {
+    if (item.second->GetStatus() == DRMStatus::FREE) {
+      item.second->Lock();
+      token->crtc_id = item.first;
+      token->crtc_index = item.second->GetIndex();
+      return 0;
+    }
+  }
+
+  return -ENODEV;
+}
+
+int DRMCrtcManager::Reserve(int32_t display_id, DRMDisplayToken *token) {
+  // Neither display type nor display id is currently used in CRTC reservation.
+  return Reserve(DRMDisplayType::PERIPHERAL, token);
+}
+
+void DRMCrtcManager::Free(const DRMDisplayToken &token) {
+  crtc_pool_.at(token.crtc_id)->Unlock();
+}
+
+void DRMCrtcManager::PostValidate(uint32_t crtc_id, bool success) {
+  crtc_pool_.at(crtc_id)->PostValidate(success);
+}
+
+void DRMCrtcManager::PostCommit(uint32_t crtc_id, bool success) {
+  crtc_pool_.at(crtc_id)->PostCommit(success);
+}
+
+// ==============================================================================================//
+
+#undef __CLASS__
+#define __CLASS__ "DRMCrtc"
+
+DRMCrtc::~DRMCrtc() {
+  if (drm_crtc_) {
+    drmModeFreeCrtc(drm_crtc_);
+  }
+}
+
+void DRMCrtc::ParseProperties() {
+  drmModeObjectProperties *props =
+    drmModeObjectGetProperties(fd_, drm_crtc_->crtc_id, DRM_MODE_OBJECT_CRTC);
+  if (!props || !props->props || !props->prop_values) {
+    drmModeFreeObjectProperties(props);
+    return;
+  }
+
+  for (uint32_t j = 0; j < props->count_props; j++) {
+    drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
+    if (!info) {
+      continue;
+    }
+
+    string property_name(info->name);
+    DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
+    if (prop_enum == DRMProperty::INVALID) {
+      DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
+      drmModeFreeProperty(info);
+      continue;
+    }
+
+    if (prop_enum == DRMProperty::SECURITY_LEVEL) {
+      PopulateSecurityLevels(info);
+    }
+
+    if (prop_enum == DRMProperty::CAPTURE_MODE) {
+      crtc_info_.concurrent_writeback = true;
+      PopulateCWbCaptureModes(info);
+    }
+
+    if (prop_enum == DRMProperty::IDLE_PC_STATE) {
+      PopulateIdlePCStates(info);
+    }
+
+    prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
+    if (prop_enum == DRMProperty::CAPABILITIES) {
+      ParseCapabilities(props->prop_values[j]);
+    }
+    drmModeFreeProperty(info);
+  }
+
+  drmModeFreeObjectProperties(props);
+}
+
+void DRMCrtc::ParseCapabilities(uint64_t blob_id) {
+  drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+  if (!blob) {
+    return;
+  }
+
+  const char *fmt_str = reinterpret_cast<const char *>(blob->data);
+  stringstream stream(fmt_str);
+  string line = {};
+  string max_blendstages = "max_blendstages=";
+  string qseed_type = "qseed_type=";
+  string has_src_split = "has_src_split=";
+  string sdma_rev = "smart_dma_rev=";
+  string core_ib_ff = "core_ib_ff=";
+  string dest_scale_prefill_lines = "dest_scale_prefill_lines=";
+  string undersized_prefill_lines = "undersized_prefill_lines=";
+  string macrotile_prefill_lines = "macrotile_prefill_lines=";
+  string yuv_nv12_prefill_lines = "yuv_nv12_prefill_lines=";
+  string linear_prefill_lines = "linear_prefill_lines=";
+  string downscaling_prefill_lines = "downscaling_prefill_lines=";
+  string xtra_prefill_lines = "xtra_prefill_lines=";
+  string amortizable_threshold = "amortizable_threshold=";
+  string max_bandwidth_low = "max_bandwidth_low=";
+  string max_bandwidth_high = "max_bandwidth_high=";
+  string max_mdp_clk = "max_mdp_clk=";
+  string core_clk_ff = "core_clk_ff=";
+  string comp_ratio_rt = "comp_ratio_rt=";
+  string comp_ratio_nrt = "comp_ratio_nrt=";
+  string hw_version = "hw_version=";
+  string solidfill_stages = "dim_layer_v1_max_layers=";
+  string has_hdr = "has_hdr=";
+  string min_prefill_lines = "min_prefill_lines=";
+
+  crtc_info_.max_solidfill_stages = 0;  // default _
+  string dest_scaler_count = "dest_scaler_count=";
+  string max_dest_scale_up = "max_dest_scale_up=";
+  string max_dest_scaler_input_width = "max_dest_scaler_input_width=";
+  string max_dest_scaler_output_width = "max_dest_scaler_output_width=";
+  string sec_ui_blendstage = "sec_ui_blendstage=";
+
+  while (std::getline(stream, line)) {
+    if (line.find(max_blendstages) != string::npos) {
+      crtc_info_.max_blend_stages = std::stoi(string(line, max_blendstages.length()));
+    } else if (line.find(qseed_type) != string::npos) {
+      if (string(line, qseed_type.length()) == "qseed2") {
+        crtc_info_.qseed_version = QSEEDVersion::V2;
+      } else if (string(line, qseed_type.length()) == "qseed3") {
+        crtc_info_.qseed_version = QSEEDVersion::V3;
+      } else if (string(line, qseed_type.length()) == "qseed3lite") {
+        crtc_info_.qseed_version = QSEEDVersion::V3LITE;
+      }
+    } else if (line.find(has_src_split) != string::npos) {
+      crtc_info_.has_src_split = std::stoi(string(line, has_src_split.length()));
+    } else if (line.find(sdma_rev) != string::npos) {
+      if (string(line, sdma_rev.length()) == "smart_dma_v2p5")
+        crtc_info_.smart_dma_rev = SmartDMARevision::V2p5;
+      else if (string(line, sdma_rev.length()) == "smart_dma_v2")
+        crtc_info_.smart_dma_rev = SmartDMARevision::V2;
+      else if (string(line, sdma_rev.length()) == "smart_dma_v1")
+        crtc_info_.smart_dma_rev = SmartDMARevision::V1;
+    } else if (line.find(core_ib_ff) != string::npos) {
+      crtc_info_.ib_fudge_factor = std::stof(string(line, core_ib_ff.length()));
+    } else if (line.find(dest_scale_prefill_lines) != string::npos) {
+      crtc_info_.dest_scale_prefill_lines =
+        std::stoi(string(line, dest_scale_prefill_lines.length()));
+    } else if (line.find(undersized_prefill_lines) != string::npos) {
+      crtc_info_.undersized_prefill_lines =
+        std::stoi(string(line, undersized_prefill_lines.length()));
+    } else if (line.find(macrotile_prefill_lines) != string::npos) {
+      crtc_info_.macrotile_prefill_lines =
+        std::stoi(string(line, macrotile_prefill_lines.length()));
+    } else if (line.find(yuv_nv12_prefill_lines) != string::npos) {
+      crtc_info_.nv12_prefill_lines = std::stoi(string(line, yuv_nv12_prefill_lines.length()));
+    } else if (line.find(linear_prefill_lines) != string::npos) {
+      crtc_info_.linear_prefill_lines = std::stoi(string(line, linear_prefill_lines.length()));
+    } else if (line.find(downscaling_prefill_lines) != string::npos) {
+      crtc_info_.downscale_prefill_lines =
+        std::stoi(string(line, downscaling_prefill_lines.length()));
+    } else if (line.find(xtra_prefill_lines) != string::npos) {
+      crtc_info_.extra_prefill_lines = std::stoi(string(line, xtra_prefill_lines.length()));
+    } else if (line.find(amortizable_threshold) != string::npos) {
+      crtc_info_.amortized_threshold = std::stoi(string(line, amortizable_threshold.length()));
+    } else if (line.find(max_bandwidth_low) != string::npos) {
+      crtc_info_.max_bandwidth_low = std::stoull(string(line, max_bandwidth_low.length()));
+    } else if (line.find(max_bandwidth_high) != string::npos) {
+      crtc_info_.max_bandwidth_high = std::stoull(string(line, max_bandwidth_high.length()));
+    } else if (line.find(max_mdp_clk) != string::npos) {
+      crtc_info_.max_sde_clk = std::stoi(string(line, max_mdp_clk.length()));
+    } else if (line.find(core_clk_ff) != string::npos) {
+      crtc_info_.clk_fudge_factor = std::stof(string(line, core_clk_ff.length()));
+    } else if (line.find(comp_ratio_rt) != string::npos) {
+      ParseCompRatio(line.substr(comp_ratio_rt.length()), true);
+    } else if (line.find(comp_ratio_nrt) != string::npos) {
+      ParseCompRatio(line.substr(comp_ratio_nrt.length()), false);
+    } else if (line.find(hw_version) != string::npos) {
+      crtc_info_.hw_version = std::stoi(string(line, hw_version.length()));
+    } else if (line.find(solidfill_stages) != string::npos) {
+      crtc_info_.max_solidfill_stages =  std::stoi(string(line, solidfill_stages.length()));
+    } else if (line.find(dest_scaler_count) != string::npos) {
+      crtc_info_.dest_scaler_count = std::stoi(string(line, dest_scaler_count.length()));
+    } else if (line.find(max_dest_scale_up) != string::npos) {
+      crtc_info_.max_dest_scale_up = std::stoi(string(line, max_dest_scale_up.length()));
+    } else if (line.find(max_dest_scaler_input_width) != string::npos) {
+      crtc_info_.max_dest_scaler_input_width =
+                          std::stoi(string(line, max_dest_scaler_input_width.length()));
+    } else if (line.find(max_dest_scaler_output_width) != string::npos) {
+      crtc_info_.max_dest_scaler_output_width =
+                         std::stoi(string(line, max_dest_scaler_output_width.length()));
+    } else if (line.find(has_hdr) != string::npos) {
+      crtc_info_.has_hdr = std::stoi(string(line, has_hdr.length()));
+    } else if (line.find(min_prefill_lines) != string::npos) {
+      crtc_info_.min_prefill_lines = std::stoi(string(line, min_prefill_lines.length()));
+    } else if (line.find(sec_ui_blendstage) != string::npos) {
+      crtc_info_.secure_disp_blend_stage = std::stoi(string(line, (sec_ui_blendstage).length()));
+    }
+  }
+  drmModeFreePropertyBlob(blob);
+}
+
+void DRMCrtc::ParseCompRatio(string line, bool real_time) {
+  CompRatioMap &comp_ratio_map =
+    real_time ? crtc_info_.comp_ratio_rt_map : crtc_info_.comp_ratio_nrt_map;
+  std::vector<string> format_cr_list;
+
+  Tokenize(line, &format_cr_list, ' ');
+
+  for (uint32_t i = 0; i < format_cr_list.size(); i++) {
+    std::vector<string> format_cr;
+    Tokenize(format_cr_list.at(i), &format_cr, '/');
+    std::string format = format_cr.at(0);
+    uint64_t vendor_code = stoi(format_cr.at(1));
+    uint64_t fmt_modifier = stoi(format_cr.at(2));
+    float comp_ratio = std::stof(format_cr.at(3));
+    uint64_t modifier = 0;
+
+    if (vendor_code == DRM_FORMAT_MOD_VENDOR_QCOM) {
+      // Macro from drm_fourcc.h to form modifier
+      modifier = fourcc_mod_code(QCOM, fmt_modifier);
+    }
+
+    std::pair<uint32_t, uint64_t> drm_format =
+      std::make_pair(fourcc_code(format[0], format[1], format[2], format[3]), modifier);
+    comp_ratio_map.insert(std::make_pair(drm_format, comp_ratio));
+  }
+}
+
+void DRMCrtc::GetInfo(DRMCrtcInfo *info) {
+  *info = crtc_info_;
+}
+
+void DRMCrtc::Lock() {
+  status_ = DRMStatus::BUSY;
+}
+
+void DRMCrtc::Unlock() {
+  if (mode_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, mode_blob_id_);
+    mode_blob_id_ = 0;
+  }
+
+  tmp_prop_val_map_.clear();
+  committed_prop_val_map_.clear();
+  status_ = DRMStatus::FREE;
+}
+
+void DRMCrtc::SetModeBlobID(uint64_t blob_id) {
+  if (mode_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, mode_blob_id_);
+  }
+
+  mode_blob_id_ = blob_id;
+}
+
+void DRMCrtc::InitAndParse(drmModeCrtc *crtc) {
+  drm_crtc_ = crtc;
+  ParseProperties();
+  pp_mgr_ = std::unique_ptr<DRMPPManager>(new DRMPPManager(fd_));
+  pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_CRTC);
+}
+
+void DRMCrtc::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
+  uint32_t obj_id = drm_crtc_->crtc_id;
+
+  switch (code) {
+    case DRMOps::CRTC_SET_MODE: {
+      drmModeModeInfo *mode = va_arg(args, drmModeModeInfo *);
+      uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::MODE_ID);
+      uint32_t blob_id = 0;
+
+      if (mode) {
+        if (drmModeCreatePropertyBlob(fd_, (const void *)mode, sizeof(drmModeModeInfo), &blob_id)) {
+          DRM_LOGE("drmModeCreatePropertyBlob failed for CRTC_SET_MODE, crtc %d", obj_id);
+          return;
+        }
+      }
+
+      AddProperty(req, obj_id, prop_id, blob_id, true /* cache */, tmp_prop_val_map_);
+      SetModeBlobID(blob_id);
+      DRM_LOGD("CRTC %d: Set mode %s", obj_id, mode ? mode->name : "null");
+    } break;
+
+    case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET: {
+      uint32_t offset = va_arg(args, uint32_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::OUTPUT_FENCE_OFFSET),
+                  offset, true /* cache */, tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_CORE_CLK: {
+      uint32_t core_clk = va_arg(args, uint32_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::CORE_CLK), core_clk, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_CORE_AB: {
+      uint64_t core_ab = va_arg(args, uint64_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::CORE_AB), core_ab, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_CORE_IB: {
+      uint64_t core_ib = va_arg(args, uint64_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::CORE_IB), core_ib, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_LLCC_AB: {
+      uint64_t llcc_ab = va_arg(args, uint64_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::LLCC_AB), llcc_ab, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_LLCC_IB: {
+      uint64_t llcc_ib = va_arg(args, uint64_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::LLCC_IB), llcc_ib, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_DRAM_AB: {
+      uint64_t dram_ab = va_arg(args, uint64_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::DRAM_AB), dram_ab, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_DRAM_IB: {
+      uint64_t dram_ib = va_arg(args, uint64_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::DRAM_IB), dram_ib, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_SET_ROT_PREFILL_BW: {
+      uint64_t rot_bw = va_arg(args, uint64_t);
+      drmModeAtomicAddProperty(req, obj_id,
+                               prop_mgr_.GetPropertyId(DRMProperty::ROT_PREFILL_BW), rot_bw);
+    }; break;
+
+    case DRMOps::CRTC_SET_ROT_CLK: {
+      uint32_t rot_clk = va_arg(args, uint32_t);
+      AddProperty(req, obj_id,
+                  prop_mgr_.GetPropertyId(DRMProperty::ROT_CLK), rot_clk, true /* cache */,
+                  tmp_prop_val_map_);
+    }; break;
+
+    case DRMOps::CRTC_GET_RELEASE_FENCE: {
+      int64_t *fence = va_arg(args, int64_t *);
+      *fence = -1;
+      uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::OUTPUT_FENCE);
+      AddProperty(req, obj_id, prop_id, reinterpret_cast<uint64_t>(fence), false /* cache */,
+                  tmp_prop_val_map_);
+    } break;
+
+    case DRMOps::CRTC_SET_ACTIVE: {
+      uint32_t enable = va_arg(args, uint32_t);
+      AddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::ACTIVE), enable,
+                  true /* cache */, tmp_prop_val_map_);
+      DRM_LOGD("CRTC %d: Set active %d", obj_id, enable);
+      if (enable == 0) {
+        ClearVotesCache();
+      }
+    } break;
+
+    case DRMOps::CRTC_SET_POST_PROC: {
+      DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
+      if (data)
+        pp_mgr_->SetPPFeature(req, obj_id, *data);
+      DRM_LOGD("CRTC %d: Set post proc", obj_id);
+    } break;
+
+    case DRMOps::CRTC_SET_ROI: {
+      uint32_t num_roi = va_arg(args, uint32_t);
+      DRMRect *crtc_rois = va_arg(args, DRMRect*);
+      SetROI(req, obj_id, num_roi, crtc_rois);
+    } break;
+
+    case DRMOps::CRTC_SET_SECURITY_LEVEL: {
+      int security_level = va_arg(args, int);
+      uint32_t crtc_security_level = SECURE_NON_SECURE;
+      if (security_level == (int)DRMSecurityLevel::SECURE_ONLY) {
+        crtc_security_level = SECURE_ONLY;
+      }
+      AddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::SECURITY_LEVEL),
+                  crtc_security_level, true /* cache */, tmp_prop_val_map_);
+    } break;
+
+    case DRMOps::CRTC_SET_SOLIDFILL_STAGES: {
+      uint64_t dim_stages = va_arg(args, uint64_t);
+      const std::vector<DRMSolidfillStage> *solid_fills =
+        reinterpret_cast <std::vector <DRMSolidfillStage> *> (dim_stages);
+      SetSolidfillStages(req, obj_id, solid_fills);
+    } break;
+
+    case DRMOps::CRTC_SET_IDLE_TIMEOUT: {
+      uint32_t timeout_ms = va_arg(args, uint32_t);
+      AddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::IDLE_TIME),
+                  timeout_ms, true /* cache */, tmp_prop_val_map_);
+    } break;
+
+    case DRMOps::CRTC_SET_DEST_SCALER_CONFIG: {
+      uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::DEST_SCALER);
+      uint64_t dest_scaler = va_arg(args, uint64_t);
+      static sde_drm_dest_scaler_data dest_scale_copy = {};
+      sde_drm_dest_scaler_data *ds_data = reinterpret_cast<sde_drm_dest_scaler_data *>
+                                           (dest_scaler);
+      dest_scale_copy = *ds_data;
+      AddProperty(req, obj_id, prop_id,
+                  reinterpret_cast<uint64_t>(&dest_scale_copy), false /* cache */,
+                  tmp_prop_val_map_);
+    } break;
+
+    case DRMOps::CRTC_SET_CAPTURE_MODE: {
+      int capture_mode = va_arg(args, int);
+      uint32_t cwb_capture_mode = CAPTURE_MIXER_OUT;
+      if (capture_mode == (int)DRMCWbCaptureMode::DSPP_OUT) {
+        cwb_capture_mode = CAPTURE_DSPP_OUT;
+      }
+      uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::CAPTURE_MODE);
+      AddProperty(req, obj_id, prop_id, cwb_capture_mode, true /* cache */, tmp_prop_val_map_);
+    } break;
+
+    case DRMOps::CRTC_SET_IDLE_PC_STATE: {
+      if (!prop_mgr_.IsPropertyAvailable(DRMProperty::IDLE_PC_STATE)) {
+        return;
+      }
+      int drm_idle_pc_state = va_arg(args, int);
+      uint32_t idle_pc_state = IDLE_PC_STATE_NONE;
+      switch (drm_idle_pc_state) {
+        case static_cast<int>(DRMIdlePCState::ENABLE):
+          idle_pc_state = IDLE_PC_STATE_ENABLE;
+          break;
+        case static_cast<int>(DRMIdlePCState::DISABLE):
+          idle_pc_state = IDLE_PC_STATE_DISABLE;
+          break;
+        default:
+          idle_pc_state = IDLE_PC_STATE_NONE;
+          break;
+      }
+      AddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::IDLE_PC_STATE), idle_pc_state,
+                  true /* cache */, tmp_prop_val_map_);
+      DRM_LOGD("CRTC %d: Set idle_pc_state %d", obj_id, idle_pc_state);
+    }; break;
+
+    default:
+      DRM_LOGE("Invalid opcode %d to set the property on crtc %d", code, obj_id);
+      break;
+  }
+}
+
+void DRMCrtc::SetROI(drmModeAtomicReq *req, uint32_t obj_id, uint32_t num_roi,
+                     DRMRect *crtc_rois) {
+#ifdef SDE_MAX_ROI_V1
+  if (!num_roi || num_roi > SDE_MAX_ROI_V1 ||
+      !prop_mgr_.IsPropertyAvailable(DRMProperty::ROI_V1)) {
+    return;
+  }
+
+  static struct sde_drm_roi_v1 roi_v1 {};
+  roi_v1.num_rects = num_roi;
+
+  for (uint32_t i = 0; i < num_roi; i++) {
+    roi_v1.roi[i].x1 = crtc_rois[i].left;
+    roi_v1.roi[i].x2 = crtc_rois[i].right;
+    roi_v1.roi[i].y1 = crtc_rois[i].top;
+    roi_v1.roi[i].y2 = crtc_rois[i].bottom;
+    DRM_LOGD("CRTC %d, ROI[l,t,b,r][%d %d %d %d]", obj_id,
+             roi_v1.roi[i].x1, roi_v1.roi[i].y1, roi_v1.roi[i].x2, roi_v1.roi[i].y2);
+  }
+  AddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::ROI_V1),
+              reinterpret_cast<uint64_t>(&roi_v1), false /* cache */, tmp_prop_val_map_);
+#endif
+}
+
+void DRMCrtc::SetSolidfillStages(drmModeAtomicReq *req, uint32_t obj_id,
+                                 const std::vector<DRMSolidfillStage> *solid_fills) {
+#if defined  SDE_MAX_DIM_LAYERS
+  static struct sde_drm_dim_layer_v1  drm_dim_layer_v1 {};
+  uint32_t shift;
+
+  drm_dim_layer_v1.num_layers = solid_fills->size();
+  for (uint32_t i = 0; i < solid_fills->size(); i++) {
+    const DRMSolidfillStage &sf = solid_fills->at(i);
+    float plane_alpha = (sf.plane_alpha / 255.0f);
+    drm_dim_layer_v1.layer_cfg[i].stage = sf.z_order;
+    drm_dim_layer_v1.layer_cfg[i].rect.x1 = (uint16_t)sf.bounding_rect.left;
+    drm_dim_layer_v1.layer_cfg[i].rect.y1 = (uint16_t)sf.bounding_rect.top;
+    drm_dim_layer_v1.layer_cfg[i].rect.x2 = (uint16_t)sf.bounding_rect.right;
+    drm_dim_layer_v1.layer_cfg[i].rect.y2 = (uint16_t)sf.bounding_rect.bottom;
+    drm_dim_layer_v1.layer_cfg[i].flags =
+      sf.is_exclusion_rect ? SDE_DRM_DIM_LAYER_EXCLUSIVE : SDE_DRM_DIM_LAYER_INCLUSIVE;
+
+    // @sde_mdss_color: expects in [g b r a] order where as till now solidfill is in [a r g b].
+    // As no support for passing plane alpha, Multiply Alpha color component with plane_alpa.
+    shift = kSolidFillHwBitDepth - sf.color_bit_depth;
+    drm_dim_layer_v1.layer_cfg[i].color_fill.color_0 = (sf.green & 0x3FF) << shift;
+    drm_dim_layer_v1.layer_cfg[i].color_fill.color_1 = (sf.blue & 0x3FF) << shift;
+    drm_dim_layer_v1.layer_cfg[i].color_fill.color_2 = (sf.red & 0x3FF) << shift;
+    // alpha is 8 bit
+    drm_dim_layer_v1.layer_cfg[i].color_fill.color_3 =
+      ((uint32_t)((((sf.alpha & 0xFF)) * plane_alpha)));
+  }
+
+  AddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::DIM_STAGES_V1),
+              reinterpret_cast<uint64_t> (&drm_dim_layer_v1), false /* cache */,
+              tmp_prop_val_map_);
+#endif
+}
+
+void DRMCrtc::Dump() {
+  DRM_LOGE("id: %d\tbuffer_id: %d\tpos:(%d, %d)\tsize:(%dx%d)\n", drm_crtc_->crtc_id,
+           drm_crtc_->buffer_id, drm_crtc_->x, drm_crtc_->y, drm_crtc_->width, drm_crtc_->height);
+}
+
+bool DRMCrtc::ConfigureScalerLUT(drmModeAtomicReq *req, uint32_t dir_lut_blob_id,
+                                 uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
+  if (is_lut_configured_ && is_lut_validated_) {
+    return false;
+  }
+  if (dir_lut_blob_id) {
+    AddProperty(req, drm_crtc_->crtc_id,
+                prop_mgr_.GetPropertyId(DRMProperty::DS_LUT_ED), dir_lut_blob_id,
+                false /* cache */, tmp_prop_val_map_);
+  }
+  if (cir_lut_blob_id) {
+    AddProperty(req, drm_crtc_->crtc_id,
+                prop_mgr_.GetPropertyId(DRMProperty::DS_LUT_CIR), cir_lut_blob_id,
+                false /* cache */, tmp_prop_val_map_);
+  }
+  if (sep_lut_blob_id) {
+    AddProperty(req, drm_crtc_->crtc_id,
+                prop_mgr_.GetPropertyId(DRMProperty::DS_LUT_SEP), sep_lut_blob_id,
+                false /* cache */, tmp_prop_val_map_);
+  }
+  is_lut_validation_in_progress_ = true;
+  return true;
+}
+
+void DRMCrtc::PostCommit(bool success) {
+  if (success) {
+    if (is_lut_validated_) {
+      is_lut_configured_ = true;
+    }
+    committed_prop_val_map_ = tmp_prop_val_map_;
+  } else {
+    tmp_prop_val_map_ = committed_prop_val_map_;
+  }
+}
+
+void DRMCrtc::PostValidate(bool success) {
+  if (success && is_lut_validation_in_progress_)  {
+    is_lut_validated_ = true;
+  }
+
+  tmp_prop_val_map_ = committed_prop_val_map_;
+}
+
+void DRMCrtc::ClearVotesCache() {
+  // On subsequent SET_ACTIVE 1, commit these to MDP driver and re-add to cache automatically
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::CORE_CLK));
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::CORE_AB));
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::CORE_IB));
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::LLCC_AB));
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::LLCC_IB));
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::DRAM_AB));
+  tmp_prop_val_map_.erase(prop_mgr_.GetPropertyId(DRMProperty::DRAM_IB));
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_crtc.h b/sde-drm/drm_crtc.h
new file mode 100644
index 0000000..e17834d
--- /dev/null
+++ b/sde-drm/drm_crtc.h
@@ -0,0 +1,126 @@
+/*
+* Copyright (c) 2019, 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 __DRM_CRTC_H__
+#define __DRM_CRTC_H__
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <map>
+#include <memory>
+#include <vector>
+#include <string>
+
+#include "drm_interface.h"
+#include "drm_utils.h"
+#include "drm_pp_manager.h"
+#include "drm_property.h"
+
+namespace sde_drm {
+
+class DRMCrtc {
+ public:
+  DRMCrtc(int fd, uint32_t crtc_index) : fd_(fd), crtc_index_(crtc_index) {}
+  void InitAndParse(drmModeCrtc *crtc);
+  DRMStatus GetStatus() { return status_; }
+  void GetInfo(DRMCrtcInfo *info);
+  void SetModeBlobID(uint64_t blob_id);
+  bool ConfigureScalerLUT(drmModeAtomicReq *req, uint32_t dir_lut_blob_id,
+                          uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id);
+  void PostValidate(bool success);
+  void PostCommit(bool success);
+  void Perform(DRMOps code, drmModeAtomicReq *req, va_list args);
+  int GetIndex() { return crtc_index_; }
+  void Dump();
+  void Lock();
+  void Unlock();
+  void GetPPInfo(DRMPPFeatureInfo *info) {
+    if (pp_mgr_)
+      pp_mgr_->GetPPInfo(info);
+  }
+  ~DRMCrtc();
+
+ private:
+  void ParseProperties();
+  void ParseCapabilities(uint64_t blob_id);
+  void ParseCompRatio(std::string line, bool real_time);
+  void SetROI(drmModeAtomicReq *req, uint32_t obj_id, uint32_t num_roi,
+              DRMRect *crtc_rois);
+  void SetSolidfillStages(drmModeAtomicReq *req, uint32_t obj_id,
+                          const std::vector<DRMSolidfillStage> *solid_fills);
+  void ClearVotesCache();
+
+  // Currently hardcoded to 10. In future we need to query bit depth from driver.
+  static const int kSolidFillHwBitDepth = 10;
+
+  int fd_ = -1;
+  uint32_t crtc_index_ = {};
+  uint64_t mode_blob_id_ = 0;
+  drmModeCrtc *drm_crtc_ = {};
+  DRMStatus status_ = DRMStatus::FREE;
+  DRMCrtcInfo crtc_info_ = {};
+  DRMPropertyManager prop_mgr_ {};
+  bool is_lut_configured_ = false;
+  bool is_lut_validated_ = false;
+  bool is_lut_validation_in_progress_ = false;
+  std::unique_ptr<DRMPPManager> pp_mgr_{};
+  std::unordered_map<uint32_t, uint64_t> tmp_prop_val_map_ {};
+  std::unordered_map<uint32_t, uint64_t> committed_prop_val_map_ {};
+};
+
+class DRMCrtcManager {
+ public:
+  explicit DRMCrtcManager(int fd) : fd_(fd) {}
+  void Init(drmModeRes *res);
+  void DeInit() {}
+  void DumpAll();
+  void DumpByID(uint32_t id);
+  int Reserve(DRMDisplayType disp_type, DRMDisplayToken *token);
+  int Reserve(int32_t display_id, DRMDisplayToken *token);
+  void Free(const DRMDisplayToken &token);
+  void Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args);
+  int GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info);
+  void SetScalerLUT(const DRMScalerLUTInfo &lut_info);
+  void UnsetScalerLUT();
+  void GetPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info);
+  void PostValidate(uint32_t crtc_id, bool success);
+  void PostCommit(uint32_t crtc_id, bool success);
+
+ private:
+  int fd_ = -1;
+  std::map<uint32_t, std::unique_ptr<DRMCrtc>> crtc_pool_{};
+    // GLobal Scaler LUT blobs
+  uint32_t dir_lut_blob_id_ = 0;
+  uint32_t cir_lut_blob_id_ = 0;
+  uint32_t sep_lut_blob_id_ = 0;
+};
+
+}  // namespace sde_drm
+
+#endif  // __DRM_CRTC_H__
diff --git a/sde-drm/drm_dpps_mgr_imp.cpp b/sde-drm/drm_dpps_mgr_imp.cpp
new file mode 100644
index 0000000..d0a593e
--- /dev/null
+++ b/sde-drm/drm_dpps_mgr_imp.cpp
@@ -0,0 +1,350 @@
+/*
+* Copyright (c) 2019, 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 <errno.h>
+#include <drm_logger.h>
+#include "drm_dpps_mgr_imp.h"
+
+#define __CLASS__ "DRMDppsManagerImp"
+namespace sde_drm {
+
+static DRMDppsManagerImp dpps_mgr;
+static DRMDppsManagerDummyImp dpps_dummy_mgr;
+
+DRMDppsManagerIntf* GetDppsManagerIntf()
+{
+#if (defined(__ANDROID__))
+    return &dpps_mgr;
+#else
+    return &dpps_dummy_mgr;
+#endif
+}
+
+int DRMDppsManagerImp::GetDrmResources(drmModeRes* res) {
+  int enc_id = -1;
+  drmModeConnector *conn = NULL;
+  drmModeEncoder *enc = NULL;
+  drmModeCrtc *crtc = NULL;
+
+  if (drm_fd_ < 0 ) {
+    DRM_LOGE("Invalid drm_fd_ %d", drm_fd_);
+    return -EINVAL;
+  }
+
+  for (auto i = 0; i < res->count_connectors; i++) {
+    conn = drmModeGetConnector(drm_fd_, res->connectors[i]);
+    if (conn && conn->connector_type == DRM_MODE_CONNECTOR_DSI &&
+        conn->count_modes && conn->connection == DRM_MODE_CONNECTED) {
+      DRM_LOGI("Found connector %d", conn->connector_id);
+      conn_id_ = conn->connector_id;
+      break;
+    }
+    drmModeFreeConnector(conn);
+    conn = NULL;
+  }
+  if (conn_id_ < 0 || !conn) {
+    DRM_LOGE("Cannot find valid connector");
+    conn_id_ = -1;
+    return -EINVAL;
+  }
+
+  for (auto i = 0; i < conn->count_encoders; i++) {
+    enc = drmModeGetEncoder(drm_fd_, conn->encoders[i]);
+    if (enc && enc->encoder_type == DRM_MODE_ENCODER_DSI) {
+      DRM_LOGI("Found encoder %d", enc->encoder_id);
+      enc_id = enc->encoder_id;
+      break;
+    }
+    drmModeFreeEncoder(enc);
+    enc = NULL;
+  }
+  if (enc_id < 0 || !enc) {
+    DRM_LOGE("Cannot find valid encoder");
+    drmModeFreeConnector(conn);
+    conn = NULL;
+    res = NULL;
+    conn_id_ = -1;
+    return -EINVAL;
+  }
+
+  for (auto i = 0; i < res->count_crtcs; i++) {
+    if (enc->possible_crtcs & (1 << i)) {
+      crtc = drmModeGetCrtc(drm_fd_, res->crtcs[i]);
+      if (crtc) {
+        DRM_LOGI("Found crtc %d", crtc->crtc_id);
+        crtc_id_ = crtc->crtc_id;
+        break;
+      }
+      drmModeFreeCrtc(crtc);
+      crtc = NULL;
+    }
+  }
+  if (crtc_id_ < 0 || !crtc) {
+    DRM_LOGE("Cannot find valid crtc");
+    drmModeFreeEncoder(enc);
+    drmModeFreeConnector(conn);
+    enc = NULL;
+    conn = NULL;
+    conn_id_ = -1;
+    crtc_id_ = -1;
+    return -EINVAL;
+  }
+  return 0;
+}
+
+int DRMDppsManagerImp::InitCrtcProps() {
+  if (drm_fd_ < 0 || crtc_id_ < 0) {
+    DRM_LOGE("Invalid drm_fd_ %d or crtc_id_ %d", drm_fd_, crtc_id_);
+    return -EINVAL;
+  }
+
+  drmModeObjectProperties *props =
+    drmModeObjectGetProperties(drm_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC);
+  if (!props || !props->props || !props->prop_values) {
+    drmModeFreeObjectProperties(props);
+    return -EINVAL;
+  }
+
+  for (uint32_t j = 0; j < props->count_props; j++) {
+    drmModePropertyRes *info = drmModeGetProperty(drm_fd_, props->props[j]);
+    if (!info) {
+      continue;
+    }
+
+    std::string property_name(info->name);
+    DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
+    if (prop_enum == DRMProperty::INVALID) {
+      DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
+      drmModeFreeProperty(info);
+      continue;
+    }
+
+    prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
+    drmModeFreeProperty(info);
+  }
+
+  drmModeFreeObjectProperties(props);
+  return 0;
+}
+
+int DRMDppsManagerImp::InitConnProps()
+{
+  if (drm_fd_ < 0 || conn_id_ < 0) {
+    DRM_LOGE("Invalid drm_fd_ %d or conn_id_ %d", drm_fd_, conn_id_);
+    return -EINVAL;
+  }
+
+  drmModeObjectProperties *props =
+      drmModeObjectGetProperties(drm_fd_, conn_id_, DRM_MODE_OBJECT_CONNECTOR);
+  if (!props || !props->props || !props->prop_values) {
+    drmModeFreeObjectProperties(props);
+    return -EINVAL;
+  }
+
+  for (uint32_t j = 0; j < props->count_props; j++) {
+    drmModePropertyRes *info = drmModeGetProperty(drm_fd_, props->props[j]);
+    if (!info) {
+      continue;
+    }
+
+    std::string property_name(info->name);
+    DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
+    if (prop_enum == DRMProperty::INVALID) {
+      DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
+      drmModeFreeProperty(info);
+      continue;
+    }
+
+    prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
+    drmModeFreeProperty(info);
+  }
+
+  drmModeFreeObjectProperties(props);
+  return 0;
+}
+
+void DRMDppsManagerImp::Init(int fd, drmModeRes* res) {
+  int ret = 0;
+
+  if (fd < 0 || !res) {
+    DRM_LOGE("Invalid drm fd %d or res %p", fd, res);
+    return;
+  }
+
+  drm_fd_ = fd;
+  ret = GetDrmResources(res);
+  if (ret) {
+    DRM_LOGE("Failed to get DRM resources %d", ret);
+    return;
+  } else {
+    ret = InitCrtcProps();
+    if (ret) {
+      DRM_LOGE("Failed to initialize crtc properties %d", ret);
+      return;
+    }
+    ret = InitConnProps();
+    if (ret) {
+      DRM_LOGE("Failed to initialize conn properties %d", ret);
+      return;
+    }
+  }
+
+  dpps_feature_[kFeatureAd4Mode] = DRMDppsPropInfo {
+    (prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_MODE) == 0 ? 0U : 4U) /* version */,
+    DRMProperty::SDE_DSPP_AD4_MODE, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_MODE),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4Init] = DRMDppsPropInfo {4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_INIT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_INIT),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4Cfg] = DRMDppsPropInfo { 4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_CFG, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_CFG),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4Input] = DRMDppsPropInfo {4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_INPUT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_INPUT),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4Backlight] = DRMDppsPropInfo {4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_BACKLIGHT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_BACKLIGHT),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4Assertiveness] = DRMDppsPropInfo {4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_ASSERTIVENESS, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_ASSERTIVENESS),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4Roi] = DRMDppsPropInfo {4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_ROI, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_ROI),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4ManualStrength] = DRMDppsPropInfo {4 /* version */,
+    DRMProperty::SDE_DSPP_AD4_STRENGTH, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_STRENGTH),
+    false /* is_event */};
+  dpps_feature_[kFeatureAbaHistCtrl] = DRMDppsPropInfo {1 /* version */,
+    DRMProperty::SDE_DSPP_ABA_HIST_CTRL, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_ABA_HIST_CTRL),
+    false /* is_event */};
+  dpps_feature_[kFeatureAbaHistIRQ] = DRMDppsPropInfo {1 /* version */,
+    DRMProperty::SDE_DSPP_ABA_HIST_IRQ, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_ABA_HIST_IRQ),
+    false /* is_event */};
+  dpps_feature_[kFeatureAbaLut] = DRMDppsPropInfo {1 /* version */,
+    DRMProperty::SDE_DSPP_ABA_LUT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_ABA_LUT),
+    false /* is_event */};
+  dpps_feature_[kFeatureAd4BlScale] = DRMDppsPropInfo {1 /* version */,
+    DRMProperty::SDE_DSPP_AD4_BL_SCALE, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_BL_SCALE),
+    false /* is_event */};
+  dpps_feature_[kFeatureBacklightScale] = DRMDppsPropInfo {1 /* version */,
+    DRMProperty::SDE_DSPP_BL_SCALE, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_BL_SCALE),
+    false /* is_event */};
+
+  dpps_feature_[kFeaturePowerEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
+  dpps_feature_[kFeatureAbaHistEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
+  dpps_feature_[kFeatureBackLightEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
+  dpps_feature_[kFeatureAdAttBlEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
+}
+
+void DRMDppsManagerImp::CacheDppsFeature(uint32_t obj_id, va_list args) {
+  uint32_t feature_id = va_arg(args, uint32_t);
+  uint64_t value = va_arg(args, uint64_t);
+  struct DRMDppsPropInfo* info;
+
+  if (feature_id >= kDppsFeaturesMax) {
+    DRM_LOGE("Invalid feature id %d for obj_id 0x%x", feature_id, obj_id);
+    return;
+  }
+
+  info = &dpps_feature_[feature_id];
+  info->obj_id = obj_id;
+  info->value = value;
+  if (info->is_event) {
+    dpps_dirty_event_.push_back(*info);
+  } else {
+    for (auto &it : dpps_dirty_prop_) {
+      if ((it.obj_id == info->obj_id) && (it.prop_id == info->prop_id)) {
+        it.value = info->value;
+        return;
+      }
+    }
+    dpps_dirty_prop_.push_back(*info);
+  }
+}
+
+void DRMDppsManagerImp::CommitDppsFeatures(drmModeAtomicReq *req, const DRMDisplayToken &tok) {
+  if (!req)
+    return;
+
+  // Set Dpps properties
+  if (!dpps_dirty_prop_.empty()) {
+    for (auto it = dpps_dirty_prop_.begin(); it != dpps_dirty_prop_.end();) {
+      if (it->obj_id == tok.crtc_id || it->obj_id == tok.conn_id) {
+        drmModeAtomicAddProperty(req, it->obj_id, it->prop_id, it->value);
+        dpps_dirty_prop_.erase(it);
+      } else {
+        it++;
+      }
+    }
+  }
+
+  // Set Dpps events
+  if (!dpps_dirty_event_.empty()) {
+    for (auto it = dpps_dirty_event_.begin(); it != dpps_dirty_event_.end();) {
+      if (!it->value)
+        continue;
+
+      struct DRMDppsEventInfo info = *(struct DRMDppsEventInfo*)it->value;
+      struct drm_msm_event_req event_req = {};
+      int ret;
+      if (it->obj_id == tok.crtc_id || it->obj_id == tok.conn_id) {
+        event_req.object_id = it->obj_id;
+        event_req.object_type = info.object_type;
+        event_req.event = info.event_type;
+        if (info.enable)
+          ret = drmIoctl(info.drm_fd, DRM_IOCTL_MSM_REGISTER_EVENT, &event_req);
+        else
+          ret = drmIoctl(info.drm_fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &event_req);
+        if (ret)
+          DRM_LOGE("Failed to set event 0x%x, object_id %u, object_type 0x%x, enable %d",
+              event_req.event, event_req.object_id, info.object_type, info.enable);
+        dpps_dirty_event_.erase(it);
+      } else {
+        it++;
+      }
+    }
+  }
+}
+
+void DRMDppsManagerImp::GetDppsFeatureInfo(DRMDppsFeatureInfo *info)
+{
+  if (!info) {
+    DRM_LOGE("Invalid info NULL");
+    return;
+  }
+
+  DRMDPPSFeatureID id = info->id;
+  if (id >= kDppsFeaturesMax) {
+    DRM_LOGE("Invalid feature id %d", id);
+    return;
+  }
+  info->version = dpps_feature_[id].version;
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_dpps_mgr_imp.h b/sde-drm/drm_dpps_mgr_imp.h
new file mode 100644
index 0000000..5508547
--- /dev/null
+++ b/sde-drm/drm_dpps_mgr_imp.h
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2019, 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 __DRM_DPPS_MGR_IMP_H__
+#define __DRM_DPPS_MGR_IMP_H__
+
+#include "drm_interface.h"
+#include "drm_property.h"
+#include "drm_dpps_mgr_intf.h"
+
+namespace sde_drm {
+
+struct DRMDppsPropInfo {
+  /* params to be set in Init */
+  uint32_t version;
+  DRMProperty prop_enum;
+  uint32_t prop_id;
+  bool is_event;
+  /* params to be set in CacheDppsFeature */
+  uint32_t obj_id;
+  uint64_t value;
+};
+
+class DRMDppsManagerImp : public DRMDppsManagerIntf {
+ public:
+  ~DRMDppsManagerImp() {}
+  void Init(int fd, drmModeRes* res);
+  void CacheDppsFeature(uint32_t obj_id, va_list args);
+  void CommitDppsFeatures(drmModeAtomicReq *req, const DRMDisplayToken &tok);
+  void GetDppsFeatureInfo(DRMDppsFeatureInfo *info);
+
+ private:
+  int GetDrmResources(drmModeRes* res);
+  int InitCrtcProps();
+  int InitConnProps();
+
+  struct DRMDppsPropInfo dpps_feature_[kDppsFeaturesMax];
+  std::vector<struct DRMDppsPropInfo> dpps_dirty_prop_;
+  std::vector<struct DRMDppsPropInfo> dpps_dirty_event_;
+  /* key is the prop name, value is prop_id */
+  std::map<std::string, uint32_t> dpps_prop_info_map_ = {};
+  DRMPropertyManager prop_mgr_ {};
+  int conn_id_ = -1;
+  int crtc_id_ = -1;
+  int drm_fd_ = -1;
+};
+
+class DRMDppsManagerDummyImp : public DRMDppsManagerIntf {
+ public:
+  ~DRMDppsManagerDummyImp() {}
+  void Init(int fd, drmModeRes* res) {}
+  void CacheDppsFeature(uint32_t obj_id, va_list args) {}
+  void CommitDppsFeatures(drmModeAtomicReq *req, const DRMDisplayToken &tok) {}
+  void GetDppsFeatureInfo(DRMDppsFeatureInfo *info) {}
+};
+}  // namespace sde_drm
+#endif  // __DRM_DPPS_MGR_IMP_H__
diff --git a/sde-drm/drm_dpps_mgr_intf.h b/sde-drm/drm_dpps_mgr_intf.h
new file mode 100644
index 0000000..42a9870
--- /dev/null
+++ b/sde-drm/drm_dpps_mgr_intf.h
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2019, 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 __DRM_DPPS_MGR_INTF_H__
+#define __DRM_DPPS_MGR_INTF_H__
+
+namespace sde_drm {
+
+class DRMDppsManagerIntf {
+ public:
+  virtual ~DRMDppsManagerIntf() {}
+  virtual void Init(int fd, drmModeRes* res) = 0;
+  virtual void CacheDppsFeature(uint32_t obj_id, va_list args) = 0;
+  virtual void CommitDppsFeatures(drmModeAtomicReq *req, const DRMDisplayToken &tok) = 0;
+  virtual void GetDppsFeatureInfo(DRMDppsFeatureInfo *info) = 0;
+};
+
+extern "C" DRMDppsManagerIntf* GetDppsManagerIntf();
+}  // namespace sde_drm
+#endif  // __DRM_DPPS_MGR_INTF_H__
diff --git a/sde-drm/drm_encoder.cpp b/sde-drm/drm_encoder.cpp
new file mode 100644
index 0000000..878210a
--- /dev/null
+++ b/sde-drm/drm_encoder.cpp
@@ -0,0 +1,203 @@
+/*
+* Copyright (c) 2019, 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 <stdint.h>
+#include <stdlib.h>
+#include <drm.h>
+#include <drm/sde_drm.h>
+#include <drm_logger.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "drm_encoder.h"
+#include "drm_utils.h"
+
+namespace sde_drm {
+
+using std::unique_ptr;
+using std::map;
+
+#define __CLASS__ "DRMEncoderManager"
+
+DRMEncoderManager::~DRMEncoderManager() {}
+
+void DRMEncoderManager::Init(drmModeRes *resource) {
+  std::set<uint32_t> tmds_encoders;
+  std::set<uint32_t> dpmst_encoders;
+  for (int i = 0; i < resource->count_encoders; i++) {
+    unique_ptr<DRMEncoder> encoder(new DRMEncoder(fd_));
+    uint32_t encoder_type;
+    drmModeEncoder *libdrm_encoder = drmModeGetEncoder(fd_, resource->encoders[i]);
+    if (!libdrm_encoder) {
+      DRM_LOGE("Critical error: drmModeGetEncoder() failed for encoder %d.", resource->encoders[i]);
+      continue;
+    }
+    encoder->InitAndParse(libdrm_encoder);
+    encoder_pool_[resource->encoders[i]] = std::move(encoder);
+    encoder_pool_[resource->encoders[i]]->GetType(&encoder_type);
+    switch (encoder_type) {
+      case DRM_MODE_ENCODER_TMDS:
+        tmds_encoders.insert(resource->encoders[i]);
+        break;
+      case DRM_MODE_ENCODER_DPMST:
+        dpmst_encoders.insert(resource->encoders[i]);
+        break;
+      default:
+        break;
+    }
+  }
+  DRM_LOGI("Found %d TMDS encoders and %d DPMST encoders.", tmds_encoders.size(),
+           dpmst_encoders.size());
+  // DRM_MODE_ENCODER_TMDS type is for DVI, HDMI and (embedded) DisplayPort.
+  // DRM_MODE_ENCODER_DPMST type is for special fake encoders used to allow mutliple DP MST streams
+  // to share one physical encoder.
+  // Maximum number of DRMDisplayType::TV displays supported is maximum of TMDS and DPMST encoders.
+  // DRMEncoderManager is used only for discovering number of display interfaces supported and for
+  // keeping track of display interfaces used/available. Reserving DRMDisplayType::TV does not
+  // distinguish between TMDS and DPMST encoders. So remove TMDS/DPMST encoders of the type with
+  // the least encoders. This will ensure HWInfoDRM::GetMaxDisplaysSupported() still works right.
+  if (tmds_encoders.size() < dpmst_encoders.size()) {
+    for (auto iter : tmds_encoders) {
+      encoder_pool_.erase(iter);
+    }
+  } else {
+    for (auto iter : dpmst_encoders) {
+      encoder_pool_.erase(iter);
+    }
+  }
+}
+
+void DRMEncoderManager::DumpByID(uint32_t id) {
+  encoder_pool_.at(id)->Dump();
+}
+
+void DRMEncoderManager::DumpAll() {
+  for (auto &encoder : encoder_pool_) {
+    encoder.second->Dump();
+  }
+}
+
+int DRMEncoderManager::GetEncoderInfo(uint32_t encoder_id, DRMEncoderInfo *info) {
+  int ret = -ENODEV;
+  auto iter = encoder_pool_.find(encoder_id);
+
+  if (iter != encoder_pool_.end()) {
+    encoder_pool_[encoder_id]->GetInfo(info);
+    ret = 0;
+  }
+  return ret;
+}
+
+int DRMEncoderManager::GetEncoderList(std::vector<uint32_t> *encoder_ids) {
+  if (!encoder_ids) {
+    return -EINVAL;
+  }
+  encoder_ids->clear();
+  for (auto &encoder : encoder_pool_) {
+    encoder_ids->push_back(encoder.first);
+  }
+  return 0;
+}
+
+static bool IsTVEncoder(uint32_t type) {
+  return (type == DRM_MODE_ENCODER_TMDS || type == DRM_MODE_ENCODER_DPMST);
+}
+
+int DRMEncoderManager::Reserve(DRMDisplayType disp_type, DRMDisplayToken *token) {
+  int ret = -ENODEV;
+  for (auto &encoder : encoder_pool_) {
+    if (encoder.second->GetStatus() == DRMStatus::FREE) {
+      uint32_t encoder_type;
+      encoder.second->GetType(&encoder_type);
+      if ((disp_type == DRMDisplayType::PERIPHERAL && encoder_type == DRM_MODE_ENCODER_DSI) ||
+          (disp_type == DRMDisplayType::VIRTUAL && encoder_type == DRM_MODE_ENCODER_VIRTUAL) ||
+          (disp_type == DRMDisplayType::TV && IsTVEncoder(encoder_type))) {
+        encoder.second->Lock();
+        token->encoder_id = encoder.first;
+        ret = 0;
+        break;
+      }
+    }
+  }
+  return ret;
+}
+
+int DRMEncoderManager::Reserve(int32_t display_id, DRMDisplayToken *token) {
+  int ret = -ENODEV;
+  return ret;
+}
+
+void DRMEncoderManager::Free(const DRMDisplayToken &token) {
+  auto iter = encoder_pool_.find(token.encoder_id);
+  if (iter != encoder_pool_.end()) {
+    iter->second->Unlock();
+  } else {
+    DRM_LOGW("Failed! encoder_id %u not found!", token.encoder_id);
+  }
+}
+
+// ==============================================================================================//
+
+#undef __CLASS__
+#define __CLASS__ "DRMEncoder"
+
+DRMEncoder::~DRMEncoder() {
+  if (drm_encoder_) {
+    drmModeFreeEncoder(drm_encoder_);
+  }
+}
+
+void DRMEncoder::GetInfo(DRMEncoderInfo *info) {
+  *info = encoder_info_;
+}
+
+void DRMEncoder::Lock() {
+  status_ = DRMStatus::BUSY;
+}
+
+void DRMEncoder::Unlock() {
+  status_ = DRMStatus::FREE;
+}
+
+void DRMEncoder::InitAndParse(drmModeEncoder *encoder) {
+  drm_encoder_ = encoder;
+  encoder_info_.type = drm_encoder_->encoder_type;
+}
+
+void DRMEncoder::Dump() {
+  DRM_LOGI("id: %d\tencoder_type: %d fd = %d\n", drm_encoder_->encoder_id,
+           drm_encoder_->encoder_type, fd_);
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_encoder.h b/sde-drm/drm_encoder.h
new file mode 100644
index 0000000..5030fd4
--- /dev/null
+++ b/sde-drm/drm_encoder.h
@@ -0,0 +1,84 @@
+/*
+* Copyright (c) 2019, 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 __DRM_ENCODER_H__
+#define __DRM_ENCODER_H__
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "drm_interface.h"
+#include "drm_utils.h"
+
+namespace sde_drm {
+
+class DRMEncoder {
+ public:
+  explicit DRMEncoder(int fd) : fd_(fd) {}
+  void InitAndParse(drmModeEncoder *encoder);
+  DRMStatus GetStatus() { return status_; }
+  void GetInfo(DRMEncoderInfo *info);
+  void GetType(uint32_t *encoder_type) { *encoder_type = drm_encoder_->encoder_type; }
+  void Dump();
+  void Lock();
+  void Unlock();
+  ~DRMEncoder();
+
+ private:
+  int fd_ = -1;
+  drmModeEncoder *drm_encoder_ = {};
+  DRMStatus status_ = DRMStatus::FREE;
+  DRMEncoderInfo encoder_info_ = {};
+};
+
+class DRMEncoderManager {
+ public:
+  explicit DRMEncoderManager(int fd) : fd_(fd) {}
+  ~DRMEncoderManager();
+  void Init(drmModeRes *res);
+  void DeInit() {}
+  void DumpAll();
+  void DumpByID(uint32_t id);
+  int Reserve(DRMDisplayType disp_type, DRMDisplayToken *token);
+  int Reserve(int32_t display_id, DRMDisplayToken *token);
+  void Free(const DRMDisplayToken &token);
+  int GetEncoderInfo(uint32_t encoder_id, DRMEncoderInfo *info);
+  int GetEncoderList(std::vector<uint32_t> *encoder_ids);
+
+ private:
+  int fd_ = -1;
+  std::map<uint32_t, std::unique_ptr<DRMEncoder>> encoder_pool_{};
+};
+
+}  // namespace sde_drm
+
+#endif  // __DRM_ENCODER_H__
diff --git a/sde-drm/drm_manager.cpp b/sde-drm/drm_manager.cpp
new file mode 100644
index 0000000..d2aafd9
--- /dev/null
+++ b/sde-drm/drm_manager.cpp
@@ -0,0 +1,371 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <drm_logger.h>
+
+#include <string.h>
+#include "drm_atomic_req.h"
+#include "drm_connector.h"
+#include "drm_crtc.h"
+#include "drm_encoder.h"
+#include "drm_manager.h"
+#include "drm_plane.h"
+
+using std::lock_guard;
+using std::mutex;
+
+extern "C" {
+
+int GetDRMManager(int fd, sde_drm::DRMManagerInterface **intf) {
+  sde_drm::DRMManager *drm_mgr = sde_drm::DRMManager::GetInstance(fd);
+  if (!drm_mgr) {
+    return -ENODEV;
+  }
+
+  *intf = drm_mgr;
+  return 0;
+}
+
+int DestroyDRMManager() {
+  sde_drm::DRMManager::Destroy();
+  return 0;
+}
+
+}  // extern "C"
+
+namespace sde_drm {
+
+#define __CLASS__ "DRMManager"
+
+DRMManager *DRMManager::s_drm_instance = NULL;
+mutex DRMManager::s_lock;
+
+DRMManager *DRMManager::GetInstance(int fd) {
+  lock_guard<mutex> lock(s_lock);
+  if (!s_drm_instance) {
+    s_drm_instance = new DRMManager();
+
+    int ret = s_drm_instance ? s_drm_instance->Init(fd) : DRM_ERR_INVALID;
+    if (ret) {
+      delete s_drm_instance;
+      s_drm_instance = nullptr;
+    }
+  }
+
+  return s_drm_instance;
+}
+
+void DRMManager::Destroy() {
+  lock_guard<mutex> lock(s_lock);
+  if (s_drm_instance) {
+    delete s_drm_instance;
+    s_drm_instance = nullptr;
+  }
+}
+
+int DRMManager::Init(int drm_fd) {
+  fd_ = drm_fd;
+
+  drmSetClientCap(fd_, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+  drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
+
+  drmModeRes *resource = drmModeGetResources(fd_);
+  if (resource == NULL) {
+    DRM_LOGE("drmModeGetResources failed");
+    return DRM_ERR_INVALID;
+  }
+
+  conn_mgr_ = new DRMConnectorManager(fd_);
+  if (!conn_mgr_) {
+    DRM_LOGE("Failed to get Connector Mgr");
+    return DRM_ERR_INVALID;
+  }
+  conn_mgr_->Init(resource);
+
+  encoder_mgr_ = new DRMEncoderManager(fd_);
+  if (!encoder_mgr_) {
+    DRM_LOGE("Failed to get Encoder Mgr");
+    return DRM_ERR_INVALID;
+  }
+  encoder_mgr_->Init(resource);
+
+  crtc_mgr_ = new DRMCrtcManager(fd_);
+  if (!crtc_mgr_) {
+    DRM_LOGE("Failed to get Crtc Mgr");
+    return DRM_ERR_INVALID;
+  }
+  crtc_mgr_->Init(resource);
+
+  plane_mgr_ = new DRMPlaneManager(fd_);
+  if (!plane_mgr_) {
+    DRM_LOGE("Failed to get Plane Mgr");
+    return DRM_ERR_INVALID;
+  }
+  plane_mgr_->Init();
+
+  dpps_mgr_intf_ = GetDppsManagerIntf();
+  if (dpps_mgr_intf_)
+    dpps_mgr_intf_->Init(fd_, resource);
+  drmModeFreeResources(resource);
+
+  return 0;
+}
+
+int DRMManager::GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info) {
+  *info = {};
+  return conn_mgr_->GetConnectorInfo(conn_id, info);
+}
+
+int DRMManager::GetConnectorsInfo(DRMConnectorsInfo *infos) {
+  *infos = {};
+  int ret = -ENODEV;
+  std::vector<uint32_t> conn_ids;
+  conn_mgr_->Update();
+  conn_mgr_->GetConnectorList(&conn_ids);
+  for (auto iter : conn_ids) {
+    DRMConnectorInfo info;
+    ret = GetConnectorInfo(iter, &info);
+    if (!ret) {
+      (*infos)[iter] = info;
+    } else {
+      break;
+    }
+  }
+
+  return ret;
+}
+
+int DRMManager::GetEncoderInfo(uint32_t encoder_id, DRMEncoderInfo *info) {
+  *info = {};
+  return encoder_mgr_->GetEncoderInfo(encoder_id, info);
+}
+
+int DRMManager::GetEncodersInfo(DRMEncodersInfo *infos) {
+  *infos = {};
+  int ret = -ENODEV;
+  std::vector<uint32_t> encoder_ids;
+  encoder_mgr_->GetEncoderList(&encoder_ids);
+  for (auto iter : encoder_ids) {
+    DRMEncoderInfo info;
+    ret = GetEncoderInfo(iter, &info);
+    if (!ret) {
+      (*infos)[iter] = info;
+    } else {
+      break;
+    }
+  }
+
+  return ret;
+}
+
+int DRMManager::GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info) {
+  *info = {};
+  return crtc_mgr_->GetCrtcInfo(crtc_id, info);
+}
+
+void DRMManager::GetPlanesInfo(DRMPlanesInfo *info) {
+  plane_mgr_->GetPlanesInfo(info);
+}
+
+void DRMManager::GetCrtcPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info) {
+  crtc_mgr_->GetPPInfo(crtc_id, info);
+}
+
+DRMPlaneManager *DRMManager::GetPlaneMgr() {
+  return plane_mgr_;
+}
+
+DRMConnectorManager *DRMManager::GetConnectorMgr() {
+  return conn_mgr_;
+}
+
+DRMEncoderManager *DRMManager::GetEncoderMgr() {
+  return encoder_mgr_;
+}
+
+DRMCrtcManager *DRMManager::GetCrtcMgr() {
+  return crtc_mgr_;
+}
+
+DRMDppsManagerIntf *DRMManager::GetDppsMgrIntf() {
+  return dpps_mgr_intf_;
+}
+
+int DRMManager::RegisterDisplay(DRMDisplayType disp_type, DRMDisplayToken *token) {
+  int ret = conn_mgr_->Reserve(disp_type, token);
+  if (ret) {
+    DRM_LOGE("Error reserving connector for display type %d. Error = %d (%s)", disp_type, ret,
+             strerror(abs(ret)));
+    return ret;
+  }
+
+  ret = encoder_mgr_->Reserve(disp_type, token);
+  if (ret) {
+    DRM_LOGE("Error reserving encoder for display type %d. Error = %d (%s)", disp_type, ret,
+             strerror(abs(ret)));
+    conn_mgr_->Free(*token);
+    return ret;
+  }
+
+  ret = crtc_mgr_->Reserve(disp_type, token);
+  if (ret) {
+    DRM_LOGE("Error reserving crtc for display type %d. Error = %d (%s)", disp_type, ret,
+             strerror(abs(ret)));
+    encoder_mgr_->Free(*token);
+    conn_mgr_->Free(*token);
+    return ret;
+  }
+
+  return 0;
+}
+
+int DRMManager::RegisterDisplay(int32_t display_id, DRMDisplayToken *token) {
+  int ret = conn_mgr_->Reserve(display_id, token);
+  if (ret) {
+    DRM_LOGE("Error reserving connector %d. Error = %d (%s)", display_id, ret, strerror(abs(ret)));
+    return ret;
+  }
+
+  DRMDisplayType disp_type;
+  DRMConnectorInfo conn_info = {};
+  ret = conn_mgr_->GetConnectorInfo(display_id, &conn_info);
+  if (ret) {
+    DLOGE("Failed getting info for connector id %u. Error: %d (%s)", display_id, ret,
+          strerror(abs(ret)));
+    conn_mgr_->Free(*token);
+    return ret;
+  }
+
+  switch (conn_info.type) {
+    case DRM_MODE_CONNECTOR_DSI:
+      disp_type = DRMDisplayType::PERIPHERAL;
+      break;
+    case DRM_MODE_CONNECTOR_TV:
+    case DRM_MODE_CONNECTOR_HDMIA:
+    case DRM_MODE_CONNECTOR_HDMIB:
+    case DRM_MODE_CONNECTOR_DisplayPort:
+    case DRM_MODE_CONNECTOR_VGA:
+      disp_type = DRMDisplayType::TV;
+      break;
+    case DRM_MODE_CONNECTOR_VIRTUAL:
+      disp_type = DRMDisplayType::VIRTUAL;
+      break;
+    default:
+      DRM_LOGE("Error reserving encoder for display id %d. Found unsupported connector type %d.",
+               display_id, conn_info.type);
+      conn_mgr_->Free(*token);
+      return -ENODEV;
+  }
+  ret = encoder_mgr_->Reserve(disp_type, token);
+  if (ret) {
+    DRM_LOGE("Error reserving encoder for display %d-%d. Error: %d (%s)", display_id, disp_type,
+             strerror(abs(ret)));
+    conn_mgr_->Free(*token);
+    return ret;
+  }
+
+  ret = crtc_mgr_->Reserve(display_id, token);
+  if (ret) {
+    DRM_LOGE("Error reserving crtc for display %d-%d. Error: %d (%s)", display_id, disp_type,
+             strerror(abs(ret)));
+    encoder_mgr_->Free(*token);
+    conn_mgr_->Free(*token);
+    return ret;
+  }
+
+  return 0;
+}
+
+void DRMManager::UnregisterDisplay(const DRMDisplayToken &token) {
+  conn_mgr_->Free(token);
+  encoder_mgr_->Free(token);
+  crtc_mgr_->Free(token);
+}
+
+DRMManager::~DRMManager() {
+  if (conn_mgr_) {
+    conn_mgr_->DeInit();
+    delete conn_mgr_;
+    conn_mgr_ = NULL;
+  }
+  if (encoder_mgr_) {
+    encoder_mgr_->DeInit();
+    delete encoder_mgr_;
+    encoder_mgr_ = NULL;
+  }
+  if (crtc_mgr_) {
+    crtc_mgr_->DeInit();
+    delete crtc_mgr_;
+    crtc_mgr_ = NULL;
+  }
+  if (plane_mgr_) {
+    plane_mgr_->DeInit();
+    delete plane_mgr_;
+    plane_mgr_ = NULL;
+  }
+}
+
+int DRMManager::CreateAtomicReq(const DRMDisplayToken &token, DRMAtomicReqInterface **intf) {
+  DRMAtomicReq *req = new DRMAtomicReq(fd_, this);
+  int ret = req ? req->Init(token) : -ENOMEM;
+
+  if (ret < 0) {
+    DRM_LOGE("Initializing DRMAtomicReqInterface failed with error %d (%s)", ret,
+             strerror(abs(ret)));
+    delete req;
+    return ret;
+  }
+  *intf = req;
+
+  return 0;
+}
+
+int DRMManager::DestroyAtomicReq(DRMAtomicReqInterface *intf) {
+  delete intf;
+  return 0;
+}
+
+int DRMManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
+  plane_mgr_->SetScalerLUT(lut_info);
+  crtc_mgr_->SetScalerLUT(lut_info);
+  return 0;
+}
+
+int DRMManager::UnsetScalerLUT() {
+  plane_mgr_->UnsetScalerLUT();
+  crtc_mgr_->UnsetScalerLUT();
+  return 0;
+}
+
+void DRMManager::GetDppsFeatureInfo(DRMDppsFeatureInfo *info) {
+  if (dpps_mgr_intf_)
+    dpps_mgr_intf_->GetDppsFeatureInfo(info);
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_manager.h b/sde-drm/drm_manager.h
new file mode 100644
index 0000000..ff55ccb
--- /dev/null
+++ b/sde-drm/drm_manager.h
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2019, 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 __DRM_MANAGER_H__
+#define __DRM_MANAGER_H__
+
+#include <drm_interface.h>
+#include <mutex>
+#include "drm_dpps_mgr_intf.h"
+
+namespace sde_drm {
+
+class DRMAtomicReqInterface;
+class DRMPlaneManager;
+class DRMPlane;
+class DRMConnectorManager;
+class DRMEncoderManager;
+class DRMConnnector;
+class DRMCrtcManager;
+class DRMCrtc;
+
+class DRMManager : public DRMManagerInterface {
+ public:
+  virtual ~DRMManager();
+  virtual int RegisterDisplay(DRMDisplayType disp_type, DRMDisplayToken *token);
+  virtual int RegisterDisplay(int32_t display_id, DRMDisplayToken *token);
+  virtual void UnregisterDisplay(const DRMDisplayToken &token);
+  virtual void GetPlanesInfo(DRMPlanesInfo *info);
+  virtual int GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info);
+  virtual int GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info);
+  virtual int GetConnectorsInfo(DRMConnectorsInfo *infos);
+  virtual int GetEncoderInfo(uint32_t encoder_id, DRMEncoderInfo *info);
+  virtual int GetEncodersInfo(DRMEncodersInfo *infos);
+  virtual void GetCrtcPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info);
+  virtual int CreateAtomicReq(const DRMDisplayToken &token, DRMAtomicReqInterface **intf);
+  virtual int DestroyAtomicReq(DRMAtomicReqInterface *intf);
+  virtual int SetScalerLUT(const DRMScalerLUTInfo &lut_info);
+  virtual int UnsetScalerLUT();
+  virtual void GetDppsFeatureInfo(DRMDppsFeatureInfo *info);
+
+  DRMPlaneManager *GetPlaneMgr();
+  DRMConnectorManager *GetConnectorMgr();
+  DRMEncoderManager *GetEncoderMgr();
+  DRMCrtcManager *GetCrtcMgr();
+  DRMDppsManagerIntf *GetDppsMgrIntf();
+
+  static DRMManager *GetInstance(int fd);
+  static void Destroy();
+
+ private:
+  int Init(int drm_fd);
+
+  int fd_ = -1;
+  DRMPlaneManager *plane_mgr_ = {};
+  DRMConnectorManager *conn_mgr_ = {};
+  DRMEncoderManager *encoder_mgr_ = {};
+  DRMCrtcManager *crtc_mgr_ = {};
+  DRMDppsManagerIntf *dpps_mgr_intf_ = {};
+
+  static DRMManager *s_drm_instance;
+  static std::mutex s_lock;
+};
+
+}  // namespace sde_drm
+#endif  // __DRM_MANAGER_H__
diff --git a/sde-drm/drm_plane.cpp b/sde-drm/drm_plane.cpp
new file mode 100644
index 0000000..033aced
--- /dev/null
+++ b/sde-drm/drm_plane.cpp
@@ -0,0 +1,987 @@
+/*
+* Copyright (c) 2019, 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 <stdint.h>
+#include <stdlib.h>
+#include <drm.h>
+// The 3 headers above are a workaround to prevent kernel drm.h from being used that has the
+// "virtual" keyword used for a variable. In future replace libdrm version drm.h with kernel
+// version drm/drm.h
+#include <drm_logger.h>
+#include <drm/drm_fourcc.h>
+#include <drm/sde_drm.h>
+
+#include <cstring>
+#include <map>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "drm_utils.h"
+#include "drm_plane.h"
+#include "drm_property.h"
+
+namespace sde_drm {
+
+using std::map;
+using std::string;
+using std::map;
+using std::pair;
+using std::vector;
+using std::unique_ptr;
+using std::tuple;
+using std::stringstream;
+
+static struct sde_drm_csc_v1 csc_10bit_convert[kCscTypeMax] = {
+  [kCscYuv2Rgb601L] = {
+    {
+      0x12A000000, 0x000000000,  0x198800000,
+      0x12A000000, 0x7F9B800000, 0x7F30000000,
+      0x12A000000, 0x204800000,  0x000000000,
+    },
+    { 0xffc0, 0xfe00, 0xfe00,},
+    { 0x0, 0x0, 0x0,},
+    { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+  },
+  [kCscYuv2Rgb601FR] = {
+    {
+      0x100000000, 0x0, 0x167000000,
+      0x100000000, 0x7fa8000000, 0x7f49000000,
+      0x100000000, 0x1c5800000, 0x0,
+    },
+    { 0x0000, 0xfe00, 0xfe00,},
+    { 0x0, 0x0, 0x0,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+  },
+  [kCscYuv2Rgb709L] = {
+    {
+      0x12a000000, 0x0, 0x1cb000000,
+      0x12a000000, 0x7fc9800000, 0x7f77800000,
+      0x12a000000, 0x21d000000, 0x0,
+    },
+    { 0xffc0, 0xfe00, 0xfe00,},
+    { 0x0, 0x0, 0x0,},
+    { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+  },
+  [kCscYuv2Rgb2020L] = {
+    {
+      0x12b000000, 0x0, 0x1af000000,
+      0x12b000000, 0x7fd0000000, 0x7f59000000,
+      0x12b000000, 0x226000000, 0x0,
+    },
+    { 0xffc0, 0xfe00, 0xfe00,},
+    { 0x0, 0x0, 0x0,},
+    { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+  },
+  [kCscYuv2Rgb2020FR] = {
+    {
+      0x100000000, 0x0, 0x179800000,
+      0x100000000, 0x7fd6000000, 0x7f6d800000,
+      0x100000000, 0x1e1800000, 0x0,
+    },
+    { 0x0000, 0xfe00, 0xfe00,},
+    { 0x0, 0x0, 0x0,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+    { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+  },
+};
+
+static uint8_t REFLECT_X = 0;
+static uint8_t REFLECT_Y = 0;
+static uint8_t ROTATE_90 = 0;
+static uint8_t ROTATE_0 = 0;
+
+// FB Secure Modes
+static uint8_t NON_SECURE = 0;
+static uint8_t SECURE = 1;
+static uint8_t NON_SECURE_DIR_TRANSLATION = 2;
+static uint8_t SECURE_DIR_TRANSLATION = 3;
+
+// Multi rect modes
+static uint8_t MULTIRECT_NONE = 0;
+static uint8_t MULTIRECT_PARALLEL = 1;
+static uint8_t MULTIRECT_SERIAL = 2;
+
+static void SetRect(DRMRect &source, drm_clip_rect *target) {
+  target->x1 = uint16_t(source.left);
+  target->y1 = uint16_t(source.top);
+  target->x2 = uint16_t(source.right);
+  target->y2 = uint16_t(source.bottom);
+}
+
+static void PopulateReflect(drmModePropertyRes *prop) {
+  if (REFLECT_X) {
+    return;
+  }
+
+  if (!drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
+    return;
+  }
+
+  for (auto i = 0; i < prop->count_enums; i++) {
+    string enum_name(prop->enums[i].name);
+    if (enum_name == "reflect-x") {
+      REFLECT_X = prop->enums[i].value;
+    } else if (enum_name == "reflect-y") {
+      REFLECT_Y = prop->enums[i].value;
+    } else if (enum_name == "rotate-90") {
+      ROTATE_90 = prop->enums[i].value;
+    } else if (enum_name == "rotate-0") {
+      ROTATE_0 = prop->enums[i].value;
+    }
+  }
+}
+
+static void PopulateSecureModes(drmModePropertyRes *prop) {
+  static bool secure_modes_populated = false;
+  if (!secure_modes_populated) {
+    for (auto i = 0; i < prop->count_enums; i++) {
+      string enum_name(prop->enums[i].name);
+      if (enum_name == "non_sec") {
+        NON_SECURE = prop->enums[i].value;
+      } else if (enum_name == "sec") {
+        SECURE = prop->enums[i].value;
+      } else if (enum_name == "non_sec_direct_translation") {
+        NON_SECURE_DIR_TRANSLATION = prop->enums[i].value;
+      } else if (enum_name == "sec_direct_translation") {
+        SECURE_DIR_TRANSLATION = prop->enums[i].value;
+      }
+    }
+    secure_modes_populated = true;
+  }
+}
+
+static InlineRotationVersion PopulateInlineRotationVersion(uint32_t ver) {
+  switch (ver) {
+    case 0x0000: return InlineRotationVersion::kInlineRotationNone;
+    case 0x0001: return InlineRotationVersion::kInlineRotationV1;
+    default: return InlineRotationVersion::kInlineRotationNone;
+  }
+}
+
+static QSEEDStepVersion PopulateQseedStepVersion(uint32_t hw_ver) {
+  switch (hw_ver) {
+    case 0x1003: return QSEEDStepVersion::V3;
+    case 0x1004: return QSEEDStepVersion::V4;
+    case 0x2004: return QSEEDStepVersion::V3LITE_V4;
+    case 0x3000: return QSEEDStepVersion::V3LITE_V5;
+    // default value. also corresponds to (hw_ver == 0x1002)
+    default: return QSEEDStepVersion::V2;
+  }
+}
+
+static void PopulateMultiRectModes(drmModePropertyRes *prop) {
+  static bool multirect_modes_populated = false;
+  if (!multirect_modes_populated) {
+    for (auto i = 0; i < prop->count_enums; i++) {
+      string enum_name(prop->enums[i].name);
+      if (enum_name == "none") {
+        MULTIRECT_NONE = prop->enums[i].value;
+      } else if (enum_name == "parallel") {
+        MULTIRECT_PARALLEL = prop->enums[i].value;
+      } else if (enum_name == "serial") {
+        MULTIRECT_SERIAL = prop->enums[i].value;
+      }
+    }
+    multirect_modes_populated = true;
+  }
+}
+
+#define __CLASS__ "DRMPlaneManager"
+
+DRMPlaneManager::DRMPlaneManager(int fd) : fd_(fd) {}
+
+void DRMPlaneManager::Init() {
+  drmModePlaneRes *resource = drmModeGetPlaneResources(fd_);
+  if (!resource) {
+    return;
+  }
+
+  for (uint32_t i = 0; i < resource->count_planes; i++) {
+    // The enumeration order itself is the priority from high to low
+    unique_ptr<DRMPlane> plane(new DRMPlane(fd_, i));
+    drmModePlane *libdrm_plane = drmModeGetPlane(fd_, resource->planes[i]);
+    if (libdrm_plane) {
+      plane->InitAndParse(libdrm_plane);
+      plane_pool_[resource->planes[i]] = std::move(plane);
+    } else {
+      DRM_LOGE("Critical error: drmModeGetPlane() failed for plane %d.", resource->planes[i]);
+    }
+  }
+
+  drmModeFreePlaneResources(resource);
+}
+
+void DRMPlaneManager::DumpByID(uint32_t id) {
+  plane_pool_.at(id)->Dump();
+}
+
+void DRMPlaneManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args) {
+  auto it = plane_pool_.find(obj_id);
+  if (it == plane_pool_.end()) {
+    DRM_LOGE("Invalid plane id %d", obj_id);
+    return;
+  }
+
+  if (code == DRMOps::PLANE_SET_SCALER_CONFIG) {
+    if (it->second->ConfigureScalerLUT(req, dir_lut_blob_id_, cir_lut_blob_id_,
+                                       sep_lut_blob_id_)) {
+      DRM_LOGD("Plane %d: Configuring scaler LUTs", obj_id);
+    }
+  }
+
+  it->second->Perform(code, req, args);
+}
+
+void DRMPlaneManager::Perform(DRMOps code, drmModeAtomicReq *req, uint32_t obj_id, ...) {
+  va_list args;
+  va_start(args, obj_id);
+  Perform(code, obj_id, req, args);
+  va_end(args);
+}
+
+void DRMPlaneManager::DumpAll() {
+  for (uint32_t i = 0; i < plane_pool_.size(); i++) {
+    plane_pool_[i]->Dump();
+  }
+}
+
+void DRMPlaneManager::GetPlanesInfo(DRMPlanesInfo *info) {
+  for (auto &plane : plane_pool_) {
+    info->push_back(std::make_pair(plane.first, plane.second->GetPlaneTypeInfo()));
+  }
+}
+
+void DRMPlaneManager::UnsetUnusedPlanes(uint32_t crtc_id, drmModeAtomicReq *req) {
+  // Unset planes that were assigned to the crtc referred to by crtc_id but are not requested
+  // in this round
+  for (auto &plane : plane_pool_) {
+    uint32_t assigned_crtc = 0;
+    uint32_t requested_crtc = 0;
+    plane.second->GetAssignedCrtc(&assigned_crtc);
+    plane.second->GetRequestedCrtc(&requested_crtc);
+    if (assigned_crtc == crtc_id && requested_crtc == 0) {
+      plane.second->Unset(req);
+    }
+  }
+}
+
+void DRMPlaneManager::RetainPlanes(uint32_t crtc_id) {
+  for (auto &plane : plane_pool_) {
+    uint32_t assigned_crtc = 0;
+    plane.second->GetAssignedCrtc(&assigned_crtc);
+    if (assigned_crtc == crtc_id) {
+      // Pretend this plane was requested by client
+      plane.second->SetRequestedCrtc(crtc_id);
+      const uint32_t plane_id = plane.first;
+      DRM_LOGD("Plane %d: Retaining on CRTC %d", plane_id, crtc_id);
+    }
+  }
+}
+
+void DRMPlaneManager::PostValidate(uint32_t crtc_id, bool success) {
+  for (auto &plane : plane_pool_) {
+    plane.second->PostValidate(crtc_id, success);
+  }
+}
+
+void DRMPlaneManager::PostCommit(uint32_t crtc_id, bool success) {
+  DRM_LOGD("crtc %d", crtc_id);
+  for (auto &plane : plane_pool_) {
+    plane.second->PostCommit(crtc_id, success);
+  }
+}
+
+void DRMPlaneManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
+  if (lut_info.dir_lut_size) {
+    drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.dir_lut),
+                              lut_info.dir_lut_size, &dir_lut_blob_id_);
+  }
+  if (lut_info.cir_lut_size) {
+    drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.cir_lut),
+                              lut_info.cir_lut_size, &cir_lut_blob_id_);
+  }
+  if (lut_info.sep_lut_size) {
+    drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.sep_lut),
+                              lut_info.sep_lut_size, &sep_lut_blob_id_);
+  }
+}
+
+void DRMPlaneManager::UnsetScalerLUT() {
+  if (dir_lut_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_);
+    dir_lut_blob_id_ = 0;
+  }
+  if (cir_lut_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_);
+    cir_lut_blob_id_ = 0;
+  }
+  if (sep_lut_blob_id_) {
+    drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_);
+    sep_lut_blob_id_ = 0;
+  }
+}
+
+// ==============================================================================================//
+
+#undef __CLASS__
+#define __CLASS__ "DRMPlane"
+
+DRMPlane::DRMPlane(int fd, uint32_t priority) : fd_(fd), priority_(priority) {}
+
+DRMPlane::~DRMPlane() {
+  drmModeFreePlane(drm_plane_);
+}
+
+void DRMPlane::GetTypeInfo(const PropertyMap &prop_map) {
+  uint64_t blob_id;
+  drmModePropertyRes *prop;
+  DRMPlaneTypeInfo *info = &plane_type_info_;
+  // Ideally we should check if this property type is a blob and then proceed.
+  std::tie(blob_id, prop) = prop_map.at(DRMProperty::CAPABILITIES);
+  drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+  if (!blob) {
+    return;
+  }
+
+  const char *fmt_str = reinterpret_cast<const char *>(blob->data);
+  info->max_linewidth = 2560;
+  info->max_scaler_linewidth = 2560;
+  info->max_rotation_linewidth = 1088;
+  info->max_upscale = 1;
+  info->max_downscale = 1;
+  info->max_horizontal_deci = 0;
+  info->max_vertical_deci = 0;
+  info->master_plane_id = 0;
+  if (info->type == DRMPlaneType::CURSOR) {
+    info->max_linewidth = 128;
+  }
+  // TODO(user): change default to V2 once we start getting V3 via capabilities blob
+  info->qseed3_version = QSEEDStepVersion::V3;
+  info->has_excl_rect = has_excl_rect_;
+
+  // We may have multiple lines with each one dedicated for something specific
+  // like formats etc
+  stringstream stream(fmt_str);
+  string line = {};
+  string pixel_formats = "pixel_formats=";
+  string max_linewidth = "max_linewidth=";
+  string max_upscale = "max_upscale=";
+  string max_downscale = "max_downscale=";
+  string max_horizontal_deci = "max_horizontal_deci=";
+  string max_vertical_deci = "max_vertical_deci=";
+  string master_plane_id = "primary_smart_plane_id=";
+  string max_pipe_bw = "max_per_pipe_bw=";
+  string scaler_version = "scaler_step_ver=";
+  string block_sec_ui = "block_sec_ui=";
+  string true_inline_rot_rev = "true_inline_rot_rev=";
+  string inline_rot_pixel_formats = "inline_rot_pixel_formats=";
+
+  while (std::getline(stream, line)) {
+    if (line.find(inline_rot_pixel_formats) != string::npos) {
+      vector<pair<uint32_t, uint64_t>> inrot_formats_supported;
+      ParseFormats(line.erase(0, inline_rot_pixel_formats.length()), &inrot_formats_supported);
+      info->inrot_fmts_supported = std::move(inrot_formats_supported);
+    } else if (line.find(pixel_formats) != string::npos) {
+      vector<pair<uint32_t, uint64_t>> formats_supported;
+      ParseFormats(line.erase(0, pixel_formats.length()), &formats_supported);
+      info->formats_supported = std::move(formats_supported);
+    } else if (line.find(max_linewidth) != string::npos) {
+      info->max_linewidth = std::stoi(line.erase(0, max_linewidth.length()));
+    } else if (line.find(max_upscale) != string::npos) {
+      info->max_upscale = std::stoi(line.erase(0, max_upscale.length()));
+    } else if (line.find(max_downscale) != string::npos) {
+      info->max_downscale = std::stoi(line.erase(0, max_downscale.length()));
+    } else if (line.find(max_horizontal_deci) != string::npos) {
+      info->max_horizontal_deci = std::stoi(line.erase(0, max_horizontal_deci.length()));
+    } else if (line.find(max_vertical_deci) != string::npos) {
+      info->max_vertical_deci = std::stoi(line.erase(0, max_vertical_deci.length()));
+    } else if (line.find(master_plane_id) != string::npos) {
+      info->master_plane_id = std::stoi(line.erase(0, master_plane_id.length()));
+      DRM_LOGI("info->master_plane_id: detected master_plane=%d", info->master_plane_id);
+    } else if (line.find(max_pipe_bw) != string::npos) {
+      info->max_pipe_bandwidth = std::stoull(line.erase(0, max_pipe_bw.length()));
+    } else if (line.find(scaler_version) != string::npos) {
+      info->qseed3_version =
+        PopulateQseedStepVersion(std::stoi(line.erase(0, scaler_version.length())));
+    } else if (line.find(block_sec_ui) != string::npos) {
+      info->block_sec_ui = !!(std::stoi(line.erase(0, block_sec_ui.length())));
+    } else if (line.find(true_inline_rot_rev) != string::npos) {
+      info->inrot_version =
+        PopulateInlineRotationVersion(std::stoi(line.erase(0, true_inline_rot_rev.length())));
+    }
+  }
+
+  info->max_scaler_linewidth = (QSEEDStepVersion::V4 == info->qseed3_version) ? 2560 :
+                                info->max_linewidth;
+  drmModeFreePropertyBlob(blob);
+}
+
+void DRMPlane::ParseProperties() {
+  // Map of property name to current value and property info pointer
+  PropertyMap prop_map;
+  bool csc = false;
+  bool scaler = false;
+  bool cursor = false;
+  drmModeObjectProperties *props =
+      drmModeObjectGetProperties(fd_, drm_plane_->plane_id, DRM_MODE_OBJECT_PLANE);
+  if (!props || !props->props || !props->prop_values) {
+    drmModeFreeObjectProperties(props);
+    return;
+  }
+
+  for (uint32_t j = 0; j < props->count_props; j++) {
+    drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
+    if (!info) {
+      continue;
+    }
+
+    string property_name(info->name);
+    DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
+    if (prop_enum == DRMProperty::INVALID) {
+      DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
+      drmModeFreeProperty(info);
+      continue;
+    }
+
+    if (prop_enum == DRMProperty::EXCL_RECT) {
+      has_excl_rect_ = true;
+    }
+    if (prop_enum == DRMProperty::ROTATION) {
+      PopulateReflect(info);
+    } else if (prop_enum == DRMProperty::FB_TRANSLATION_MODE) {
+      PopulateSecureModes(info);
+    } else if (prop_enum == DRMProperty::MULTIRECT_MODE) {
+      PopulateMultiRectModes(info);
+      plane_type_info_.multirect_prop_present = true;
+    }
+
+    prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
+    prop_map[prop_enum] = std::make_tuple(props->prop_values[j], info);
+    csc = prop_enum == DRMProperty::CSC_V1 ? true : csc;
+    scaler = (prop_enum == DRMProperty::SCALER_V1 || prop_enum == DRMProperty::SCALER_V2) \
+      ? true : scaler;
+    cursor = (prop_enum == DRMProperty::TYPE && props->prop_values[j] == DRM_PLANE_TYPE_CURSOR) \
+      ? true : cursor;
+
+    // Tone mapping properties.
+    if (prop_enum == DRMProperty::INVERSE_PMA) {
+      plane_type_info_.inverse_pma = true;
+    }
+
+    if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::CSC_DMA_V1 &&
+        (uint32_t)prop_enum <= (uint32_t)DRMProperty::CSC_DMA_V1) {
+      plane_type_info_.dgm_csc_version =
+          ((uint32_t)prop_enum - (uint32_t)DRMProperty::CSC_DMA_V1 + 1);
+    }
+
+    if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 &&
+        (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5) {
+      plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_IGC] =
+          ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 + 5);
+    }
+    if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 &&
+        (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5) {
+     plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_GC] =
+         ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 + 5);
+    }
+    if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 &&
+        (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5) {
+      plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_1D_IGC] =
+          ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 + 5);
+    }
+    if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 &&
+        (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5) {
+      plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_3D_GAMUT] =
+          ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 + 5);
+    }
+  }
+
+  DRMPlaneType type = DRMPlaneType::DMA;
+  if (csc && scaler) {
+    type = DRMPlaneType::VIG;
+  } else if (cursor) {
+    type = DRMPlaneType::CURSOR;
+  }
+
+  plane_type_info_.type = type;
+  GetTypeInfo(prop_map);
+
+  for (auto &prop : prop_map) {
+    drmModeFreeProperty(std::get<1>(prop.second));
+  }
+
+  drmModeFreeObjectProperties(props);
+}
+
+void DRMPlane::InitAndParse(drmModePlane *plane) {
+  drm_plane_ = plane;
+  ParseProperties();
+
+  unique_ptr<DRMPPManager> pp_mgr(new DRMPPManager(fd_));
+  pp_mgr_ = std::move(pp_mgr);
+  pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_PLANE);
+}
+
+bool DRMPlane::ConfigureScalerLUT(drmModeAtomicReq *req, uint32_t dir_lut_blob_id,
+                                  uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
+  if (plane_type_info_.type != DRMPlaneType::VIG || is_lut_configured_) {
+    return false;
+  }
+
+  if (dir_lut_blob_id) {
+    AddProperty(req, drm_plane_->plane_id,
+                prop_mgr_.GetPropertyId(DRMProperty::LUT_ED),
+                dir_lut_blob_id, false /* cache */, tmp_prop_val_map_);
+  }
+  if (cir_lut_blob_id) {
+    AddProperty(req, drm_plane_->plane_id,
+                prop_mgr_.GetPropertyId(DRMProperty::LUT_CIR),
+                cir_lut_blob_id, false /* cache */, tmp_prop_val_map_);
+  }
+  if (sep_lut_blob_id) {
+    AddProperty(req, drm_plane_->plane_id,
+                prop_mgr_.GetPropertyId(DRMProperty::LUT_SEP),
+                sep_lut_blob_id, false /* cache */, tmp_prop_val_map_);
+  }
+
+  return true;
+}
+
+void DRMPlane::SetExclRect(drmModeAtomicReq *req, DRMRect rect) {
+  auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::EXCL_RECT);
+  drm_clip_rect clip_rect;
+  SetRect(rect, &clip_rect);
+  excl_rect_copy_ = clip_rect;
+  AddProperty(req, drm_plane_->plane_id, prop_id, reinterpret_cast<uint64_t>
+              (&excl_rect_copy_), false /* cache */, tmp_prop_val_map_);
+  DRM_LOGD("Plane %d: Setting exclusion rect [x,y,w,h][%d,%d,%d,%d]", drm_plane_->plane_id,
+           clip_rect.x1, clip_rect.y1, (clip_rect.x2 - clip_rect.x1),
+           (clip_rect.y2 - clip_rect.y1));
+}
+
+bool DRMPlane::SetCscConfig(drmModeAtomicReq *req, DRMCscType csc_type) {
+  if (plane_type_info_.type != DRMPlaneType::VIG) {
+    return false;
+  }
+
+  if (csc_type > kCscTypeMax) {
+    return false;
+  }
+
+  if (!prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_V1)) {
+    return false;
+  }
+
+  auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::CSC_V1);
+  if (csc_type == kCscTypeMax) {
+    AddProperty(req, drm_plane_->plane_id, prop_id, 0, false /* cache */, tmp_prop_val_map_);
+  } else {
+    csc_config_copy_ = csc_10bit_convert[csc_type];
+    AddProperty(req, drm_plane_->plane_id, prop_id,
+                reinterpret_cast<uint64_t>(&csc_config_copy_), false /* cache */,
+                tmp_prop_val_map_);
+  }
+
+  return true;
+}
+
+bool DRMPlane::SetScalerConfig(drmModeAtomicReq *req, uint64_t handle) {
+  if (plane_type_info_.type != DRMPlaneType::VIG) {
+    return false;
+  }
+
+  if (prop_mgr_.IsPropertyAvailable(DRMProperty::SCALER_V2)) {
+    auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::SCALER_V2);
+    sde_drm_scaler_v2 *scaler_v2_config = reinterpret_cast<sde_drm_scaler_v2 *>(handle);
+    uint64_t scaler_data = 0;
+    // The address needs to be valid even after async commit, since we are sending address to
+    // driver directly, instead of blob. So we need to copy over contents that client sent. Client
+    // may have sent an address of object on stack which will be released after this call.
+    scaler_v2_config_copy_ = *scaler_v2_config;
+    if (scaler_v2_config_copy_.enable) {
+      scaler_data = reinterpret_cast<uint64_t>(&scaler_v2_config_copy_);
+    }
+    AddProperty(req, drm_plane_->plane_id, prop_id, scaler_data, false /* cache */,
+                tmp_prop_val_map_);
+    return true;
+  }
+
+  return false;
+}
+
+void DRMPlane::SetDecimation(drmModeAtomicReq *req, uint32_t prop_id, uint32_t prop_value) {
+  if (plane_type_info_.type == DRMPlaneType::DMA || plane_type_info_.master_plane_id) {
+    // if value is 0, client is just trying to clear previous decimation, so bail out silently
+    if (prop_value > 0) {
+      DRM_LOGE("Plane %d: Setting decimation %d is not supported.", drm_plane_->plane_id,
+               prop_value);
+    }
+    return;
+  }
+
+  // TODO(user): Currently a ViG plane in smart DMA mode could receive a non-zero decimation value
+  // but there is no good way to catch. In any case fix will be in client
+  AddProperty(req, drm_plane_->plane_id, prop_id, prop_value, true /* cache */, tmp_prop_val_map_);
+  DRM_LOGD("Plane %d: Setting decimation %d", drm_plane_->plane_id, prop_value);
+}
+
+void DRMPlane::PostValidate(uint32_t crtc_id, bool /*success*/) {
+  if (requested_crtc_id_ == crtc_id) {
+    SetRequestedCrtc(0);
+    tmp_prop_val_map_ = committed_prop_val_map_;
+  }
+}
+
+void DRMPlane::PostCommit(uint32_t crtc_id, bool success) {
+  DRM_LOGD("crtc %d", crtc_id);
+  if (!success) {
+    // To reset
+    PostValidate(crtc_id, success);
+    return;
+  }
+
+  uint32_t assigned_crtc = 0;
+  uint32_t requested_crtc = 0;
+
+  GetAssignedCrtc(&assigned_crtc);
+  GetRequestedCrtc(&requested_crtc);
+
+  // In future, it is possible that plane is already attached in case of continuous splash. This
+  // will cause the first commit to only unstage pipes. We want to mark luts as configured only
+  // when they really are, which typically happens if a crtc is requested for a plane
+  if (requested_crtc == crtc_id && !is_lut_configured_) {
+    is_lut_configured_ = true;
+  }
+
+  if (requested_crtc && assigned_crtc && requested_crtc != assigned_crtc) {
+    // We should never be here
+    DRM_LOGE("Found plane %d switching from crtc %d to crtc %d", drm_plane_->plane_id,
+             assigned_crtc, requested_crtc);
+  }
+
+  // If we have set a pipe OR unset a pipe during commit, update states
+  if (requested_crtc == crtc_id || assigned_crtc == crtc_id) {
+    committed_prop_val_map_ = tmp_prop_val_map_;
+    SetAssignedCrtc(requested_crtc);
+    SetRequestedCrtc(0);
+  }
+}
+
+void DRMPlane::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
+  uint32_t prop_id = 0;
+  uint32_t obj_id = drm_plane_->plane_id;
+
+  switch (code) {
+    // TODO(user): Check if these exist in map before attempting to access
+    case DRMOps::PLANE_SET_SRC_RECT: {
+      DRMRect rect = va_arg(args, DRMRect);
+      // source co-ordinates accepted by DRM are 16.16 fixed point
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_X);
+      AddProperty(req, obj_id, prop_id, rect.left << 16, true /* cache */, tmp_prop_val_map_);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_Y);
+      AddProperty(req, obj_id, prop_id, rect.top << 16, true /* cache */, tmp_prop_val_map_);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_W);
+      AddProperty(req, obj_id, prop_id, (rect.right - rect.left) << 16, true /* cache */,
+                  tmp_prop_val_map_);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_H);
+      AddProperty(req, obj_id, prop_id, (rect.bottom - rect.top) << 16, true /* cache */,
+                  tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting crop [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
+               rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
+    } break;
+
+    case DRMOps::PLANE_SET_DST_RECT: {
+      DRMRect rect = va_arg(args, DRMRect);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_X);
+      AddProperty(req, obj_id, prop_id, rect.left, true /* cache */, tmp_prop_val_map_);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_Y);
+      AddProperty(req, obj_id, prop_id, rect.top, true /* cache */, tmp_prop_val_map_);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_W);
+      AddProperty(req, obj_id, prop_id, (rect.right - rect.left), true /* cache */,
+                  tmp_prop_val_map_);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_H);
+      AddProperty(req, obj_id, prop_id, (rect.bottom - rect.top), true /* cache */,
+                  tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting dst [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
+               rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
+    } break;
+    case DRMOps::PLANE_SET_EXCL_RECT: {
+      DRMRect excl_rect = va_arg(args, DRMRect);
+      SetExclRect(req, excl_rect);
+    } break;
+
+    case DRMOps::PLANE_SET_ZORDER: {
+      uint32_t zpos = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::ZPOS);
+      AddProperty(req, obj_id, prop_id, zpos, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGD("Plane %d: Setting z %d", obj_id, zpos);
+    } break;
+
+    case DRMOps::PLANE_SET_ROTATION: {
+      uint32_t rot_bit_mask = va_arg(args, uint32_t);
+      uint32_t drm_rot_bit_mask = 0;
+      if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_H)) {
+        drm_rot_bit_mask |= 1 << REFLECT_X;
+      }
+      if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_V)) {
+        drm_rot_bit_mask |= 1 << REFLECT_Y;
+      }
+      if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::ROT_90)) {
+        drm_rot_bit_mask |= 1 << ROTATE_90;
+      } else {
+        drm_rot_bit_mask |= 1 << ROTATE_0;
+      }
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::ROTATION);
+      AddProperty(req, obj_id, prop_id, drm_rot_bit_mask, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting rotation mask %x", obj_id, drm_rot_bit_mask);
+    } break;
+
+    case DRMOps::PLANE_SET_ALPHA: {
+      uint32_t alpha = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::ALPHA);
+      AddProperty(req, obj_id, prop_id, alpha, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting alpha %d", obj_id, alpha);
+    } break;
+
+    case DRMOps::PLANE_SET_BLEND_TYPE: {
+      uint32_t blending = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::BLEND_OP);
+      AddProperty(req, obj_id, prop_id, blending, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting blending %d", obj_id, blending);
+    } break;
+
+    case DRMOps::PLANE_SET_H_DECIMATION: {
+      uint32_t deci = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::H_DECIMATE);
+      SetDecimation(req, prop_id, deci);
+    } break;
+
+    case DRMOps::PLANE_SET_V_DECIMATION: {
+      uint32_t deci = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::V_DECIMATE);
+      SetDecimation(req, prop_id, deci);
+    } break;
+
+    case DRMOps::PLANE_SET_SRC_CONFIG: {
+      bool src_config = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_CONFIG);
+      AddProperty(req, obj_id, prop_id, src_config, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting src_config flags-%x", obj_id, src_config);
+    } break;
+
+    case DRMOps::PLANE_SET_CRTC: {
+      uint32_t crtc_id = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_ID);
+      AddProperty(req, obj_id, prop_id, crtc_id, true /* cache */, tmp_prop_val_map_);
+      SetRequestedCrtc(crtc_id);
+      DRM_LOGV("Plane %d: Setting crtc %d", obj_id, crtc_id);
+    } break;
+
+    case DRMOps::PLANE_SET_FB_ID: {
+      uint32_t fb_id = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::FB_ID);
+      AddProperty(req, obj_id, prop_id, fb_id, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting fb_id %d", obj_id, fb_id);
+    } break;
+
+    case DRMOps::PLANE_SET_ROT_FB_ID: {
+      uint32_t fb_id = va_arg(args, uint32_t);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::ROT_FB_ID);
+      drmModeAtomicAddProperty(req, obj_id, prop_id, fb_id);
+      DRM_LOGV("Plane %d: Setting rot_fb_id %d", obj_id, fb_id);
+    } break;
+
+    case DRMOps::PLANE_SET_INPUT_FENCE: {
+      int fence = va_arg(args, int);
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::INPUT_FENCE);
+      AddProperty(req, obj_id, prop_id, fence, false /* cache */, tmp_prop_val_map_);
+      DRM_LOGV("Plane %d: Setting input fence %d", obj_id, fence);
+    } break;
+
+    case DRMOps::PLANE_SET_SCALER_CONFIG: {
+      uint64_t handle = va_arg(args, uint64_t);
+      if (SetScalerConfig(req, handle)) {
+        DRM_LOGV("Plane %d: Setting scaler config", obj_id);
+      }
+    } break;
+
+    case DRMOps::PLANE_SET_FB_SECURE_MODE: {
+      int secure_mode = va_arg(args, int);
+      uint32_t fb_secure_mode = NON_SECURE;
+      switch (secure_mode) {
+        case (int)DRMSecureMode::NON_SECURE:
+          fb_secure_mode = NON_SECURE;
+          break;
+        case (int)DRMSecureMode::SECURE:
+          fb_secure_mode = SECURE;
+          break;
+        case (int)DRMSecureMode::NON_SECURE_DIR_TRANSLATION:
+          fb_secure_mode = NON_SECURE_DIR_TRANSLATION;
+          break;
+        case (int)DRMSecureMode::SECURE_DIR_TRANSLATION:
+          fb_secure_mode = SECURE_DIR_TRANSLATION;
+          break;
+        default:
+          DRM_LOGE("Invalid secure mode %d to set on plane %d", secure_mode, obj_id);
+          break;
+      }
+
+      prop_id = prop_mgr_.GetPropertyId(DRMProperty::FB_TRANSLATION_MODE);
+      AddProperty(req, obj_id, prop_id, fb_secure_mode, true /* cache */, tmp_prop_val_map_);
+      DRM_LOGD("Plane %d: Setting FB secure mode %d", obj_id, fb_secure_mode);
+    } break;
+
+    case DRMOps::PLANE_SET_CSC_CONFIG: {
+      uint32_t* csc_type = va_arg(args, uint32_t*);
+      if (csc_type) {
+        SetCscConfig(req, (DRMCscType)*csc_type);
+      }
+    } break;
+
+    case DRMOps::PLANE_SET_MULTIRECT_MODE: {
+      DRMMultiRectMode drm_multirect_mode = (DRMMultiRectMode)va_arg(args, uint32_t);
+      SetMultiRectMode(req, drm_multirect_mode);
+    } break;
+
+    case DRMOps::PLANE_SET_INVERSE_PMA: {
+       uint32_t pma = va_arg(args, uint32_t);
+       prop_id = prop_mgr_.GetPropertyId(DRMProperty::INVERSE_PMA);
+       AddProperty(req, obj_id, prop_id, pma, true /* cache */, tmp_prop_val_map_);
+       DRM_LOGD("Plane %d: %s inverse pma", obj_id, pma ? "Setting" : "Resetting");
+     } break;
+
+    case DRMOps::PLANE_SET_DGM_CSC_CONFIG: {
+      uint64_t handle = va_arg(args, uint64_t);
+      if (SetDgmCscConfig(req, handle)) {
+        DRM_LOGD("Plane %d: Setting Csc Lut config", obj_id);
+      }
+    } break;
+
+    case DRMOps::PLANE_SET_POST_PROC: {
+       DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
+       if (data) {
+         DRM_LOGD("Plane %d: Set post proc", obj_id);
+         pp_mgr_->SetPPFeature(req, obj_id, *data);
+       }
+     } break;
+
+    default:
+      DRM_LOGE("Invalid opcode %d for DRM Plane %d", code, obj_id);
+  }
+}
+
+void DRMPlane::PerformWrapper(DRMOps code, drmModeAtomicReq *req, ...) {
+  va_list args;
+  va_start(args, req);
+  Perform(code, req, args);
+  va_end(args);
+}
+
+void DRMPlane::Dump() {
+  DRM_LOGE(
+      "id: %d\tcrtc id: %d\tfb id: %d\tCRTC_xy: %dx%d\txy: %dx%d\tgamma "
+      "size: %d\tpossible crtc: 0x%x\n",
+      drm_plane_->plane_id, drm_plane_->crtc_id, drm_plane_->fb_id, drm_plane_->crtc_x,
+      drm_plane_->crtc_y, drm_plane_->x, drm_plane_->y, drm_plane_->gamma_size,
+      drm_plane_->possible_crtcs);
+  DRM_LOGE("Format Suported: \n");
+  for (uint32_t i = 0; i < (uint32_t)drm_plane_->count_formats; i++)
+    DRM_LOGE(" %4.4s", (char *)&drm_plane_->formats[i]);
+}
+
+void DRMPlane::SetMultiRectMode(drmModeAtomicReq *req, DRMMultiRectMode drm_multirect_mode) {
+    if (!plane_type_info_.multirect_prop_present) {
+      return;
+    }
+    uint32_t obj_id = drm_plane_->plane_id;
+    uint32_t multirect_mode = MULTIRECT_NONE;
+    switch (drm_multirect_mode) {
+      case DRMMultiRectMode::NONE:
+        multirect_mode = MULTIRECT_NONE;
+        break;
+      case DRMMultiRectMode::PARALLEL:
+        multirect_mode = MULTIRECT_PARALLEL;
+        break;
+      case DRMMultiRectMode::SERIAL:
+        multirect_mode = MULTIRECT_SERIAL;
+        break;
+      default:
+        DRM_LOGE("Invalid multirect mode %d to set on plane %d", drm_multirect_mode, obj_id);
+        break;
+    }
+    auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::MULTIRECT_MODE);
+    AddProperty(req, obj_id, prop_id, multirect_mode, true /* cache */, tmp_prop_val_map_);
+    DRM_LOGD("Plane %d: Setting multirect_mode %d", obj_id, multirect_mode);
+}
+
+void DRMPlane::Unset(drmModeAtomicReq *req) {
+  DRM_LOGD("Plane %d: Unsetting from crtc %d", drm_plane_->plane_id, assigned_crtc_id_);
+  PerformWrapper(DRMOps::PLANE_SET_FB_ID, req, 0);
+  PerformWrapper(DRMOps::PLANE_SET_CRTC, req, 0);
+  DRMRect rect = {0, 0, 0, 0};
+  PerformWrapper(DRMOps::PLANE_SET_SRC_RECT, req, rect);
+  PerformWrapper(DRMOps::PLANE_SET_DST_RECT, req, rect);
+  PerformWrapper(DRMOps::PLANE_SET_EXCL_RECT, req, rect);
+  if (plane_type_info_.inverse_pma) {
+    PerformWrapper(DRMOps::PLANE_SET_INVERSE_PMA, req, 0);
+  }
+  tmp_prop_val_map_.clear();
+  committed_prop_val_map_.clear();
+}
+
+bool DRMPlane::SetDgmCscConfig(drmModeAtomicReq *req, uint64_t handle) {
+  if (plane_type_info_.type == DRMPlaneType::DMA &&
+      prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_DMA_V1)) {
+    auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::CSC_DMA_V1);
+    sde_drm_csc_v1 *csc_v1 = reinterpret_cast<sde_drm_csc_v1 *>(handle);
+    uint64_t csc_v1_data = 0;
+    sde_drm_csc_v1 csc_v1_tmp = {};
+    csc_config_copy_ = *csc_v1;
+    if (std::memcmp(&csc_config_copy_, &csc_v1_tmp, sizeof(sde_drm_csc_v1)) != 0) {
+      csc_v1_data = reinterpret_cast<uint64_t>(&csc_config_copy_);
+    }
+    DRM_LOGV("Dgm CSC = %d", csc_v1_data);
+    AddProperty(req, drm_plane_->plane_id, prop_id,
+                reinterpret_cast<uint64_t>(csc_v1_data), false /* cache */,
+                tmp_prop_val_map_);
+
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_plane.h b/sde-drm/drm_plane.h
new file mode 100644
index 0000000..0f606b8
--- /dev/null
+++ b/sde-drm/drm_plane.h
@@ -0,0 +1,131 @@
+/*
+* Copyright (c) 2019, 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 __DRM_PLANE_H__
+#define __DRM_PLANE_H__
+
+#include <drm/sde_drm.h>
+#include <drm_interface.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include "drm_property.h"
+#include "drm_pp_manager.h"
+
+namespace sde_drm {
+
+class DRMPlaneManager;
+
+class DRMPlane {
+ public:
+  explicit DRMPlane(int fd, uint32_t priority);
+  ~DRMPlane();
+  void InitAndParse(drmModePlane *plane);
+  void GetId(uint32_t *id) { *id = drm_plane_->plane_id; }
+  void GetType(DRMPlaneType *type) { *type = plane_type_info_.type; }
+  void GetPriority(uint32_t *priority) { *priority = priority_; }
+  void GetAssignedCrtc(uint32_t *crtc_id) { *crtc_id = assigned_crtc_id_; }
+  void GetRequestedCrtc(uint32_t *crtc_id) { *crtc_id = requested_crtc_id_; }
+  void SetAssignedCrtc(uint32_t crtc_id) { assigned_crtc_id_ = crtc_id; }
+  void SetRequestedCrtc(uint32_t crtc_id) { requested_crtc_id_ = crtc_id; }
+  bool SetScalerConfig(drmModeAtomicReq *req, uint64_t handle);
+  bool SetCscConfig(drmModeAtomicReq *req, DRMCscType csc_type);
+  bool ConfigureScalerLUT(drmModeAtomicReq *req, uint32_t dir_lut_blob_id,
+                          uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id);
+  const DRMPlaneTypeInfo& GetPlaneTypeInfo() { return plane_type_info_; }
+  void SetDecimation(drmModeAtomicReq *req, uint32_t prop_id, uint32_t prop_value);
+  void SetExclRect(drmModeAtomicReq *req, DRMRect rect);
+  void Perform(DRMOps code, drmModeAtomicReq *req, va_list args);
+  void Dump();
+  void SetMultiRectMode(drmModeAtomicReq *req, DRMMultiRectMode drm_multirect_mode);
+  void Unset(drmModeAtomicReq *req);
+  void PostValidate(uint32_t crtc_id, bool success);
+  void PostCommit(uint32_t crtc_id, bool success);
+  bool SetDgmCscConfig(drmModeAtomicReq *req, uint64_t handle);
+
+ private:
+  typedef std::map<DRMProperty, std::tuple<uint64_t, drmModePropertyRes *>> PropertyMap;
+  void ParseProperties();
+  void GetTypeInfo(const PropertyMap &props);
+  void PerformWrapper(DRMOps code, drmModeAtomicReq *req, ...);
+
+  int fd_ = -1;
+  uint32_t priority_ = 0;
+  drmModePlane *drm_plane_ = {};
+  DRMPlaneTypeInfo plane_type_info_{};
+  uint32_t assigned_crtc_id_ = 0;
+  uint32_t requested_crtc_id_ = 0;
+  DRMPropertyManager prop_mgr_ {};
+  bool has_excl_rect_ = false;
+  drm_clip_rect excl_rect_copy_ = {};
+  std::unique_ptr<DRMPPManager> pp_mgr_ {};
+  std::unordered_map<uint32_t, uint64_t> tmp_prop_val_map_ {};
+  std::unordered_map<uint32_t, uint64_t> committed_prop_val_map_ {};
+
+  // Only applicable to planes that have scaler
+  sde_drm_scaler_v2 scaler_v2_config_copy_ = {};
+  sde_drm_csc_v1 csc_config_copy_ = {};
+  bool is_lut_configured_ = false;
+};
+
+class DRMPlaneManager {
+ public:
+  explicit DRMPlaneManager(int fd);
+  void Init();
+  void DeInit() {}
+  void GetPlanesInfo(DRMPlanesInfo *info);
+  void DumpAll();
+  void DumpByID(uint32_t id);
+  void Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args);
+  void UnsetUnusedPlanes(uint32_t crtc_id, drmModeAtomicReq *req);
+  void RetainPlanes(uint32_t crtc_id);
+  void SetScalerLUT(const DRMScalerLUTInfo &lut_info);
+  void UnsetScalerLUT();
+  void PostValidate(uint32_t crtc_id, bool success);
+  void PostCommit(uint32_t crtc_id, bool success);
+
+ private:
+  void Perform(DRMOps code, drmModeAtomicReq *req, uint32_t obj_id, ...);
+
+  int fd_ = -1;
+  // Map of plane id to DRMPlane *
+  std::map<uint32_t, std::unique_ptr<DRMPlane>> plane_pool_{};
+  // Global Scaler LUT blobs
+  uint32_t dir_lut_blob_id_ = 0;
+  uint32_t cir_lut_blob_id_ = 0;
+  uint32_t sep_lut_blob_id_ = 0;
+};
+
+}  // namespace sde_drm
+
+#endif  // __DRM_PLANE_H__
diff --git a/sde-drm/drm_pp_manager.cpp b/sde-drm/drm_pp_manager.cpp
new file mode 100644
index 0000000..dee76de
--- /dev/null
+++ b/sde-drm/drm_pp_manager.cpp
@@ -0,0 +1,267 @@
+/*
+* Copyright (c) 2019, 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.
+*/
+
+#ifdef PP_DRM_ENABLE
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm/msm_drm_pp.h>
+#endif
+#include <drm_logger.h>
+#include <cstring>
+#include <algorithm>
+#include <memory>
+#include <map>
+#include <string>
+
+#include "drm_pp_manager.h"
+#include "drm_property.h"
+
+#define __CLASS__ "DRMPPManager"
+namespace sde_drm {
+
+DRMPPManager::DRMPPManager(int fd) : fd_(fd) {
+}
+
+DRMPPManager::~DRMPPManager() {
+#ifdef PP_DRM_ENABLE
+  DRMPPPropInfo prop_info = {};
+
+  /* free previously created blob to avoid memory leak */
+  for (int i = 0; i < kPPFeaturesMax; i++) {
+    prop_info = pp_prop_map_[i];
+    if (prop_info.blob_id > 0) {
+      drmModeDestroyPropertyBlob(fd_, prop_info.blob_id);
+      prop_info.blob_id = 0;
+    }
+  }
+#endif
+  fd_ = -1;
+}
+
+void DRMPPManager::Init(const DRMPropertyManager &pm , uint32_t object_type) {
+  object_type_ = object_type;
+  for (uint32_t i = (uint32_t)DRMProperty::INVALID + 1; i < (uint32_t)DRMProperty::MAX; i++) {
+    /* parse all the object properties and store the PP properties
+     * into DRMPPManager class
+    */
+    if (!pm.IsPropertyAvailable((DRMProperty)i)) {
+      continue;
+    }
+
+    if (i >= (uint32_t)DRMProperty::SDE_DSPP_GAMUT_V3 && i <=
+        (uint32_t)DRMProperty::SDE_DSPP_GAMUT_V5) {
+      pp_prop_map_[kFeatureGamut].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureGamut].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureGamut].version = i - (uint32_t)DRMProperty::SDE_DSPP_GAMUT_V3 + 3;
+      DRM_LOGI("Gamut version %d, prop_id %d", pp_prop_map_[kFeatureGamut].version,
+               pp_prop_map_[kFeatureGamut].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_GC_V1 && i <=
+               (uint32_t)DRMProperty::SDE_DSPP_GC_V2) {
+      pp_prop_map_[kFeaturePgc].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePgc].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePgc].version = i - (uint32_t)DRMProperty::SDE_DSPP_GC_V1 + 1;
+      DRM_LOGI("Pgc version %d, prop_id %d", pp_prop_map_[kFeaturePgc].version,
+               pp_prop_map_[kFeaturePgc].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_IGC_V2 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_IGC_V4) {
+      pp_prop_map_[kFeatureIgc].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureIgc].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureIgc].version = i - (uint32_t)DRMProperty::SDE_DSPP_IGC_V2 + 2;
+      DRM_LOGI("Igc version %d, prop_id %d", pp_prop_map_[kFeatureIgc].version,
+               pp_prop_map_[kFeatureIgc].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PCC_V3 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PCC_V5) {
+      pp_prop_map_[kFeaturePcc].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePcc].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePcc].version = i - (uint32_t)DRMProperty::SDE_DSPP_PCC_V3 + 3;
+      DRM_LOGI("Pcc version %d, prop_id %d", pp_prop_map_[kFeaturePcc].version,
+               pp_prop_map_[kFeaturePcc].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_HSIC_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_HSIC_V2) {
+      pp_prop_map_[kFeaturePAHsic].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePAHsic].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePAHsic].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_HSIC_V1 + 1;
+      DRM_LOGI("PaHsic version %d, prop_id %d", pp_prop_map_[kFeaturePAHsic].version,
+               pp_prop_map_[kFeaturePAHsic].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_SIXZONE_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_SIXZONE_V2) {
+      pp_prop_map_[kFeaturePASixZone].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePASixZone].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePASixZone].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_SIXZONE_V1 + 1;
+      DRM_LOGI("SixZone version %d, prop_id %d", pp_prop_map_[kFeaturePASixZone].version,
+               pp_prop_map_[kFeaturePASixZone].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_SKIN_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_SKIN_V2) {
+      pp_prop_map_[kFeaturePAMemColSkin].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePAMemColSkin].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePAMemColSkin].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_SKIN_V1 + 1;
+      DRM_LOGI("MemColor skin version %d, prop_id %d", pp_prop_map_[kFeaturePAMemColSkin].version,
+               pp_prop_map_[kFeaturePAMemColSkin].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_SKY_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_SKY_V2) {
+      pp_prop_map_[kFeaturePAMemColSky].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePAMemColSky].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePAMemColSky].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_SKY_V1 + 1;
+      DRM_LOGI("MemColor sky version %d, prop_id %d", pp_prop_map_[kFeaturePAMemColSky].version,
+               pp_prop_map_[kFeaturePAMemColSky].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_FOLIAGE_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_FOLIAGE_V2) {
+      pp_prop_map_[kFeaturePAMemColFoliage].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePAMemColFoliage].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePAMemColFoliage].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_FOLIAGE_V1 + 1;
+      DRM_LOGI("MemColor foliage version %d, prop_id %d", pp_prop_map_[kFeaturePAMemColFoliage].version,
+               pp_prop_map_[kFeaturePAMemColFoliage].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_PROT_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_PROT_V2) {
+      pp_prop_map_[kFeaturePAMemColProt].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePAMemColProt].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePAMemColProt].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_MEMCOL_PROT_V1 + 1;
+      DRM_LOGI("MemColor prot version %d, prop_id %d", pp_prop_map_[kFeaturePAMemColProt].version,
+               pp_prop_map_[kFeaturePAMemColProt].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DSPP_PA_DITHER_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_DSPP_PA_DITHER_V2) {
+      pp_prop_map_[kFeaturePADither].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeaturePADither].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeaturePADither].version = i - (uint32_t)DRMProperty::SDE_DSPP_PA_DITHER_V1 + 1;
+      DRM_LOGI("PA Dither version %d, prop_id %d", pp_prop_map_[kFeaturePADither].version,
+               pp_prop_map_[kFeaturePADither].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_PP_DITHER_V1 &&
+               i <= (uint32_t)DRMProperty::SDE_PP_DITHER_V2) {
+      pp_prop_map_[kFeatureDither].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureDither].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureDither].version = i - (uint32_t)DRMProperty::SDE_PP_DITHER_V1 + 1;
+      DRM_LOGI("PP dither version %d, prop_id %d", pp_prop_map_[kFeatureDither].version,
+               pp_prop_map_[kFeatureDither].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 &&
+               i <= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5) {
+      pp_prop_map_[kFeatureVigGamut].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureVigGamut].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureVigGamut].version = i - (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 + 5;
+      DRM_LOGI("Vig Gamut version %d, prop_id %d", pp_prop_map_[kFeatureVigGamut].version,
+               pp_prop_map_[kFeatureVigGamut].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 &&
+               i <= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5) {
+      pp_prop_map_[kFeatureVigIgc].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureVigIgc].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureVigIgc].version = i - (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 + 5;
+      DRM_LOGI("Vig Igc version %d, prop_id %d", pp_prop_map_[kFeatureVigIgc].version,
+               pp_prop_map_[kFeatureVigIgc].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 &&
+               i <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5) {
+      pp_prop_map_[kFeatureDgmIgc].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureDgmIgc].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureDgmIgc].version = i - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 + 5;
+      DRM_LOGI("Dgm Igc version %d, prop_id %d", pp_prop_map_[kFeatureDgmIgc].version,
+               pp_prop_map_[kFeatureDgmIgc].prop_id);
+    } else if (i >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 &&
+               i <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5) {
+      pp_prop_map_[kFeatureDgmGc].prop_enum = (DRMProperty)i;
+      pp_prop_map_[kFeatureDgmGc].prop_id = pm.GetPropertyId((DRMProperty)i);
+      pp_prop_map_[kFeatureDgmGc].version = i - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 + 5;
+      DRM_LOGI("Dgm Gc version %d, prop_id %d", pp_prop_map_[kFeatureDgmGc].version,
+               pp_prop_map_[kFeatureDgmGc].prop_id);
+    }
+  }
+  return;
+}
+
+void DRMPPManager::GetPPInfo(DRMPPFeatureInfo *info) {
+  if (!info)
+    return;
+  if (info->id > kPPFeaturesMax)
+    return;
+
+  info->version = pp_prop_map_[info->id].version;
+  info->object_type = object_type_;
+  return;
+}
+
+void DRMPPManager::SetPPFeature(drmModeAtomicReq *req, uint32_t obj_id, DRMPPFeatureInfo &feature) {
+  if (!req) {
+      DRM_LOGE("Invalid input param: req %p", req);
+      return;
+  }
+
+  if (feature.id >= kPPFeaturesMax)
+    return;
+
+  switch (feature.type) {
+    case kPropEnum:
+      break;
+    case kPropRange:
+      break;
+    case kPropBlob:
+      SetPPBlobProperty(req, obj_id, &pp_prop_map_[feature.id], feature);
+      break;
+    default:
+      DRM_LOGE("Unsupported feature type %d", feature.type);
+      break;
+  }
+
+  return;
+}
+
+int DRMPPManager::SetPPBlobProperty(drmModeAtomicReq *req, uint32_t obj_id,
+                                    struct DRMPPPropInfo *prop_info,
+                                    DRMPPFeatureInfo &feature) {
+  int ret = DRM_ERR_INVALID;
+#ifdef PP_DRM_ENABLE
+  uint32_t blob_id = 0;
+
+  /* free previously created blob for this feature if exist */
+  if (prop_info->blob_id > 0) {
+    ret = drmModeDestroyPropertyBlob(fd_, prop_info->blob_id);
+    if (ret) {
+      DRM_LOGE("failed to destroy property blob for feature %d, ret = %d", feature.id, ret);
+      return ret;
+    } else {
+      prop_info->blob_id = 0;
+    }
+  }
+
+  if (!feature.payload) {
+    // feature disable case
+    drmModeAtomicAddProperty(req, obj_id, prop_info->prop_id, 0);
+    return 0;
+  }
+
+  ret = drmModeCreatePropertyBlob(fd_, feature.payload, feature.payload_size, &blob_id);
+  if (ret || blob_id == 0) {
+    DRM_LOGE("failed to create property blob ret %d, blob_id = %d", ret, blob_id);
+    return DRM_ERR_INVALID;
+  }
+
+  prop_info->blob_id = blob_id;
+  drmModeAtomicAddProperty(req, obj_id, prop_info->prop_id, blob_id);
+
+#endif
+  return ret;
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_pp_manager.h b/sde-drm/drm_pp_manager.h
new file mode 100644
index 0000000..a81525c
--- /dev/null
+++ b/sde-drm/drm_pp_manager.h
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2019, 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 __DRM_PP_MANAGER_H__
+#define __DRM_PP_MANAGER_H__
+
+#include <limits>
+#include "drm_utils.h"
+#include "drm_interface.h"
+#include "drm_property.h"
+
+namespace sde_drm {
+
+struct DRMPPPropInfo {
+  DRMProperty prop_enum;
+  uint32_t version = std::numeric_limits<uint32_t>::max();
+  uint32_t prop_id;
+  uint32_t blob_id;
+};
+
+class DRMPPManager {
+ public:
+  explicit DRMPPManager(int fd);
+  ~DRMPPManager();
+  void Init(const DRMPropertyManager &pm, uint32_t object_type);
+  void DeInit() {}
+  void GetPPInfo(DRMPPFeatureInfo *info);
+  void SetPPFeature(drmModeAtomicReq *req, uint32_t obj_id, DRMPPFeatureInfo &feature);
+
+ private:
+  int SetPPBlobProperty(drmModeAtomicReq *req, uint32_t obj_id, struct DRMPPPropInfo *prop_info,
+                        DRMPPFeatureInfo &feature);
+
+  int fd_ = -1;
+  uint32_t object_type_ = std::numeric_limits<uint32_t>::max();
+  DRMPPPropInfo pp_prop_map_[kPPFeaturesMax] = {};
+};
+
+}  // namespace sde_drm
+#endif  // __DRM_PP_MANAGER_H__
diff --git a/sde-drm/drm_property.cpp b/sde-drm/drm_property.cpp
new file mode 100644
index 0000000..26f11fc
--- /dev/null
+++ b/sde-drm/drm_property.cpp
@@ -0,0 +1,153 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "drm_property.h"
+
+namespace sde_drm {
+
+DRMProperty DRMPropertyManager::GetPropertyEnum(const std::string &name) const {
+  if (name == "type") { return DRMProperty::TYPE; }
+  if (name == "FB_ID") { return DRMProperty::FB_ID; }
+  if (name == "rot_fb_id") { return DRMProperty::ROT_FB_ID; }
+  if (name == "CRTC_ID") { return DRMProperty::CRTC_ID; }
+  if (name == "CRTC_X") { return DRMProperty::CRTC_X; }
+  if (name == "CRTC_Y") { return DRMProperty::CRTC_Y; }
+  if (name == "CRTC_W") { return DRMProperty::CRTC_W; }
+  if (name == "CRTC_H") { return DRMProperty::CRTC_H; }
+  if (name == "SRC_X") { return DRMProperty::SRC_X; }
+  if (name == "SRC_Y") { return DRMProperty::SRC_Y; }
+  if (name == "SRC_W") { return DRMProperty::SRC_W; }
+  if (name == "SRC_H") { return DRMProperty::SRC_H; }
+  if (name == "zpos") { return DRMProperty::ZPOS; }
+  if (name == "alpha") { return DRMProperty::ALPHA; }
+  if (name == "excl_rect_v1") { return DRMProperty::EXCL_RECT; }
+  if (name == "h_decimate") { return DRMProperty::H_DECIMATE; }
+  if (name == "v_decimate") { return DRMProperty::V_DECIMATE; }
+  if (name == "input_fence") { return DRMProperty::INPUT_FENCE; }
+  if (name == "rotation") { return DRMProperty::ROTATION; }
+  if (name == "blend_op") { return DRMProperty::BLEND_OP; }
+  if (name == "src_config") { return DRMProperty::SRC_CONFIG; }
+  if (name == "scaler_v1") { return DRMProperty::SCALER_V1; }
+  if (name == "scaler_v2") { return DRMProperty::SCALER_V2; }
+  if (name == "csc_v1") { return DRMProperty::CSC_V1; }
+  if (name == "capabilities") { return DRMProperty::CAPABILITIES; }
+  if (name == "mode_properties") { return DRMProperty::MODE_PROPERTIES; }
+  if (name == "lut_ed") { return DRMProperty::LUT_ED; }
+  if (name == "lut_cir") { return DRMProperty::LUT_CIR; }
+  if (name == "lut_sep") { return DRMProperty::LUT_SEP; }
+  if (name == "rot_caps_v1") { return DRMProperty::ROTATOR_CAPS_V1; }
+  if (name == "true_inline_rot_rev") { return DRMProperty::TRUE_INLINE_ROT_REV; }
+  if (name == "fb_translation_mode") { return DRMProperty::FB_TRANSLATION_MODE; }
+  if (name == "ACTIVE") { return DRMProperty::ACTIVE; }
+  if (name == "MODE_ID") { return DRMProperty::MODE_ID; }
+  if (name == "output_fence_offset") { return DRMProperty::OUTPUT_FENCE_OFFSET; }
+  if (name == "output_fence") { return DRMProperty::OUTPUT_FENCE; }
+  if (name == "sde_drm_roi_v1") { return DRMProperty::ROI_V1; }
+  if (name == "core_clk") { return DRMProperty::CORE_CLK; }
+  if (name == "core_ab") { return DRMProperty::CORE_AB; }
+  if (name == "core_ib") { return DRMProperty::CORE_IB; }
+  if (name == "llcc_ab") { return DRMProperty::LLCC_AB; }
+  if (name == "llcc_ib") { return DRMProperty::LLCC_IB; }
+  if (name == "dram_ab") { return DRMProperty::DRAM_AB; }
+  if (name == "dram_ib") { return DRMProperty::DRAM_IB; }
+  if (name == "rot_prefill_bw") { return DRMProperty::ROT_PREFILL_BW; }
+  if (name == "rot_clk") { return DRMProperty::ROT_CLK; }
+  if (name == "security_level") { return DRMProperty::SECURITY_LEVEL; }
+  if (name == "dim_layer_v1") { return DRMProperty::DIM_STAGES_V1; }
+  if (name == "idle_time") { return DRMProperty::IDLE_TIME; }
+  if (name == "RETIRE_FENCE") { return DRMProperty::RETIRE_FENCE; }
+  if (name == "DST_X") { return DRMProperty::DST_X; }
+  if (name == "DST_Y") { return DRMProperty::DST_Y; }
+  if (name == "DST_W") { return DRMProperty::DST_W; }
+  if (name == "DST_H") { return DRMProperty::DST_H; }
+  if (name == "LP") { return DRMProperty::LP; }
+  if (name == "dest_scaler") { return DRMProperty::DEST_SCALER; }
+  if (name == "ds_lut_ed") { return DRMProperty::DS_LUT_ED; }
+  if (name == "ds_lut_cir") { return DRMProperty::DS_LUT_CIR; }
+  if (name == "ds_lut_sep") { return DRMProperty::DS_LUT_SEP; }
+  if (name == "hdr_properties") { return DRMProperty::HDR_PROPERTIES; }
+  if (name == "SDE_DSPP_GAMUT_V3") { return DRMProperty::SDE_DSPP_GAMUT_V3; }
+  if (name == "SDE_DSPP_GAMUT_V4") { return DRMProperty::SDE_DSPP_GAMUT_V4; }
+  if (name == "SDE_DSPP_GAMUT_V5") { return DRMProperty::SDE_DSPP_GAMUT_V5; }
+  if (name == "SDE_DSPP_GC_V1") { return DRMProperty::SDE_DSPP_GC_V1; }
+  if (name == "SDE_DSPP_GC_V2") { return DRMProperty::SDE_DSPP_GC_V2; }
+  if (name == "SDE_DSPP_IGC_V2") { return DRMProperty::SDE_DSPP_IGC_V2; }
+  if (name == "SDE_DSPP_IGC_V3") { return DRMProperty::SDE_DSPP_IGC_V3; }
+  if (name == "SDE_DSPP_IGC_V4") { return DRMProperty::SDE_DSPP_IGC_V4; }
+  if (name == "SDE_DSPP_PCC_V3") { return DRMProperty::SDE_DSPP_PCC_V3; }
+  if (name == "SDE_DSPP_PCC_V4") { return DRMProperty::SDE_DSPP_PCC_V4; }
+  if (name == "SDE_DSPP_PCC_V5") { return DRMProperty::SDE_DSPP_PCC_V5; }
+  if (name == "SDE_DSPP_PA_HSIC_V1") { return DRMProperty::SDE_DSPP_PA_HSIC_V1; }
+  if (name == "SDE_DSPP_PA_HSIC_V2") { return DRMProperty::SDE_DSPP_PA_HSIC_V2; }
+  if (name == "SDE_DSPP_PA_SIXZONE_V1") { return DRMProperty::SDE_DSPP_PA_SIXZONE_V1; }
+  if (name == "SDE_DSPP_PA_SIXZONE_V2") { return DRMProperty::SDE_DSPP_PA_SIXZONE_V2; }
+  if (name == "SDE_DSPP_PA_MEMCOL_SKIN_V1") { return DRMProperty::SDE_DSPP_PA_MEMCOL_SKIN_V1; }
+  if (name == "SDE_DSPP_PA_MEMCOL_SKIN_V2") { return DRMProperty::SDE_DSPP_PA_MEMCOL_SKIN_V2; }
+  if (name == "SDE_DSPP_PA_MEMCOL_SKY_V1") { return DRMProperty::SDE_DSPP_PA_MEMCOL_SKY_V1; }
+  if (name == "SDE_DSPP_PA_MEMCOL_SKY_V2") { return DRMProperty::SDE_DSPP_PA_MEMCOL_SKY_V2; }
+  if (name == "SDE_DSPP_PA_MEMCOL_FOLIAGE_V1") { return DRMProperty::SDE_DSPP_PA_MEMCOL_FOLIAGE_V1; }
+  if (name == "SDE_DSPP_PA_MEMCOL_FOLIAGE_V2") { return DRMProperty::SDE_DSPP_PA_MEMCOL_FOLIAGE_V2; }
+  if (name == "SDE_DSPP_PA_MEMCOL_PROT_V1") { return DRMProperty::SDE_DSPP_PA_MEMCOL_PROT_V1; }
+  if (name == "SDE_DSPP_PA_MEMCOL_PROT_V2") { return DRMProperty::SDE_DSPP_PA_MEMCOL_PROT_V2; }
+  if (name == "autorefresh") { return DRMProperty::AUTOREFRESH; }
+  if (name == "ext_hdr_properties") { return DRMProperty::EXT_HDR_PROPERTIES; }
+  if (name == "hdr_metadata") { return DRMProperty::HDR_METADATA; }
+  if (name == "multirect_mode") { return DRMProperty::MULTIRECT_MODE; }
+  if (name == "SDE_DSPP_PA_DITHER_V1") { return DRMProperty::SDE_DSPP_PA_DITHER_V1; }
+  if (name == "SDE_DSPP_PA_DITHER_V2") { return DRMProperty::SDE_DSPP_PA_DITHER_V2; }
+  if (name == "SDE_PP_DITHER_V1") { return DRMProperty::SDE_PP_DITHER_V1; }
+  if (name == "SDE_PP_DITHER_V2") { return DRMProperty::SDE_PP_DITHER_V2; }
+  if (name == "inverse_pma") { return DRMProperty::INVERSE_PMA; }
+  if (name == "csc_dma_v1") { return DRMProperty::CSC_DMA_V1; }
+  if (name == "SDE_DGM_1D_LUT_IGC_V5") { return DRMProperty::SDE_DGM_1D_LUT_IGC_V5; }
+  if (name == "SDE_DGM_1D_LUT_GC_V5") { return DRMProperty::SDE_DGM_1D_LUT_GC_V5; }
+  if (name == "SDE_VIG_1D_LUT_IGC_V5") { return DRMProperty::SDE_VIG_1D_LUT_IGC_V5; }
+  if (name == "SDE_VIG_3D_LUT_GAMUT_V5") { return DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5; }
+  if (name == "SDE_DSPP_AD_V4_MODE") { return DRMProperty::SDE_DSPP_AD4_MODE; }
+  if (name == "SDE_DSPP_AD_V4_INIT") { return DRMProperty::SDE_DSPP_AD4_INIT; }
+  if (name == "SDE_DSPP_AD_V4_CFG") { return DRMProperty::SDE_DSPP_AD4_CFG; }
+  if (name == "SDE_DSPP_AD_V4_ASSERTIVENESS") { return DRMProperty::SDE_DSPP_AD4_ASSERTIVENESS; }
+  if (name == "SDE_DSPP_AD_V4_STRENGTH") { return DRMProperty::SDE_DSPP_AD4_STRENGTH; }
+  if (name == "SDE_DSPP_AD_V4_INPUT") { return DRMProperty::SDE_DSPP_AD4_INPUT; }
+  if (name == "SDE_DSPP_AD_V4_BACKLIGHT") { return DRMProperty::SDE_DSPP_AD4_BACKLIGHT; }
+  if (name == "SDE_DSPP_AD_V4_ROI") { return DRMProperty::SDE_DSPP_AD4_ROI; }
+  if (name == "SDE_DSPP_HIST_CTRL_V1") { return DRMProperty::SDE_DSPP_ABA_HIST_CTRL; }
+  if (name == "SDE_DSPP_HIST_IRQ_V1") { return DRMProperty::SDE_DSPP_ABA_HIST_IRQ; }
+  if (name == "SDE_DSPP_VLUT_V1") { return DRMProperty::SDE_DSPP_ABA_LUT; }
+  if (name == "bl_scale") { return DRMProperty::SDE_DSPP_BL_SCALE; }
+  if (name == "ad_bl_scale") { return DRMProperty::SDE_DSPP_AD4_BL_SCALE; }
+  if (name == "capture_mode") { return DRMProperty::CAPTURE_MODE; }
+  if (name == "qsync_mode") { return DRMProperty::QSYNC_MODE; }
+  if (name == "idle_pc_state") { return DRMProperty::IDLE_PC_STATE; }
+  if (name == "topology_control") { return DRMProperty::TOPOLOGY_CONTROL; }
+
+  return DRMProperty::INVALID;
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_property.h b/sde-drm/drm_property.h
new file mode 100644
index 0000000..d18e18d
--- /dev/null
+++ b/sde-drm/drm_property.h
@@ -0,0 +1,180 @@
+/*
+* Copyright (c) 2019, 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 __DRM_PROPERTY_H__
+#define __DRM_PROPERTY_H__
+
+#include <stdint.h>
+#include <string>
+
+namespace sde_drm {
+
+enum struct DRMProperty {
+  INVALID,
+  TYPE,
+  FB_ID,
+  CRTC_ID,
+  CRTC_X,
+  CRTC_Y,
+  CRTC_W,
+  CRTC_H,
+  SRC_X,
+  SRC_Y,
+  SRC_W,
+  SRC_H,
+  ZPOS,
+  ALPHA,
+  EXCL_RECT,
+  H_DECIMATE,
+  V_DECIMATE,
+  INPUT_FENCE,
+  ROTATION,
+  BLEND_OP,
+  SRC_CONFIG,
+  SCALER_V1,
+  SCALER_V2,
+  CSC_V1,
+  CAPABILITIES,
+  MODE_PROPERTIES,
+  LUT_ED,
+  LUT_CIR,
+  LUT_SEP,
+  ROTATOR_CAPS_V1,
+  TRUE_INLINE_ROT_REV,
+  FB_TRANSLATION_MODE,
+  ACTIVE,
+  MODE_ID,
+  OUTPUT_FENCE_OFFSET,
+  OUTPUT_FENCE,
+  ROI_V1,
+  CORE_CLK,
+  CORE_AB,
+  CORE_IB,
+  LLCC_AB,
+  LLCC_IB,
+  DRAM_AB,
+  DRAM_IB,
+  ROT_PREFILL_BW,
+  ROT_CLK,
+  SECURITY_LEVEL,
+  DIM_STAGES_V1,
+  IDLE_TIME,
+  RETIRE_FENCE,
+  DST_X,
+  DST_Y,
+  DST_W,
+  DST_H,
+  LP,
+  HDR_PROPERTIES,
+  DEST_SCALER,
+  DS_LUT_ED,
+  DS_LUT_CIR,
+  DS_LUT_SEP,
+  SDE_DSPP_GAMUT_V3,
+  SDE_DSPP_GAMUT_V4,
+  SDE_DSPP_GAMUT_V5,
+  SDE_DSPP_GC_V1,
+  SDE_DSPP_GC_V2,
+  SDE_DSPP_IGC_V2,
+  SDE_DSPP_IGC_V3,
+  SDE_DSPP_IGC_V4,
+  SDE_DSPP_PCC_V3,
+  SDE_DSPP_PCC_V4,
+  SDE_DSPP_PCC_V5,
+  SDE_DSPP_PA_HSIC_V1,
+  SDE_DSPP_PA_HSIC_V2,
+  SDE_DSPP_PA_SIXZONE_V1,
+  SDE_DSPP_PA_SIXZONE_V2,
+  SDE_DSPP_PA_MEMCOL_SKIN_V1,
+  SDE_DSPP_PA_MEMCOL_SKIN_V2,
+  SDE_DSPP_PA_MEMCOL_SKY_V1,
+  SDE_DSPP_PA_MEMCOL_SKY_V2,
+  SDE_DSPP_PA_MEMCOL_FOLIAGE_V1,
+  SDE_DSPP_PA_MEMCOL_FOLIAGE_V2,
+  SDE_DSPP_PA_MEMCOL_PROT_V1,
+  SDE_DSPP_PA_MEMCOL_PROT_V2,
+  AUTOREFRESH,
+  EXT_HDR_PROPERTIES,
+  HDR_METADATA,
+  MULTIRECT_MODE,
+  ROT_FB_ID,
+  SDE_DSPP_PA_DITHER_V1,
+  SDE_DSPP_PA_DITHER_V2,
+  SDE_PP_DITHER_V1,
+  SDE_PP_DITHER_V2,
+  INVERSE_PMA,
+  CSC_DMA_V1,
+  SDE_DGM_1D_LUT_IGC_V5,
+  SDE_DGM_1D_LUT_GC_V5,
+  SDE_VIG_1D_LUT_IGC_V5,
+  SDE_VIG_3D_LUT_GAMUT_V5,
+  SDE_DSPP_AD4_MODE,
+  SDE_DSPP_AD4_INIT,
+  SDE_DSPP_AD4_CFG,
+  SDE_DSPP_AD4_INPUT,
+  SDE_DSPP_AD4_BACKLIGHT,
+  SDE_DSPP_AD4_ROI,
+  SDE_DSPP_AD4_ASSERTIVENESS,
+  SDE_DSPP_AD4_STRENGTH,
+  SDE_DSPP_ABA_HIST_CTRL,
+  SDE_DSPP_ABA_HIST_IRQ,
+  SDE_DSPP_ABA_LUT,
+  SDE_DSPP_AD4_BL_SCALE,
+  SDE_DSPP_BL_SCALE,
+  CAPTURE_MODE,
+  QSYNC_MODE,
+  IDLE_PC_STATE,
+  TOPOLOGY_CONTROL,
+
+  // Insert above
+  MAX
+};
+
+struct DRMPropertyManager {
+  DRMProperty GetPropertyEnum(const std::string &name) const;
+
+  void SetPropertyId(DRMProperty prop_enum, uint32_t prop_id) {
+    properties_[(uint32_t)prop_enum] = prop_id;
+  }
+
+  uint32_t GetPropertyId(DRMProperty prop_enum) const {
+    return properties_[(uint32_t)prop_enum];
+  }
+
+  bool IsPropertyAvailable(DRMProperty prop_enum) const {
+    return !!properties_[(uint32_t)prop_enum];
+  }
+
+ private:
+  uint32_t properties_[(uint32_t)DRMProperty::MAX] {};
+};
+
+}  // namespace sde_drm
+
+#endif  // __DRM_PROPERTY_H__
diff --git a/sde-drm/drm_utils.cpp b/sde-drm/drm_utils.cpp
new file mode 100644
index 0000000..b79c4c8
--- /dev/null
+++ b/sde-drm/drm_utils.cpp
@@ -0,0 +1,118 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <drm/drm_fourcc.h>
+#include <drm_utils.h>
+#include <regex>
+#include <sstream>
+#include <sstream>
+#include <string>
+#include <string>
+#include <utility>
+#include <vector>
+
+using std::string;
+using std::stringstream;
+using std::regex;
+using std::pair;
+using std::vector;
+
+namespace sde_drm {
+
+void ParseFormats(const string &line, vector<pair<uint32_t, uint64_t>> *formats) {
+  // Match fourcc strings like RA24 or those with modifier like RA24/5/1. The
+  // digit after first / is vendor code, the digit after second / is modifier
+  // code.
+  regex exp_base("[[:alnum:]]{4}(/[[:digit:]]/([[:digit:]]){1,3})?");
+  regex exp_modifier("[[:alnum:]]{4}(/[[:digit:]]/([[:digit:]]){1,3})");
+  string tmp_line = line;
+  std::smatch str_match;  // Resultant match
+  while (std::regex_search(tmp_line, str_match, exp_base)) { //clang_sa_ignore[core.CallAndMessage]
+    string matched_sub_str = str_match.str();
+    string final_format_str = {};
+    uint64_t modifier = 0;
+
+    if (std::regex_match(matched_sub_str, exp_modifier)) { //clang_sa_ignore[core.CallAndMessage]
+      // Here we try to parse formats with vendor code and modifier like
+      // RA24/5/1
+
+      // Extract base format string
+      final_format_str = matched_sub_str.substr(0, matched_sub_str.find("/"));
+
+      // Match vendor code
+      string vendor_sub_str = matched_sub_str.substr(matched_sub_str.find("/") + 1);
+      uint64_t vendor_code = std::stoi(vendor_sub_str);
+
+      // Match modifier
+      uint64_t fmt_modifier = std::stoi(vendor_sub_str.substr(vendor_sub_str.find("/") + 1));
+      if (vendor_code == DRM_FORMAT_MOD_VENDOR_QCOM) {
+        // Macro from drm_fourcc.h to form modifier
+        modifier = fourcc_mod_code(QCOM, fmt_modifier);
+      }
+
+    } else {
+      final_format_str = matched_sub_str.c_str();
+    }
+
+    // fourcc_code is a macro from drm_fourcc.h to form the format from 4 characters (thus fourcc)
+    formats->push_back(std::make_pair(fourcc_code(final_format_str.at(0), final_format_str.at(1),
+                                                  final_format_str.at(2), final_format_str.at(3)),
+                                      modifier));
+    tmp_line = str_match.suffix();
+  }
+}
+
+void Tokenize(const std::string &str, std::vector<std::string> *tokens, char delim) {
+  size_t pos = 0;
+  std::string str_temp(str);
+
+  while ((pos = str_temp.find(delim)) != std::string::npos && delim != ' ') {
+    str_temp.replace(pos, 1, 1, ' ');
+  }
+
+  std::stringstream ss(str_temp);
+  while (ss >> str_temp) {
+    tokens->push_back(str_temp);
+  }
+}
+
+void AddProperty(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value,
+                 bool cache, std::unordered_map<uint32_t, uint64_t> &prop_val_map) {
+#ifndef SDM_VIRTUAL_DRIVER
+  auto it = prop_val_map.find(property_id);
+  if (it == prop_val_map.end() || it->second != value)
+#endif
+    drmModeAtomicAddProperty(req, object_id, property_id, value);
+#ifndef SDM_VIRTUAL_DRIVER
+  if (cache)
+    prop_val_map[property_id] = value;
+#endif
+}
+
+}  // namespace sde_drm
diff --git a/sde-drm/drm_utils.h b/sde-drm/drm_utils.h
new file mode 100644
index 0000000..2c6246d
--- /dev/null
+++ b/sde-drm/drm_utils.h
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2019, 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 __DRM_UTILS_H__
+#define __DRM_UTILS_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drmMode.h>
+#include <string>
+#include <utility>
+#include <vector>
+#include <unordered_map>
+
+namespace sde_drm {
+
+enum struct DRMStatus {
+  BUSY,
+  FREE,
+};
+
+void ParseFormats(const std::string &line, std::vector<std::pair<uint32_t, uint64_t>> *formats);
+void Tokenize(const std::string &str, std::vector<std::string> *tokens, char delim);
+void AddProperty(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value,
+                 bool cache, std::unordered_map<uint32_t, uint64_t> &prop_val_map);
+
+}  // namespace sde_drm
+
+#endif  // __DRM_UTILS_H__