[automerger skipped] Mark 24Q4 as merged in aosp-main-future am: 7e3dec580e -s ours

am skip reason: Merged-In I3fa081c724b4adc9aa913c4158e587b1e376bd7a with SHA-1 d15890e6b9 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/external/drm_hwcomposer/+/29933964

Change-Id: Ia934109b84cb3bbc3bf7c3baba6d4aeb9580f317
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index f854999..f821595 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -36,7 +36,7 @@
 }
 
 check_tool_installed bpfmt
-check_tool_installed clang-format-diff-15
+check_tool_installed clang-format-diff-19
 
 git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git
 
@@ -61,7 +61,7 @@
 		exit 1
 	fi
 
-	git show "$h" -- | clang-format-diff-15 -p 1 -style=file > /tmp/format-fixup.patch
+	git show "$h" -- | clang-format-diff-19 -p 1 -style=file > /tmp/format-fixup.patch
 	if [ -s  /tmp/format-fixup.patch ]; then
 		cat /tmp/format-fixup.patch >&2
 		exit 1
diff --git a/.ci/Dockerfile b/.ci/Dockerfile
index c42c8b6..9dfe3d3 100644
--- a/.ci/Dockerfile
+++ b/.ci/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:23.04
+FROM ubuntu:24.10
 
 ENV DEBIAN_FRONTEND=noninteractive
 
@@ -6,7 +6,7 @@
 
 # Taking into account layer structure, everything should be done within one layer.
 RUN apt-get update && apt-get upgrade -y && \
-    apt-get install -y clang-15 clang-tidy-15 clang-format-15 git libdrm-dev blueprint-tools libgtest-dev clang \
+    apt-get install -y clang-19 clang-tidy-19 clang-format-19 git libdrm-dev blueprint-tools libgtest-dev clang \
     llvm make python3 wget sudo rsync lld pkg-config ninja-build meson \
     python3-mako python3-jinja2 python3-ply python3-yaml
 
@@ -41,10 +41,10 @@
 USER ${RUN_USER}
 
 # Install aospless package (produced by GloDroid/aospext)
-RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/-/project/5/uploads/d66764aa71f9f1235b92d44a652cd3c3/aospless_drm_hwcomposer_arm64.tar.xz && \
+RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/-/project/5/uploads/70643bd1c4d419015b9930b7aadc9cfd/aospless_drm_hwcomposer_arm64.tar.xz && \
     cd ${USER_HOME} && \
     sha256sum aospless_drm_hwcomposer_arm64.tar.xz && \
-    (echo 00ff288f184111dd35143c462e82fd5f8f31a1417d5eb9a11e8798695abcc141 aospless_drm_hwcomposer_arm64.tar.xz | sha256sum --check) && \
+    (echo 640e0d0e04761c804db69f880e0c0957699babdbe82c72c507177b860d878569 aospless_drm_hwcomposer_arm64.tar.xz | sha256sum --check) && \
     tar xf aospless_drm_hwcomposer_arm64.tar.xz && ln -s ../drm_hwcomposer/ ${USER_HOME}/aospless/src
 
 # Create project path
diff --git a/.ci/Makefile b/.ci/Makefile
index 325e0b5..051a437 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -1,18 +1,18 @@
 
-BASE_DIR ?=../aospless
+BASE_DIR:=../aospless
 
 SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
 
-CLANG := clang++-15
-CLANG_TIDY := clang-tidy-15
+CLANG := clang++-19
+CLANG_TIDY := clang-tidy-19
 OUT_DIR := /tmp/drm_hwcomposer/build
 SRC_DIR := .
 
-CXXFLAGS := -Wall -Wextra -Werror
+CXXFLAGS := -Wall -Wextra -Werror -Wno-missing-designated-field-initializers
 CXXFLAGS += -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
 CXXFLAGS += -fvisibility-inlines-hidden -std=gnu++17 -DHWC2_USE_CPP11 -DHWC2_INCLUDE_STRINGIFICATION -fno-rtti
 
-CXXARGS := $(shell cat $(BASE_DIR)/build_flags/sharedlib.cppflags)
+CXXARGS := $(shell cat $(BASE_DIR)/toolchain_wrapper/sharedlib.cppflags)
 CXXARGS := $(subst [BASE_DIR],$(BASE_DIR),$(CXXARGS))
 # clang-tidy doesn't like -mcpu=xxx flag
 CXXARGS := $(patsubst -mcpu=%,,$(CXXARGS))
@@ -45,6 +45,24 @@
     -hicpp-signed-bitwise                               \
     -misc-const-correctness                             \
     -readability-identifier-length                      \
+    -misc-include-cleaner                               \
+    -performance-enum-size                              \
+    -misc-use-anonymous-namespace                       \
+    -boost-use-ranges                                   \
+    -cppcoreguidelines-avoid-do-while                   \
+    -modernize-min-max-use-initializer-list             \
+    -cppcoreguidelines-owning-memory                    \
+    -readability-redundant-member-init                  \
+    -cppcoreguidelines-avoid-const-or-ref-data-members  \
+    -cert-err33-c                                       \
+    -readability-math-missing-parentheses               \
+    -readability-avoid-unconditional-preprocessor-if    \
+    -modernize-type-traits                              \
+    -clang-analyzer-optin.core.EnumCastOutOfRange       \
+    -performance-inefficient-vector-operation           \
+    -readability-static-accessed-through-instance       \
+    -misc-use-internal-linkage                          \
+    -performance-avoid-endl                             \
 
 TIDY_CHECKS_NORMAL :=                                   \
     $(TIDY_CHECKS_FINE)                                 \
diff --git a/.clang-format b/.clang-format
index 984fa5e..caadedf 100644
--- a/.clang-format
+++ b/.clang-format
@@ -3,5 +3,6 @@
 AllowShortIfStatementsOnASingleLine: false
 AllowShortLoopsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: None
+IncludeBlocks: Preserve
 PenaltyBreakAssignment: 10000000
 PenaltyBreakBeforeFirstCallParameter: 1000
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5863159..b045da8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,3 +1,5 @@
+image: ubuntu:24.10
+
 workflow:
   rules:
     - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
@@ -5,51 +7,31 @@
 
 variables:
   DEBIAN_FRONTEND: noninteractive
-  DOCKER_IMAGE_TAG: registry.freedesktop.org/drm-hwcomposer/drm-hwcomposer:latest
+
+before_script:
+  - apt-get --quiet update --yes >/dev/null
+  - apt-get --quiet install --yes clang-19 clang-tidy-19 clang-format-19 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
+  - apt-get --quiet install --yes clang llvm make python3 wget sudo rsync lld pkg-config ninja-build meson >/dev/null
+  - apt-get --quiet install --yes python3-mako python3-jinja2 python3-ply python3-yaml >/dev/null
 
 stages:
-  - build-container
   - build
   - tidy
   - style
 
-build-container:
-  stage: build-container
-  image: docker:27.0.3
-  services:
-    - docker:27.0.3-dind
-  variables:
-    DOCKER_TLS_CERTDIR: ""
-    # Use the fork's docker image when rebuilding the container
-    DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
-  before_script:
-    - echo "$CI_JOB_TOKEN" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
-  script:
-    - docker build -t $DOCKER_IMAGE_TAG -f .ci/Dockerfile .
-    - docker push $DOCKER_IMAGE_TAG
-    - echo "DOCKER_IMAGE_TAG=$DOCKER_IMAGE_TAG" >> build.env
-  after_script:
-    - docker logout
-  artifacts:
-    reports:
-      dotenv: build.env
-  rules:
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      changes:
-      - .ci/Dockerfile
-    - if: $CI_PIPELINE_SOURCE == 'push'
-      changes:
-      - .ci/Dockerfile
-
 build:
   stage: build
-  image: $DOCKER_IMAGE_TAG
   script:
     - mkdir -p install/arm64
