hwc2: power mode support

Allow client to set power mode to on or off. Doze modes are not currently
supported.

Test: Add "TARGET_USES_HWC2 := true" to BoardConfig.mk.
      Recompile.
      Run testcases: https://android-review.googlesource.com/#/q/project:
            platform/frameworks/native+branch:master+topic:test-hwc2

Change-Id: Ia4d579b28ac725975248eacd82685155ae7b0d91
diff --git a/hwc2/hwc2.cpp b/hwc2/hwc2.cpp
index 1693132..a70833a 100644
--- a/hwc2/hwc2.cpp
+++ b/hwc2/hwc2.cpp
@@ -159,10 +159,11 @@
     return dev->get_display_type(display, out_type);
 }
 
-hwc2_error_t get_doze_support(hwc2_device_t* /*device*/,
-        hwc2_display_t /*display*/, int32_t* /*out_support*/)
+hwc2_error_t get_doze_support(hwc2_device_t *device, hwc2_display_t display,
+        int32_t *out_support)
 {
-    return HWC2_ERROR_NONE;
+    hwc2_dev *dev = reinterpret_cast<hwc2_context *>(device)->hwc2_dev;
+    return dev->get_doze_support(display, out_support);
 }
 
 hwc2_error_t get_hdr_capabilities(hwc2_device_t* /*device*/,
@@ -221,10 +222,11 @@
     return HWC2_ERROR_NONE;
 }
 
-hwc2_error_t set_power_mode(hwc2_device_t* /*device*/,
-        hwc2_display_t /*display*/, hwc2_power_mode_t /*mode*/)
+hwc2_error_t set_power_mode(hwc2_device_t *device, hwc2_display_t display,
+        hwc2_power_mode_t mode)
 {
-    return HWC2_ERROR_NONE;
+    hwc2_dev *dev = reinterpret_cast<hwc2_context *>(device)->hwc2_dev;
+    return dev->set_power_mode(display, mode);
 }
 
 hwc2_error_t set_vsync_enabled(hwc2_device_t* /*device*/,
diff --git a/hwc2/hwc2.h b/hwc2/hwc2.h
index 70c6f61..44e8a82 100644
--- a/hwc2/hwc2.h
+++ b/hwc2/hwc2.h
@@ -95,7 +95,7 @@
 public:
     hwc2_display(hwc2_display_t id, int adf_intf_fd,
                 const struct adf_device &adf_dev, hwc2_connection_t connection,
-                hwc2_display_type_t type);
+                hwc2_display_type_t type, hwc2_power_mode_t power_mode);
     ~hwc2_display();
 
     hwc2_display_t get_id() const { return id; }
@@ -104,6 +104,10 @@
 
     hwc2_error_t set_connection(hwc2_connection_t connection);
 
