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/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__