-    - rm ${HOME}/aospless/src
-    - ln -s ${PWD} ${HOME}/aospless/src
-    - make -C ${HOME}/aospless all
-    - cp -r ${HOME}/aospless/install/* install/arm64
+    - cd ..
+    - rm -f aospless_drm_hwcomposer_arm64.tar.xz
+    - rm -rf aospless/*
+    - wget https://gitlab.freedesktop.org/-/project/5/uploads/70643bd1c4d419015b9930b7aadc9cfd/aospless_drm_hwcomposer_arm64.tar.xz
+    - tar xf aospless_drm_hwcomposer_arm64.tar.xz
+    - rm -rf aospless/src
+    - ln -s ../drm-hwcomposer/ aospless/src
+    - make -C ./aospless install
+    - cp -r aospless/install/* drm-hwcomposer/install/arm64
 
   artifacts:
     paths:
@@ -58,16 +40,17 @@
 
 tidy:
   stage: tidy
-  image: $DOCKER_IMAGE_TAG
   script:
-    - rm ${HOME}/aospless/src
-    - ln -s ${PWD} ${HOME}/aospless/src
-    - BASE_DIR=${HOME}/aospless make -j$(nproc) -k -f .ci/Makefile
-  timeout: 2h
+    - cd ..
+    - rm -f aospless_drm_hwcomposer_arm64.tar.xz
+    - rm -rf aospless/*
+    - wget https://gitlab.freedesktop.org/-/project/5/uploads/70643bd1c4d419015b9930b7aadc9cfd/aospless_drm_hwcomposer_arm64.tar.xz
+    - tar xf aospless_drm_hwcomposer_arm64.tar.xz
+    - cd -
+    - make -j$(nproc) -k -f .ci/Makefile
 
 checkstyle:
   stage: style
-  image: $DOCKER_IMAGE_TAG
   script: "./.ci/.gitlab-ci-checkcommit.sh"
   artifacts:
     when: on_failure
diff --git a/Android.bp b/Android.bp
index 2578188..6be50d6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,13 +97,13 @@
         "drm/DrmDisplayPipeline.cpp",
         "drm/DrmEncoder.cpp",
         "drm/DrmFbImporter.cpp",
+        "drm/DrmHwc.cpp",
         "drm/DrmMode.cpp",
         "drm/DrmPlane.cpp",
         "drm/DrmProperty.cpp",
         "drm/ResourceManager.cpp",
         "drm/UEventListener.cpp",
         "drm/VSyncWorker.cpp",
-        "drm/DrmHwc.cpp",
 
         "backend/Backend.cpp",
         "backend/BackendClient.cpp",
@@ -181,9 +181,9 @@
     name: "android.hardware.composer.hwc3-service.drm",
 
     srcs: [
+        ":drm_hwcomposer_common",
         ":drm_hwcomposer_hwc3",
         ":drm_hwcomposer_service",
-        ":drm_hwcomposer_common",
         "bufferinfo/legacy/BufferInfoLibdrm.cpp",
     ],
 
@@ -192,7 +192,7 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
+        "android.hardware.graphics.composer3-V4-ndk",
         "libbase",
         "libbinder_ndk",
         "liblog",
diff --git a/Makefile b/Makefile
index 8a88083..fc12423 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@
 	@echo "Run native build:"
 	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -f .ci/Makefile -j$(NPROCS)"
 	@echo "Run meson cross-build for Android:"
-	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless install"
 	@echo "Run style check:"
 	$(if $(GIT_IS_SYMLINK), \
 		./.ci/.gitlab-ci-checkcommit.sh, \
diff --git a/README.md b/README.md
index 5724b36..76cfd6c 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
   you with formatting of your patches:
 
     ```
-    git diff | clang-format-diff-15 -p 1 -style=file
+    git diff | clang-format-diff-19 -p 1 -style=file
     ```
 
 * Hardware specific changes should be tested on relevant platforms before
diff --git a/compositor/ColorInfo.h b/compositor/ColorInfo.h
new file mode 100644
index 0000000..1afda07
--- /dev/null
+++ b/compositor/ColorInfo.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+enum class Colorspace : int32_t {
+  kDefault,
+  kSmpte170MYcc,
+  kBt709Ycc,
+  kXvycc601,
+  kXvycc709,
+  kSycc601,
+  kOpycc601,
+  kOprgb,
+  kBt2020Cycc,
+  kBt2020Rgb,
+  kBt2020Ycc,
+  kDciP3RgbD65,
+  kDciP3RgbTheater,
+  kRgbWideFixed,
+  kRgbWideFloat,
+  kBt601Ycc,
+};
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index 537f819..bb26189 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -139,6 +139,17 @@
       return -EINVAL;
   }
 
+  if (args.colorspace && connector->GetColorspaceProperty()) {
+    if (!connector->GetColorspaceProperty()
+             .AtomicSet(*pset, connector->GetColorspacePropertyValue(*args.colorspace)))
+      return -EINVAL;
+  }
+
+  if (args.content_type && connector->GetContentTypeProperty()) {
+    if (!connector->GetContentTypeProperty().AtomicSet(*pset, *args.content_type))
+      return -EINVAL;
+  }
+
   auto unused_planes = new_frame_state.used_planes;
 
   if (args.composition) {
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index 923927d..c8736f2 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -21,6 +21,7 @@
 #include <memory>
 #include <optional>
 
+#include "compositor/ColorInfo.h"
 #include "compositor/DrmKmsPlan.h"
 #include "compositor/LayerData.h"
 #include "drm/DrmPlane.h"
@@ -36,6 +37,8 @@
   std::optional<bool> active;
   std::shared_ptr<DrmKmsPlan> composition;
   std::shared_ptr<drm_color_ctm> color_matrix;
+  std::optional<Colorspace> colorspace;
+  std::optional<int32_t> content_type;
 
   std::shared_ptr<DrmFbIdHandle> writeback_fb;
   SharedFd writeback_release_fence;
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index e459fe7..5371513 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <drm/drm_mode.h>
 #define LOG_TAG "drmhwc"
 
 #include "DrmConnector.h"
@@ -42,22 +43,21 @@
 
 constexpr size_t kTypesCount = 21;
 
-static bool GetOptionalConnectorProperty(const DrmDevice &dev,
-                                         const DrmConnector &connector,
-                                         const char *prop_name,
-                                         DrmProperty *property) {
-  return dev.GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR,
-                         prop_name, property) == 0;
-}
+auto DrmConnector::GetConnectorProperty(const char *prop_name,
+                                        DrmProperty *property,
+                                        bool is_optional) -> bool {
+  auto err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
+                               property);
+  if (err == 0)
+    return true;
 
-static bool GetConnectorProperty(const DrmDevice &dev,
-                                 const DrmConnector &connector,
-                                 const char *prop_name, DrmProperty *property) {
-  if (!GetOptionalConnectorProperty(dev, connector, prop_name, property)) {
-    ALOGE("Could not get %s property\n", prop_name);
-    return false;
+  if (is_optional) {
+    ALOGV("Could not get optional %s property from connector %d", prop_name,
+          GetId());
+  } else {
+    ALOGE("Could not get %s property from connector %d", prop_name, GetId());
   }
-  return true;
+  return false;
 }
 
 auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
@@ -72,28 +72,75 @@
   auto c = std::unique_ptr<DrmConnector>(
       new DrmConnector(std::move(conn), &dev, index));
 
-  if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
-      !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
-    return {};
-  }
-
-  c->UpdateEdidProperty();
-
-  if (c->IsWriteback() &&
-      (!GetConnectorProperty(dev, *c, "WRITEBACK_PIXEL_FORMATS",
-                             &c->writeback_pixel_formats_) ||
-       !GetConnectorProperty(dev, *c, "WRITEBACK_FB_ID",
-                             &c->writeback_fb_id_) ||
-       !GetConnectorProperty(dev, *c, "WRITEBACK_OUT_FENCE_PTR",
-                             &c->writeback_out_fence_))) {
+  if (!c->Init()) {
+    ALOGE("Failed to initialize connector %d", connector_id);
     return {};
   }
 
   return c;
 }
 
+auto DrmConnector::Init()-> bool {
+  if (!GetConnectorProperty("DPMS", &dpms_property_) ||
+      !GetConnectorProperty("CRTC_ID", &crtc_id_property_)) {
+    return false;
+  }
+
+  UpdateEdidProperty();
+
+  if (IsWriteback() &&
+      (!GetConnectorProperty("WRITEBACK_PIXEL_FORMATS",
+                             &writeback_pixel_formats_) ||
+       !GetConnectorProperty("WRITEBACK_FB_ID", &writeback_fb_id_) ||
+       !GetConnectorProperty("WRITEBACK_OUT_FENCE_PTR",
+                             &writeback_out_fence_))) {
+    return false;
+  }
+
+  if (GetConnectorProperty("Colorspace", &colorspace_property_,
+                           /*is_optional=*/true)) {
+    colorspace_property_.AddEnumToMap("Default", Colorspace::kDefault,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("SMPTE_170M_YCC", Colorspace::kSmpte170MYcc,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("BT709_YCC", Colorspace::kBt709Ycc,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("XVYCC_601", Colorspace::kXvycc601,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("XVYCC_709", Colorspace::kXvycc709,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("SYCC_601", Colorspace::kSycc601,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("opYCC_601", Colorspace::kOpycc601,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("opRGB", Colorspace::kOprgb,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("BT2020_CYCC", Colorspace::kBt2020Cycc,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("BT2020_RGB", Colorspace::kBt2020Rgb,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("BT2020_YCC", Colorspace::kBt2020Ycc,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("DCI-P3_RGB_D65", Colorspace::kDciP3RgbD65,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("DCI-P3_RGB_Theater", Colorspace::kDciP3RgbTheater,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("RGB_WIDE_FIXED", Colorspace::kRgbWideFixed,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("RGB_WIDE_FLOAT", Colorspace::kRgbWideFloat,
+                                      colorspace_enum_map_);
+    colorspace_property_.AddEnumToMap("BT601_YCC", Colorspace::kBt601Ycc,
+                                      colorspace_enum_map_);
+  }
+
+  GetConnectorProperty("content type", &content_type_property_,
+                       /*is_optional=*/true);
+
+  return true;
+}
+
 int DrmConnector::UpdateEdidProperty() {
-  return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
+  return GetConnectorProperty("EDID", &edid_property_, /*is_optional=*/true)
              ? 0
              : -EINVAL;
 }
@@ -184,4 +231,14 @@
   return 0;
 }
 
+bool DrmConnector::IsLinkStatusGood() {
+  if (GetConnectorProperty("link-status", &link_status_property_, false)) {
+    auto link_status_property_value = link_status_property_.GetValue();
+    if (link_status_property_value &&
+        (link_status_property_value == DRM_MODE_LINK_STATUS_BAD))
+      return false;
+  }
+
+  return true;
+}
 }  // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 018c615..9186f07 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -27,6 +27,8 @@
 #include "DrmProperty.h"
 #include "DrmUnique.h"
 
+#include "compositor/ColorInfo.h"
+
 namespace android {
 
 class DrmDevice;
@@ -78,6 +80,8 @@
 
   int UpdateModes();
 
+  bool IsLinkStatusGood();
+
   auto &GetModes() const {
     return modes_;
   }
@@ -94,6 +98,18 @@
     return edid_property_;
   }
 
+  auto &GetColorspaceProperty() const {
+    return colorspace_property_;
+  }
+
+  auto GetColorspacePropertyValue(Colorspace c) {
+    return colorspace_enum_map_[c];
+  }
+
+  auto &GetContentTypeProperty() const {
+    return content_type_property_;
+  }
+
   auto &GetWritebackFbIdProperty() const {
     return writeback_fb_id_;
   }
@@ -123,6 +139,10 @@
   DrmModeConnectorUnique connector_;
   DrmDevice *const drm_;
 
+  auto Init() -> bool;
+  auto GetConnectorProperty(const char *prop_name, DrmProperty *property,
+                            bool is_optional = false) -> bool;
+
   const uint32_t index_in_res_array_;
 
   std::vector<DrmMode> modes_;
@@ -130,8 +150,14 @@
   DrmProperty dpms_property_;
   DrmProperty crtc_id_property_;
   DrmProperty edid_property_;
+  DrmProperty colorspace_property_;
+  DrmProperty content_type_property_;
+
+  DrmProperty link_status_property_;
   DrmProperty writeback_pixel_formats_;
   DrmProperty writeback_fb_id_;
   DrmProperty writeback_out_fence_;
+
+  std::map<Colorspace, uint64_t> colorspace_enum_map_;
 };
 }  // namespace android
diff --git a/drm/DrmHwc.cpp b/drm/DrmHwc.cpp
index df3eb56..57293c2 100644
--- a/drm/DrmHwc.cpp
+++ b/drm/DrmHwc.cpp
@@ -124,6 +124,16 @@
   return true;
 }
 
+void DrmHwc::NotifyDisplayLinkStatus(
+    std::shared_ptr<DrmDisplayPipeline> pipeline) {
+  if (display_handles_.count(pipeline) == 0) {
+    ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
+    return;
+  }
+  ScheduleHotplugEvent(display_handles_[pipeline],
+                       DisplayStatus::kLinkTrainingFailed);
+}
+
 HWC2::Error DrmHwc::CreateVirtualDisplay(
     uint32_t width, uint32_t height,
     int32_t *format,  // NOLINT(readability-non-const-parameter)
diff --git a/drm/DrmHwc.h b/drm/DrmHwc.h
index 44dc276..ac97717 100644
--- a/drm/DrmHwc.h
+++ b/drm/DrmHwc.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "drm/DrmDisplayPipeline.h"
 #include "drm/ResourceManager.h"
 #include "hwc2_device/HwcDisplay.h"
 
@@ -26,6 +27,13 @@
   DrmHwc();
   ~DrmHwc() override = default;
 
+  // Enum for Display status: Connected, Disconnected, Link Training Failed
+  enum DisplayStatus {
+    kDisconnected,
+    kConnected,
+    kLinkTrainingFailed,
+  };
+
   // Client Callback functions.:
   virtual void SendVsyncEventToClient(hwc2_display_t displayid,
                                       int64_t timestamp,
@@ -34,7 +42,7 @@
       hwc2_display_t displayid, int64_t timestamp) const = 0;
   virtual void SendRefreshEventToClient(uint64_t displayid) = 0;
   virtual void SendHotplugEventToClient(hwc2_display_t displayid,
-                                        bool connected) = 0;
+                                        enum DisplayStatus display_status) = 0;
 
   // Device functions
   HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
@@ -53,8 +61,9 @@
     return resource_manager_;
   }
 
-  void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
-    deferred_hotplug_events_[displayid] = connected;
+  void ScheduleHotplugEvent(hwc2_display_t displayid,
+                            enum DisplayStatus display_status) {
+    deferred_hotplug_events_[displayid] = display_status;
   }
 
   void DeinitDisplays();
@@ -64,8 +73,14 @@
   bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
   void FinalizeDisplayBinding() override;
 
+  // Notify Display Link Status
+  void NotifyDisplayLinkStatus(
+      std::shared_ptr<DrmDisplayPipeline> pipeline) override;
+
  protected:
-  auto& Displays() { return displays_; }
+  auto &Displays() {
+    return displays_;
+  }
 
  private:
   ResourceManager resource_manager_;
@@ -75,7 +90,7 @@
 
   std::string dump_string_;
 
-  std::map<hwc2_display_t, bool> deferred_hotplug_events_;
+  std::map<hwc2_display_t, enum DisplayStatus> deferred_hotplug_events_;
   std::vector<hwc2_display_t> displays_for_removal_list_;
 
   uint32_t last_display_handle_ = kPrimaryDisplay;
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index 5ac80c4..0c23734 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -154,6 +154,10 @@
         attached_pipelines_.erase(conn);
       }
     }
+    if (connected) {
+      if (!conn->IsLinkStatusGood())
+        frontend_interface_->NotifyDisplayLinkStatus(attached_pipelines_[conn]);
+    }
   }
   frontend_interface_->FinalizeDisplayBinding();
 }
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 9a2652c..3c4d7ae 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -22,6 +22,7 @@
 #include "DrmDevice.h"
 #include "DrmDisplayPipeline.h"
 #include "DrmFbImporter.h"
+#include "DrmProperty.h"
 #include "UEventListener.h"
 
 namespace android {
@@ -37,6 +38,8 @@
   virtual bool BindDisplay(std::shared_ptr<DrmDisplayPipeline>) = 0;
   virtual bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline>) = 0;
   virtual void FinalizeDisplayBinding() = 0;
+  virtual void NotifyDisplayLinkStatus(
+      std::shared_ptr<DrmDisplayPipeline> pipeline) = 0;
 };
 
 class ResourceManager {
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index c120b63..b243199 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -69,15 +69,16 @@
 }
 
 void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
-                                         bool connected) {
+                                         DisplayStatus display_status) {
   auto hc = hotplug_callback_;
+
   if (hc.first != nullptr && hc.second != nullptr) {
     /* For some reason HWC Service will call HWC2 API in hotplug callback
      * handler. This is the reason we're using recursive mutex.
      */
     hc.first(hc.second, displayid,
-             connected ? HWC2_CONNECTION_CONNECTED
-                       : HWC2_CONNECTION_DISCONNECTED);
+             display_status ? HWC2_CONNECTION_CONNECTED
+                            : HWC2_CONNECTION_DISCONNECTED);
   }
 }
 
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index b3ca0f8..ac87153 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -37,7 +37,7 @@
       hwc2_display_t displayid, int64_t timestamp) const override;
   void SendRefreshEventToClient(uint64_t displayid) override;
   void SendHotplugEventToClient(hwc2_display_t displayid,
-                                bool connected) override;
+                                DisplayStatus display_status) override;
 
  private:
   std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 9a9761b..7f65e65 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -19,6 +19,8 @@
 
 #include "HwcDisplay.h"
 