+    /* Power modes */
+    hwc2_error_t set_power_mode(hwc2_power_mode_t mode);
+    hwc2_error_t get_doze_support(int32_t *out_support) const;
+
     /* Config functions */
     int          retrieve_display_configs(struct adf_hwc_helper *adf_helper);
     hwc2_error_t get_display_attribute(hwc2_config_t config,
@@ -141,6 +145,9 @@
     /* The id of the current active configuration of the display */
     hwc2_config_t active_config;
 
+    /* The current power mode of the display */
+    hwc2_power_mode_t power_mode;
+
     /* The adf interface file descriptor for the display */
     int adf_intf_fd;
 
@@ -160,6 +167,11 @@
     hwc2_error_t get_display_type(hwc2_display_t dpy_id,
                     hwc2_display_type_t *out_type) const;
 
+    /* Power modes */
+    hwc2_error_t set_power_mode(hwc2_display_t dpy_id, hwc2_power_mode_t mode);
+    hwc2_error_t get_doze_support(hwc2_display_t dpy_id, int32_t *out_support)
+                    const;
+
     /* Config functions */
     hwc2_error_t get_display_attribute(hwc2_display_t dpy_id,
                     hwc2_config_t config, hwc2_attribute_t attribute,
diff --git a/hwc2/hwc2_dev.cpp b/hwc2/hwc2_dev.cpp
index 156fc13..28b365e 100644
--- a/hwc2/hwc2_dev.cpp
+++ b/hwc2/hwc2_dev.cpp
@@ -72,6 +72,30 @@
     return HWC2_ERROR_NONE;
 }
 
+hwc2_error_t hwc2_dev::set_power_mode(hwc2_display_t dpy_id,
+        hwc2_power_mode_t mode)
+{
+    auto it = displays.find(dpy_id);
+    if (it == displays.end()) {
+        ALOGE("dpy %" PRIu64 ": invalid display handle", dpy_id);
+        return HWC2_ERROR_BAD_DISPLAY;
+    }
+
+    return it->second.set_power_mode(mode);
+}
+
+hwc2_error_t hwc2_dev::get_doze_support(hwc2_display_t dpy_id,
+        int32_t *out_support) const
+{
+    auto it = displays.find(dpy_id);
+    if (it == displays.end()) {
+        ALOGE("dpy %" PRIu64 ": invalid display handle", dpy_id);
+        return HWC2_ERROR_BAD_DISPLAY;
+    }
+
+    return it->second.get_doze_support(out_support);
+}
+
 hwc2_error_t hwc2_dev::get_display_attribute(hwc2_display_t dpy_id,
         hwc2_config_t config, hwc2_attribute_t attribute, int32_t *out_value)
         const
@@ -257,7 +281,8 @@
     displays.emplace(std::piecewise_construct, std::forward_as_tuple(dpy_id),
             std::forward_as_tuple(dpy_id, intf_fd, adf_dev,
             (intf.hotplug_detect)? HWC2_CONNECTION_CONNECTED:
-            HWC2_CONNECTION_DISCONNECTED, HWC2_DISPLAY_TYPE_PHYSICAL));
+            HWC2_CONNECTION_DISCONNECTED, HWC2_DISPLAY_TYPE_PHYSICAL,
+            (intf.hotplug_detect)? HWC2_POWER_MODE_ON: HWC2_POWER_MODE_OFF));
 
     adf_free_interface_data(&intf);
 
diff --git a/hwc2/hwc2_display.cpp b/hwc2/hwc2_display.cpp
index 137e08a..90d8048 100644
--- a/hwc2/hwc2_display.cpp
+++ b/hwc2/hwc2_display.cpp
@@ -26,13 +26,14 @@
 
 hwc2_display::hwc2_display(hwc2_display_t id, int adf_intf_fd,
         const struct adf_device &adf_dev, hwc2_connection_t connection,
-        hwc2_display_type_t type)
+        hwc2_display_type_t type, hwc2_power_mode_t power_mode)
     : id(id),
       connection(connection),
       type(type),
       layers(),
       configs(),
       active_config(0),
+      power_mode(power_mode),
       adf_intf_fd(adf_intf_fd),
       adf_dev(adf_dev) { }
 
@@ -53,6 +54,38 @@
     return HWC2_ERROR_NONE;
 }
 
+hwc2_error_t hwc2_display::set_power_mode(hwc2_power_mode_t mode)
+{
+    int drm_mode;
+
+    switch (mode) {
+    case HWC2_POWER_MODE_ON:
+        drm_mode = DRM_MODE_DPMS_ON;
+        break;
+    case HWC2_POWER_MODE_OFF:
+        drm_mode = DRM_MODE_DPMS_OFF;
+        break;
+    case HWC2_POWER_MODE_DOZE:
+    case HWC2_POWER_MODE_DOZE_SUSPEND:
+        ALOGE("dpy %" PRIu64 ": unsupported power mode: %u", id, mode);
+        return HWC2_ERROR_UNSUPPORTED;
+    default:
+        ALOGE("dpy %" PRIu64 ": invalid power mode: %u", id, mode);
+        return HWC2_ERROR_BAD_PARAMETER;
+    }
+
+    adf_interface_blank(adf_intf_fd, drm_mode);
+    power_mode = mode;
+
+    return HWC2_ERROR_NONE;
+}
+
+hwc2_error_t hwc2_display::get_doze_support(int32_t *out_support) const
+{
+    *out_support = 0;
+    return HWC2_ERROR_NONE;
+}
+
 int hwc2_display::retrieve_display_configs(struct adf_hwc_helper *adf_helper)
 {
     size_t num_configs = 0;