+#include <cinttypes>
+
 #include "backend/Backend.h"
 #include "backend/BackendManager.h"
 #include "bufferinfo/BufferInfoGetter.h"
@@ -73,7 +75,7 @@
   }
 }
 
-void HwcDisplay::SetColorMarixToIdentity() {
+void HwcDisplay::SetColorMatrixToIdentity() {
   color_matrix_ = std::make_shared<drm_color_ctm>();
   for (int i = 0; i < kCtmCols; i++) {
     for (int j = 0; j < kCtmRows; j++) {
@@ -96,9 +98,9 @@
 
   if (pipeline_ != nullptr || handle_ == kPrimaryDisplay) {
     Init();
-    hwc_->ScheduleHotplugEvent(handle_, /*connected = */ true);
+    hwc_->ScheduleHotplugEvent(handle_, DrmHwc::kConnected);
   } else {
-    hwc_->ScheduleHotplugEvent(handle_, /*connected = */ false);
+    hwc_->ScheduleHotplugEvent(handle_, DrmHwc::kDisconnected);
   }
 }
 
@@ -189,7 +191,7 @@
 
   client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
 
-  SetColorMarixToIdentity();
+  SetColorMatrixToIdentity();
 
   return HWC2::Error::None;
 }
@@ -462,6 +464,8 @@
   }
 
   a_args.color_matrix = color_matrix_;
+  a_args.content_type = content_type_;
+  a_args.colorspace = colorspace_;
 
   uint32_t prev_vperiod_ns = 0;
   GetDisplayVsyncPeriod(&prev_vperiod_ns);
@@ -671,11 +675,35 @@
 }
 
 HWC2::Error HwcDisplay::SetColorMode(int32_t mode) {
-  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
+  /* Maps to the Colorspace DRM connector property:
+   * https://elixir.bootlin.com/linux/v6.11/source/include/drm/drm_connector.h#L538
+   */
+  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3)
     return HWC2::Error::BadParameter;
 
-  if (mode != HAL_COLOR_MODE_NATIVE)
-    return HWC2::Error::Unsupported;
+  switch (mode) {
+    case HAL_COLOR_MODE_NATIVE:
+      colorspace_ = Colorspace::kDefault;
+      break;
+    case HAL_COLOR_MODE_STANDARD_BT601_625:
+    case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
+    case HAL_COLOR_MODE_STANDARD_BT601_525:
+    case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
+      // The DP spec does not say whether this is the 525 or the 625 line version.
+      colorspace_ = Colorspace::kBt601Ycc;
+      break;
+    case HAL_COLOR_MODE_STANDARD_BT709:
+    case HAL_COLOR_MODE_SRGB:
+      colorspace_ = Colorspace::kBt709Ycc;
+      break;
+    case HAL_COLOR_MODE_DCI_P3:
+    case HAL_COLOR_MODE_DISPLAY_P3:
+      colorspace_ = Colorspace::kDciP3RgbD65;
+      break;
+    case HAL_COLOR_MODE_ADOBE_RGB:
+    default:
+      return HWC2::Error::Unsupported;
+  }
 
   color_mode_ = mode;
   return HWC2::Error::None;
@@ -683,6 +711,15 @@
 
 #include <xf86drmMode.h>
 
+static uint64_t To3132FixPt(float in) {
+  constexpr uint64_t kSignMask = (1ULL << 63);
+  constexpr uint64_t kValueMask = ~(1ULL << 63);
+  constexpr auto kValueScale = static_cast<float>(1ULL << 32);
+  if (in < 0)
+    return (static_cast<uint64_t>(-in * kValueScale) & kValueMask) | kSignMask;
+  return static_cast<uint64_t>(in * kValueScale) & kValueMask;
+}
+
 HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
   if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
       hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
@@ -701,17 +738,40 @@
 
   switch (color_transform_hint_) {
     case HAL_COLOR_TRANSFORM_IDENTITY:
-      SetColorMarixToIdentity();
+      SetColorMatrixToIdentity();
       break;
     case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+      // Without HW support, we cannot correctly process matrices with an offset.
+      for (int i = 12; i < 14; i++) {
+        if (matrix[i] != 0.F)
+          return HWC2::Error::Unsupported;
+      }
+
+      /* HAL provides a 4x4 float type matrix:
+       * | 0  1  2  3|
+       * | 4  5  6  7|
+       * | 8  9 10 11|
+       * |12 13 14 15|
+       *
+       * R_out = R*0 + G*4 + B*8 + 12
+       * G_out = R*1 + G*5 + B*9 + 13
+       * B_out = R*2 + G*6 + B*10 + 14
+       *
+       * DRM expects a 3x3 s31.32 fixed point matrix:
+       * out   matrix    in
+       * |R|   |0 1 2|   |R|
+       * |G| = |3 4 5| x |G|
+       * |B|   |6 7 8|   |B|
+       *
+       * R_out = R*0 + G*1 + B*2
+       * G_out = R*3 + G*4 + B*5
+       * B_out = R*6 + G*7 + B*8
+       */
       color_matrix_ = std::make_shared<drm_color_ctm>();
-      /* DRM expects a 3x3 matrix, but the HAL provides a 4x4 matrix. */
       for (int i = 0; i < kCtmCols; i++) {
         for (int j = 0; j < kCtmRows; j++) {
           constexpr int kInCtmRows = 4;
-          /* HAL matrix type is float, but DRM expects a s31.32 fix point */
-          auto value = uint64_t(matrix[i * kInCtmRows + j] * float(1ULL << 32));
-          color_matrix_->matrix[i * kCtmRows + j] = value;
+          color_matrix_->matrix[i * kCtmRows + j] = To3132FixPt(matrix[j * kInCtmRows + i]);
         }
       }
       break;
@@ -916,12 +976,13 @@
 }
 
 HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
-  if (contentType != HWC2_CONTENT_TYPE_NONE)
-    return HWC2::Error::Unsupported;
-
-  /* TODO: Map to the DRM Connector property:
-   * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809
+  /* Maps exactly to the content_type DRM connector property:
+   * https://elixir.bootlin.com/linux/v6.11/source/include/uapi/drm/drm_mode.h#L107
    */
+  if (contentType < HWC2_CONTENT_TYPE_NONE || contentType > HWC2_CONTENT_TYPE_GAME)
+    return HWC2::Error::BadParameter;
+
+  content_type_ = contentType;
 
   return HWC2::Error::None;
 }
@@ -1016,16 +1077,12 @@
       intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
     return HWC2::Error::BadParameter;
 
-  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
-    return HWC2::Error::BadParameter;
-
-  if (mode != HAL_COLOR_MODE_NATIVE)
-    return HWC2::Error::Unsupported;
-
   if (intent != HAL_RENDER_INTENT_COLORIMETRIC)
     return HWC2::Error::Unsupported;
 
-  color_mode_ = mode;
+  auto err = SetColorMode(mode);
+  if (err != HWC2::Error::None) return err;
+
   return HWC2::Error::None;
 }
 
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 87d2da7..c568a73 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -23,6 +23,7 @@
 #include <sstream>
 
 #include "HwcDisplayConfigs.h"
+#include "compositor/ColorInfo.h"
 #include "compositor/FlatteningController.h"
 #include "compositor/LayerData.h"
 #include "drm/DrmAtomicStateManager.h"
@@ -58,7 +59,7 @@
     return configs_;
   }
 
-  // HWC Hooks
+  // HWC2 Hooks - these should not be used outside of the hwc2 device.
   HWC2::Error AcceptDisplayChanges();
   HWC2::Error CreateLayer(hwc2_layer_t *layer);
   HWC2::Error DestroyLayer(hwc2_layer_t layer);
@@ -233,6 +234,8 @@
   static constexpr int kCtmCols = 3;
   std::shared_ptr<drm_color_ctm> color_matrix_;
   android_color_transform_t color_transform_hint_{};
+  int32_t content_type_{};
+  Colorspace colorspace_{};
 
   std::shared_ptr<DrmKmsPlan> current_plan_;
 
@@ -241,7 +244,7 @@
   Stats prev_stats_;
   std::string DumpDelta(HwcDisplay::Stats delta);
 
-  void SetColorMarixToIdentity();
+  void SetColorMatrixToIdentity();
 
   HWC2::Error Init();
 
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index da4ce7c..cd2a319 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -24,6 +24,37 @@
 
 namespace android {
 
+void HwcLayer::SetLayerProperties(const LayerProperties& layer_properties) {
+  if (layer_properties.blend_mode) {
+    blend_mode_ = layer_properties.blend_mode.value();
+  }
+  if (layer_properties.color_space) {
+    color_space_ = layer_properties.color_space.value();
+  }
+  if (layer_properties.sample_range) {
+    sample_range_ = layer_properties.sample_range.value();
+  }
+  if (layer_properties.composition_type) {
+    sf_type_ = layer_properties.composition_type.value();
+  }
+  if (layer_properties.display_frame) {
+    layer_data_.pi.display_frame = layer_properties.display_frame.value();
+  }
+  if (layer_properties.alpha) {
+    layer_data_.pi.alpha = std::lround(layer_properties.alpha.value() *
+                                       UINT16_MAX);
+  }
+  if (layer_properties.source_crop) {
+    layer_data_.pi.source_crop = layer_properties.source_crop.value();
+  }
+  if (layer_properties.transform) {
+    layer_data_.pi.transform = layer_properties.transform.value();
+  }
+  if (layer_properties.z_order) {
+    z_order_ = layer_properties.z_order.value();
+  }
+}
+
 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
 HWC2::Error HwcLayer::SetCursorPosition(int32_t /*x*/, int32_t /*y*/) {
   return HWC2::Error::None;
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index b69ce5b..b8fb959 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <aidl/android/hardware/graphics/common/Transform.h>
 #include <hardware/hwcomposer2.h>
 
 #include "bufferinfo/BufferInfoGetter.h"
@@ -27,6 +28,19 @@
 
 class HwcLayer {
  public:
+  // A set of properties to be validated.
+  struct LayerProperties {
+    std::optional<BufferBlendMode> blend_mode;
+    std::optional<BufferColorSpace> color_space;
+    std::optional<BufferSampleRange> sample_range;
+    std::optional<HWC2::Composition> composition_type;
+    std::optional<hwc_rect_t> display_frame;
+    std::optional<float> alpha;
+    std::optional<hwc_frect_t> source_crop;
+    std::optional<LayerTransform> transform;
+    std::optional<uint32_t> z_order;
+  };
+
   explicit HwcLayer(HwcDisplay *parent_display) : parent_(parent_display){};
 
   HWC2::Composition GetSfType() const {
@@ -61,7 +75,9 @@
     return layer_data_;
   }
 
-  // Layer hooks
+  void SetLayerProperties(const LayerProperties &layer_properties);
+
+  // HWC2 Layer hooks
   HWC2::Error SetCursorPosition(int32_t /*x*/, int32_t /*y*/);
   HWC2::Error SetLayerBlendMode(int32_t mode);
   HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence);
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 2efce8f..76eb52a 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -19,28 +19,30 @@
 
 #include "ComposerClient.h"
 
-#include <aidlcommonsupport/NativeHandle.h>
-#include <android-base/logging.h>
-#include <android/binder_ibinder_platform.h>
-#include <hardware/hwcomposer2.h>
-
 #include <cinttypes>
 #include <cmath>
 #include <memory>
 #include <unordered_map>
 #include <vector>
 
-#include "aidl/android/hardware/graphics/common/Transform.h"
-#include "aidl/android/hardware/graphics/composer3/ClientTarget.h"
-#include "aidl/android/hardware/graphics/composer3/Composition.h"
-#include "aidl/android/hardware/graphics/composer3/DisplayRequest.h"
-#include "aidl/android/hardware/graphics/composer3/IComposerClient.h"
-#include "aidl/android/hardware/graphics/composer3/PowerMode.h"
-#include "aidl/android/hardware/graphics/composer3/PresentOrValidate.h"
-#include "aidl/android/hardware/graphics/composer3/RenderIntent.h"
-#include "android/binder_auto_utils.h"
-#include "cutils/native_handle.h"
-#include "hardware/hwcomposer_defs.h"
+#include <aidl/android/hardware/graphics/common/Transform.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTarget.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayRequest.h>
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <aidl/android/hardware/graphics/composer3/Lut.h>
+#include <aidl/android/hardware/graphics/composer3/PowerMode.h>
+#include <aidl/android/hardware/graphics/composer3/PresentOrValidate.h>
+#include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder_platform.h>
+#include <cutils/native_handle.h>
+#include <hardware/hwcomposer2.h>
+#include <hardware/hwcomposer_defs.h>
+
+#include "bufferinfo/BufferInfo.h"
 #include "hwc2_device/HwcDisplay.h"
 #include "hwc2_device/HwcDisplayConfigs.h"
 #include "hwc2_device/HwcLayer.h"
@@ -48,7 +50,10 @@
 #include "hwc3/Utils.h"
 
 using ::android::HwcDisplay;
+using ::android::HwcDisplayConfig;
 using ::android::HwcDisplayConfigs;
+using ::android::HwcLayer;
+using ::android::LayerTransform;
 
 #include "utils/log.h"
 
@@ -64,6 +69,209 @@
 };
 // clang-format on
 
+std::optional<BufferBlendMode> AidlToBlendMode(
+    const std::optional<ParcelableBlendMode>& aidl_blend_mode) {
+  if (!aidl_blend_mode) {
+    return std::nullopt;
+  }
+
+  switch (aidl_blend_mode->blendMode) {
+    case common::BlendMode::NONE:
+      return BufferBlendMode::kNone;
+    case common::BlendMode::PREMULTIPLIED:
+      return BufferBlendMode::kPreMult;
+    case common::BlendMode::COVERAGE:
+      return BufferBlendMode::kCoverage;
+    case common::BlendMode::INVALID:
+      ALOGE("Invalid BlendMode");
+      return std::nullopt;
+  }
+}
+
+std::optional<BufferColorSpace> AidlToColorSpace(
+    const std::optional<ParcelableDataspace>& dataspace) {
+  if (!dataspace) {
+    return std::nullopt;
+  }
+
+  int32_t standard = static_cast<int32_t>(dataspace->dataspace) &
+                     static_cast<int32_t>(common::Dataspace::STANDARD_MASK);
+  switch (standard) {
+    case static_cast<int32_t>(common::Dataspace::STANDARD_BT709):
+      return BufferColorSpace::kItuRec709;
+    case static_cast<int32_t>(common::Dataspace::STANDARD_BT601_625):
+    case static_cast<int32_t>(common::Dataspace::STANDARD_BT601_625_UNADJUSTED):
+    case static_cast<int32_t>(common::Dataspace::STANDARD_BT601_525):
+    case static_cast<int32_t>(common::Dataspace::STANDARD_BT601_525_UNADJUSTED):
+      return BufferColorSpace::kItuRec601;
+    case static_cast<int32_t>(common::Dataspace::STANDARD_BT2020):
+    case static_cast<int32_t>(
+        common::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE):
+      return BufferColorSpace::kItuRec2020;
+    default:
+      ALOGE("Unsupported standard: %d", standard);
+      return std::nullopt;
+  }
+}
+
+std::optional<BufferSampleRange> AidlToSampleRange(
+    const std::optional<ParcelableDataspace>& dataspace) {
+  if (!dataspace) {
+    return std::nullopt;
+  }
+
+  int32_t sample_range = static_cast<int32_t>(dataspace->dataspace) &
+                         static_cast<int32_t>(common::Dataspace::RANGE_MASK);
+  switch (sample_range) {
+    case static_cast<int32_t>(common::Dataspace::RANGE_FULL):
+      return BufferSampleRange::kFullRange;
+    case static_cast<int32_t>(common::Dataspace::RANGE_LIMITED):
+      return BufferSampleRange::kLimitedRange;
+    default:
+      ALOGE("Unsupported sample range: %d", sample_range);
+      return std::nullopt;
+  }
+}
+
+bool IsSupportedCompositionType(
+    const std::optional<ParcelableComposition> composition) {
+  if (!composition) {
+    return true;
+  }
+  switch (composition->composition) {
+    case Composition::INVALID:
+    case Composition::CLIENT:
+    case Composition::DEVICE:
+    case Composition::SOLID_COLOR:
+    case Composition::CURSOR:
+      return true;
+
+    // Unsupported composition types. Set an error for the current
+    // DisplayCommand and return.
+    case Composition::DISPLAY_DECORATION:
+    case Composition::SIDEBAND:
+    case Composition::REFRESH_RATE_INDICATOR:
+      return false;
+  }
+}
+
+bool ValidateLayerBrightness(const std::optional<LayerBrightness>& brightness) {
+  if (!brightness) {
+    return true;
+  }
+  return !(std::signbit(brightness->brightness) ||
+           std::isnan(brightness->brightness));
+}
+
+std::optional<HWC2::Composition> AidlToCompositionType(
+    const std::optional<ParcelableComposition> composition) {
+  if (!composition) {
+    return std::nullopt;
+  }
+
+  switch (composition->composition) {
+    case Composition::INVALID:
+      return HWC2::Composition::Invalid;
+    case Composition::CLIENT:
+      return HWC2::Composition::Client;
+    case Composition::DEVICE:
+      return HWC2::Composition::Device;
+    case Composition::SOLID_COLOR:
+      return HWC2::Composition::SolidColor;
+    case Composition::CURSOR:
+      return HWC2::Composition::Cursor;
+
+    // Unsupported composition types.
+    case Composition::DISPLAY_DECORATION:
+    case Composition::SIDEBAND:
+    case Composition::REFRESH_RATE_INDICATOR:
+      ALOGE("Unsupported composition type: %s",
+            toString(composition->composition).c_str());
+      return std::nullopt;
+  }
+}
+
+DisplayConfiguration HwcDisplayConfigToAidlConfiguration(
+    const HwcDisplayConfigs& configs, const HwcDisplayConfig& config) {
+  DisplayConfiguration aidl_configuration =
+      {.configId = static_cast<int32_t>(config.id),
+       .width = config.mode.GetRawMode().hdisplay,
+       .height = config.mode.GetRawMode().vdisplay,
+       .configGroup = static_cast<int32_t>(config.group_id),
+       .vsyncPeriod = config.mode.GetVSyncPeriodNs()};
+
+  if (configs.mm_width != 0) {
+    // ideally this should be vdisplay/mm_heigth, however mm_height
+    // comes from edid parsing and is highly unreliable. Viewing the
+    // rarity of anisotropic displays, falling back to a single value
+    // for dpi yield more correct output.
+    static const float kMmPerInch = 25.4;
+    float dpi = float(config.mode.GetRawMode().hdisplay) * kMmPerInch /
+                float(configs.mm_width);
+    aidl_configuration.dpi = {.x = dpi, .y = dpi};
+  }
+  // TODO: Populate vrrConfig.
+  return aidl_configuration;
+}
+
+std::optional<hwc_rect> AidlToRect(const std::optional<common::Rect>& rect) {
+  if (!rect) {
+    return std::nullopt;
+  }
+  return hwc_rect{rect->left, rect->top, rect->right, rect->bottom};
+}
+
+std::optional<hwc_frect> AidlToFRect(const std::optional<common::FRect>& rect) {
+  if (!rect) {
+    return std::nullopt;
+  }
+  return hwc_frect{rect->left, rect->top, rect->right, rect->bottom};
+}
+
+std::optional<float> AidlToAlpha(const std::optional<PlaneAlpha>& alpha) {
+  if (!alpha) {
+    return std::nullopt;
+  }
+  return alpha->alpha;
+}
+
+std::optional<uint32_t> AidlToZOrder(const std::optional<ZOrder>& z_order) {
+  if (!z_order) {
+    return std::nullopt;
+  }
+  return z_order->z;
+}
+
+std::optional<LayerTransform> AidlToLayerTransform(
+    const std::optional<ParcelableTransform>& aidl_transform) {
+  if (!aidl_transform) {
+    return std::nullopt;
+  }
+
+  uint32_t transform = LayerTransform::kIdentity;
+  // 270* and 180* cannot be combined with flips. More specifically, they
+  // already contain both horizontal and vertical flips, so those fields are
+  // redundant in this case. 90* rotation can be combined with either horizontal
+  // flip or vertical flip, so treat it differently
+  if (aidl_transform->transform == common::Transform::ROT_270) {
+    transform = LayerTransform::kRotate270;
+  } else if (aidl_transform->transform == common::Transform::ROT_180) {
+    transform = LayerTransform::kRotate180;
+  } else {
+    auto aidl_transform_bits = static_cast<uint32_t>(aidl_transform->transform);
+    if ((aidl_transform_bits &
+         static_cast<uint32_t>(common::Transform::FLIP_H)) != 0)
+      transform |= LayerTransform::kFlipH;
+    if ((aidl_transform_bits &
+         static_cast<uint32_t>(common::Transform::FLIP_V)) != 0)
+      transform |= LayerTransform::kFlipV;
+    if ((aidl_transform_bits &
+         static_cast<uint32_t>(common::Transform::ROT_90)) != 0)
+      transform |= LayerTransform::kRotate90;
+  }
+  return static_cast<LayerTransform>(transform);
+}
+
 }  // namespace
 
 ComposerClient::ComposerClient() {
@@ -306,38 +514,37 @@
     return;
   }
 
+  // If the requested composition type is not supported, the HWC should return
+  // an error and not process any further commands.
+  if (!IsSupportedCompositionType(command.composition)) {
+    cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
+    return;
+  }
+
+  // For some invalid parameters, the HWC should return an error and not process
+  // any further commands.
+  if (!ValidateLayerBrightness(command.brightness)) {
+    cmd_result_writer_->AddError(hwc3::Error::kBadParameter);
+    return;
+  }
+
   HwcLayerWrapper layer_wrapper{command.layer, layer};
   if (command.buffer) {
     ExecuteSetLayerBuffer(display_id, layer_wrapper, *command.buffer);
   }
-  if (command.blendMode) {
-    ExecuteSetLayerBlendMode(display_id, layer_wrapper, *command.blendMode);
-  }
-  if (command.composition) {
-    ExecuteSetLayerComposition(display_id, layer_wrapper, *command.composition);
-  }
-  if (command.dataspace) {
-    ExecuteSetLayerDataspace(display_id, layer_wrapper, *command.dataspace);
-  }
-  if (command.displayFrame) {
-    ExecuteSetLayerDisplayFrame(display_id, layer_wrapper,
-                                *command.displayFrame);
-  }
-  if (command.planeAlpha) {
-    ExecuteSetLayerPlaneAlpha(display_id, layer_wrapper, *command.planeAlpha);
-  }
-  if (command.sourceCrop) {
-    ExecuteSetLayerSourceCrop(display_id, layer_wrapper, *command.sourceCrop);
-  }
-  if (command.transform) {
-    ExecuteSetLayerTransform(display_id, layer_wrapper, *command.transform);
-  }
-  if (command.z) {
-    ExecuteSetLayerZOrder(display_id, layer_wrapper, *command.z);
-  }
-  if (command.brightness) {
-    ExecuteSetLayerBrightness(display_id, layer_wrapper, *command.brightness);
-  }
+
+  HwcLayer::LayerProperties properties;
+  properties.blend_mode = AidlToBlendMode(command.blendMode);
+  properties.color_space = AidlToColorSpace(command.dataspace);
+  properties.sample_range = AidlToSampleRange(command.dataspace);
+  properties.composition_type = AidlToCompositionType(command.composition);
+  properties.display_frame = AidlToRect(command.displayFrame);
+  properties.alpha = AidlToAlpha(command.planeAlpha);
+  properties.source_crop = AidlToFRect(command.sourceCrop);
+  properties.transform = AidlToLayerTransform(command.transform);
+  properties.z_order = AidlToZOrder(command.z);
+
+  layer->SetLayerProperties(properties);
 
   // Some unsupported functionality returns kUnsupported, and others
   // are just a no-op.
@@ -346,6 +553,9 @@
   if (command.sidebandStream) {
     cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
   }
+  if (command.luts) {
+    cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
+  }
   // TODO: Blocking region handling missing.
   // TODO: Layer surface damage.
   // TODO: Layer visible region.
@@ -473,7 +683,7 @@
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayAttribute(
-    int64_t display_id, int32_t config, DisplayAttribute attribute,
+    int64_t display_id, int32_t config_id, DisplayAttribute attribute,
     int32_t* value) {
   DEBUG_FUNC();
   const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
@@ -482,11 +692,46 @@
     return ToBinderStatus(hwc3::Error::kBadDisplay);
   }
 
-  const hwc3::Error error = Hwc2toHwc3Error(
-      display->GetDisplayAttribute(Hwc3ConfigIdToHwc2(config),
-                                   Hwc3DisplayAttributeToHwc2(attribute),
-                                   value));
-  return ToBinderStatus(error);
+  const HwcDisplayConfigs& configs = display->GetDisplayConfigs();
+  auto config = configs.hwc_configs.find(config_id);
+  if (config == configs.hwc_configs.end()) {
+    return ToBinderStatus(hwc3::Error::kBadConfig);
+  }
+
+  DisplayConfiguration
+      aidl_configuration = HwcDisplayConfigToAidlConfiguration(configs,
+                                                               config->second);
+  // Legacy API for querying DPI uses units of dots per 1000 inches.
+  static const int kLegacyDpiUnit = 1000;
+  switch (attribute) {
+    case DisplayAttribute::WIDTH:
+      *value = aidl_configuration.width;
+      break;
+    case DisplayAttribute::HEIGHT:
+      *value = aidl_configuration.height;
+      break;
+    case DisplayAttribute::VSYNC_PERIOD:
+      *value = aidl_configuration.vsyncPeriod;
+      break;
+    case DisplayAttribute::DPI_X:
+      *value = aidl_configuration.dpi
+                   ? static_cast<int>(aidl_configuration.dpi->x *
+                                      kLegacyDpiUnit)
+                   : -1;
+      break;
+    case DisplayAttribute::DPI_Y:
+      *value = aidl_configuration.dpi
+                   ? static_cast<int>(aidl_configuration.dpi->y *
+                                      kLegacyDpiUnit)
+                   : -1;
+      break;
+    case DisplayAttribute::CONFIG_GROUP:
+      *value = aidl_configuration.configGroup;
+      break;
+    case DisplayAttribute::INVALID:
+      return ToBinderStatus(hwc3::Error::kUnsupported);
+  }
+  return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(
@@ -520,7 +765,7 @@
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayConfigs(
-    int64_t display_id, std::vector<int32_t>* configs) {
+    int64_t display_id, std::vector<int32_t>* out_configs) {
   DEBUG_FUNC();
   const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
   HwcDisplay* display = GetDisplay(display_id);
@@ -528,23 +773,9 @@
     return ToBinderStatus(hwc3::Error::kBadDisplay);
   }
 
-  uint32_t num_configs = 0;
-  hwc3::Error error = Hwc2toHwc3Error(
-      display->LegacyGetDisplayConfigs(&num_configs, nullptr));
-  if (error != hwc3::Error::kNone) {
-    return ToBinderStatus(error);
-  }
-
-  std::vector<hwc2_config_t> out_configs(num_configs);
-  error = Hwc2toHwc3Error(
-      display->LegacyGetDisplayConfigs(&num_configs, out_configs.data()));
-  if (error != hwc3::Error::kNone) {
-    return ToBinderStatus(error);
-  }
-
-  configs->reserve(num_configs);
-  for (const auto config : out_configs) {
-    configs->emplace_back(Hwc2ConfigIdToHwc3(config));
+  const HwcDisplayConfigs& configs = display->GetDisplayConfigs();
+  for (const auto& [id, config] : configs.hwc_configs) {
+    out_configs->push_back(static_cast<int32_t>(id));
   }
   return ndk::ScopedAStatus::ok();
 }
@@ -744,24 +975,8 @@
     return ToBinderStatus(hwc3::Error::kBadDisplay);
   }
 
-  uint32_t out_num_supported_types = 0;
-  auto error = Hwc2toHwc3Error(
-      display->GetSupportedContentTypes(&out_num_supported_types, nullptr));
-  if (error != hwc3::Error::kNone) {
-    return ToBinderStatus(error);
-  }
-
-  std::vector<uint32_t> out_supported_types(out_num_supported_types);
-  error = Hwc2toHwc3Error(
-      display->GetSupportedContentTypes(&out_num_supported_types,
-                                        out_supported_types.data()));
-  if (error != hwc3::Error::kNone) {
-    return ToBinderStatus(error);
-  }
-
-  for (const auto type : out_supported_types) {
-    types->push_back(Hwc2ContentTypeToHwc3(type));
-  }
+  // Support for ContentType is not implemented.
+  types->clear();
   return ndk::ScopedAStatus::ok();
 }
 
@@ -885,8 +1100,10 @@
     return ToBinderStatus(hwc3::Error::kBadDisplay);
   }
 
-  auto error = display->SetContentType(Hwc3ContentTypeToHwc2(type));
-  return ToBinderStatus(Hwc2toHwc3Error(error));
+  if (type == ContentType::NONE) {
+    return ndk::ScopedAStatus::ok();
+  }
+  return ToBinderStatus(hwc3::Error::kUnsupported);
 }
 
 ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled(
@@ -972,26 +1189,8 @@
 
   const HwcDisplayConfigs& configs = display->GetDisplayConfigs();
   for (const auto& [id, config] : configs.hwc_configs) {
-    configurations->emplace_back(
-        DisplayConfiguration{.configId = static_cast<int32_t>(config.id),
-                             .width = config.mode.GetRawMode().hdisplay,
-                             .height = config.mode.GetRawMode().vdisplay,
-                             .configGroup = static_cast<int32_t>(
-                                 config.group_id),
-                             .vsyncPeriod = config.mode.GetVSyncPeriodNs()});
-
-    if (configs.mm_width != 0) {
-      // ideally this should be vdisplay/mm_heigth, however mm_height
-      // comes from edid parsing and is highly unreliable. Viewing the
-      // rarity of anisotropic displays, falling back to a single value
-      // for dpi yield more correct output.
-      static const float kMmPerInch = 25.4;
-      float dpi = float(config.mode.GetRawMode().hdisplay) * kMmPerInch /
-                  float(configs.mm_width);
-      configurations->back().dpi = {.x = dpi, .y = dpi};
-    }
-
-    // TODO: Populate vrrConfig.
+    configurations->push_back(
+        HwcDisplayConfigToAidlConfiguration(configs, config));
   }
   return ndk::ScopedAStatus::ok();
 }
@@ -1040,102 +1239,6 @@
   }
 }
 
-void ComposerClient::ExecuteSetLayerBlendMode(
-    int64_t /*display_id*/, HwcLayerWrapper& layer,
-    const ParcelableBlendMode& blend_mode) {
-  auto err = Hwc2toHwc3Error(layer.layer->SetLayerBlendMode(
-      Hwc3BlendModeToHwc2(blend_mode.blendMode)));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-
-void ComposerClient::ExecuteSetLayerComposition(
-    int64_t /*display_id*/, HwcLayerWrapper& layer,
-    const ParcelableComposition& composition) {
-  hwc3::Error error = hwc3::Error::kNone;
-  switch (composition.composition) {
-      // Unsupported composition types should set an error for the current
-      // DisplayCommand.
-    case Composition::DISPLAY_DECORATION:
-    case Composition::SIDEBAND:
-      error = hwc3::Error::kUnsupported;
-      break;
-    default:
-      error = Hwc2toHwc3Error(layer.layer->SetLayerCompositionType(
-          Hwc3CompositionToHwc2(composition.composition)));
-  }
-  if (error != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(error);
-  }
-}
-
-void ComposerClient::ExecuteSetLayerDataspace(
-    int64_t /*display_id*/, HwcLayerWrapper& layer,
-    const ParcelableDataspace& dataspace) {
-  auto err = Hwc2toHwc3Error(
-      layer.layer->SetLayerDataspace(Hwc3DataspaceToHwc2(dataspace.dataspace)));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-
-void ComposerClient::ExecuteSetLayerDisplayFrame(int64_t /*display_id*/,
-                                                 HwcLayerWrapper& layer,
-                                                 const common::Rect& rect) {
-  const hwc_rect_t hwc2_rect{rect.left, rect.top, rect.right, rect.bottom};
-  auto err = Hwc2toHwc3Error(layer.layer->SetLayerDisplayFrame(hwc2_rect));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-void ComposerClient::ExecuteSetLayerPlaneAlpha(int64_t /*display_id*/,
-                                               HwcLayerWrapper& layer,
-                                               const PlaneAlpha& plane_alpha) {
-  auto err = Hwc2toHwc3Error(
-      layer.layer->SetLayerPlaneAlpha(plane_alpha.alpha));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-
-void ComposerClient::ExecuteSetLayerSourceCrop(
-    int64_t /*display_id*/, HwcLayerWrapper& layer,
-    const common::FRect& source_crop) {
-  const hwc_frect_t rect{source_crop.left, source_crop.top, source_crop.right,
-                         source_crop.bottom};
-  auto err = Hwc2toHwc3Error(layer.layer->SetLayerSourceCrop(rect));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-void ComposerClient::ExecuteSetLayerTransform(
-    int64_t /*display_id*/, HwcLayerWrapper& layer,
-    const ParcelableTransform& transform) {
-  auto err = Hwc2toHwc3Error(
-      layer.layer->SetLayerTransform(Hwc3TransformToHwc2(transform.transform)));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-void ComposerClient::ExecuteSetLayerZOrder(int64_t /*display_id*/,
-                                           HwcLayerWrapper& layer,
-                                           const ZOrder& z_order) {
-  auto err = Hwc2toHwc3Error(layer.layer->SetLayerZOrder(z_order.z));
-  if (err != hwc3::Error::kNone) {
-    cmd_result_writer_->AddError(err);
-  }
-}
-
-void ComposerClient::ExecuteSetLayerBrightness(
-    int64_t /*display_id*/, HwcLayerWrapper& /*layer*/,
-    const LayerBrightness& brightness) {
-  if (std::signbit(brightness.brightness) ||
-      std::isnan(brightness.brightness)) {
-    cmd_result_writer_->AddError(hwc3::Error::kBadParameter);
-  }
-}
-
 void ComposerClient::ExecuteSetDisplayBrightness(
     uint64_t display_id, const DisplayBrightness& command) {
   auto* display = GetDisplay(display_id);
diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h
index f6362ad..5e4949e 100644
--- a/hwc3/ComposerClient.h
+++ b/hwc3/ComposerClient.h
@@ -160,24 +160,6 @@
   void DispatchLayerCommand(int64_t display_id, const LayerCommand& command);
   void ExecuteSetLayerBuffer(int64_t display_id, HwcLayerWrapper& layer_id,
                              const Buffer& buffer);
-  void ExecuteSetLayerBlendMode(int64_t display_id, HwcLayerWrapper& layer,
-                                const ParcelableBlendMode& blend_mode);
-  void ExecuteSetLayerComposition(int64_t display_id, HwcLayerWrapper& layer,
-                                  const ParcelableComposition& composition);
-  void ExecuteSetLayerDataspace(int64_t display_id, HwcLayerWrapper& layer,
-                                const ParcelableDataspace& dataspace);
-  void ExecuteSetLayerDisplayFrame(int64_t display_id, HwcLayerWrapper& layer,
-                                   const common::Rect& rect);
-  void ExecuteSetLayerPlaneAlpha(int64_t display_id, HwcLayerWrapper& layer,
-                                 const PlaneAlpha& plane_alpha);
-  void ExecuteSetLayerSourceCrop(int64_t display_id, HwcLayerWrapper& layer,
-                                 const common::FRect& source_crop);
-  void ExecuteSetLayerTransform(int64_t display_id, HwcLayerWrapper& layer,
-                                const ParcelableTransform& transform);
-  void ExecuteSetLayerZOrder(int64_t display_id, HwcLayerWrapper& layer,
-                             const ZOrder& z_order);
-  void ExecuteSetLayerBrightness(int64_t display_id, HwcLayerWrapper& layer,
-                                 const LayerBrightness& brightness);
 
   // Display commands
   void ExecuteDisplayCommand(const DisplayCommand& command);
diff --git a/hwc3/DrmHwcThree.cpp b/hwc3/DrmHwcThree.cpp
index d758865..2ac307c 100644
--- a/hwc3/DrmHwcThree.cpp
+++ b/hwc3/DrmHwcThree.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "drmhwc"
+
 #include "DrmHwcThree.h"
 
 #include <cinttypes>
@@ -59,10 +61,22 @@
                               static_cast<int32_t>(vsync_period));
 }
 
-void DrmHwcThree::SendHotplugEventToClient(hwc2_display_t display_id,
-                                           bool connected) {
-  HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), connected);
-  common::DisplayHotplugEvent event = connected ? common::DisplayHotplugEvent::CONNECTED : common::DisplayHotplugEvent::DISCONNECTED;
+void DrmHwcThree::SendHotplugEventToClient(
+    hwc2_display_t display_id, DrmHwc::DisplayStatus display_status) {
+  common::DisplayHotplugEvent event = common::DisplayHotplugEvent::DISCONNECTED;
+  switch (display_status) {
+    case DrmHwc::kDisconnected:
+      event = common::DisplayHotplugEvent::DISCONNECTED;
+      HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), false);
+      break;
+    case DrmHwc::kConnected:
+      event = common::DisplayHotplugEvent::CONNECTED;
+      HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), true);
+      break;
+    case DrmHwc::kLinkTrainingFailed:
+      event = common::DisplayHotplugEvent::ERROR_INCOMPATIBLE_CABLE;
+      break;
+  }
   composer_callback_->onHotplugEvent(static_cast<int64_t>(display_id), event);
 }
 
diff --git a/hwc3/DrmHwcThree.h b/hwc3/DrmHwcThree.h
index 8ba96c6..f020634 100644
--- a/hwc3/DrmHwcThree.h
+++ b/hwc3/DrmHwcThree.h
@@ -39,7 +39,7 @@
       hwc2_display_t display_id, int64_t timestamp) const override;
   void SendRefreshEventToClient(uint64_t display_id) override;
   void SendHotplugEventToClient(hwc2_display_t display_id,
-                                bool connected) override;
+                                DrmHwc::DisplayStatus display_status) override;
 
  private:
   void CleanDisplayResources(uint64_t display_id);
diff --git a/hwc3/Utils.h b/hwc3/Utils.h
index 2e21b97..b322f5d 100644
--- a/hwc3/Utils.h
+++ b/hwc3/Utils.h
@@ -94,13 +94,6 @@
   return static_cast<Composition>(composition_type);
 }
 
-inline int32_t Hwc3CompositionToHwc2(Composition composition_type) {
-  if (composition_type > Composition::SIDEBAND) {
-    return HWC2_COMPOSITION_INVALID;
-  }
-  return static_cast<int32_t>(composition_type);
-}
-
 // Values for color modes match across HWC versions, so static cast is safe:
 // https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/ColorMode.aidl
 // https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=118
@@ -153,27 +146,6 @@
   return static_cast<int32_t>(render_intent);
 }
 
-// Content type matches, so static_cast is safe.
-// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/ContentType.aidl
-// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=350;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e
-inline ContentType Hwc2ContentTypeToHwc3(uint32_t content_type) {
-  if (content_type > HWC2_CONTENT_TYPE_GAME) {
-    ALOGE("Unknown HWC2 content type. Could not translate: %d", content_type);
-    return ContentType::NONE;
-  }
-  return static_cast<ContentType>(content_type);
-}
-inline int32_t Hwc3ContentTypeToHwc2(ContentType content_type) {
-  return static_cast<int32_t>(content_type);
-}
-
-// Values match, so it's safe to do static_cast.
-// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayAttribute.aidl
-// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=58;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24
-inline int32_t Hwc3DisplayAttributeToHwc2(DisplayAttribute display_attribute) {
-  return static_cast<int32_t>(display_attribute);
-}
-
 // Values match up to DOZE_SUSPEND.
 // https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/PowerMode.aidl
 // https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=348;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24
@@ -185,13 +157,6 @@
   return static_cast<int32_t>(power_mode);
 }
 
-// Values match, so static_cast is okay.
-// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl;drc=bab1ba54ede32520a5042d616a3af46ad4f55d5f;l=25
-// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=72;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e
-inline int32_t Hwc3BlendModeToHwc2(common::BlendMode blend_mode) {
-  return static_cast<int32_t>(blend_mode);
-}
-
 // Values appear to match.
 // https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
 // https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=43
@@ -200,11 +165,4 @@
   return static_cast<int32_t>(dataspace);
 }
 
-// Values match, so static_cast is okay.
-// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
-// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=41
-inline int32_t Hwc3TransformToHwc2(common::Transform transform) {
-  return static_cast<int32_t>(transform);
-}
-
 };  // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/hwc3-drm.xml b/hwc3/hwc3-drm.xml
index 911f7f8..7debcf9 100644
--- a/hwc3/hwc3-drm.xml
+++ b/hwc3/hwc3-drm.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>