sdm: Implement SetDisplayBrightness, GetDisplayBrightness.

Change-Id: Ica0f0bbb2955ad26fa113728ee152a21e6014b6c
CRs-Fixed: 2454377
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 03c8e0e..918a7fe 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017 - 2020, 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
@@ -606,6 +606,7 @@
   uint32_t mmWidth;
   uint32_t mmHeight;
   uint32_t type;
+  uint32_t type_id;
   std::vector<DRMModeInfo> modes;
   std::string panel_name;
   DRMPanelMode panel_mode;
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 43aa2d8..080afcb 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2020, 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:
@@ -537,13 +537,13 @@
   */
   virtual bool IsUnderscanSupported() = 0;
 
-  /*! @brief Method to set brightness of the primary display.
+  /*! @brief Method to set brightness of the builtin display.
 
-    @param[in] level the new backlight level.
+    @param[in] brightness the new backlight level 0.0f(min) to 1.0f(max) where -1.0f represents off.
 
     @return \link DisplayError \endlink
   */
-  virtual DisplayError SetPanelBrightness(int level) = 0;
+  virtual DisplayError SetPanelBrightness(float brightness) = 0;
 
   /*! @brief Method to notify display about change in min HDCP encryption level.
 
@@ -646,11 +646,11 @@
 
   /*! @brief Method to get the brightness level of the display
 
-    @param[out] level brightness level
+    @param[out] brightness brightness percentage
 
     @return \link DisplayError \endlink
   */
-  virtual DisplayError GetPanelBrightness(int *level) = 0;
+  virtual DisplayError GetPanelBrightness(float *brightness) = 0;
 
   /*! @brief Method to set layer mixer resolution.
 
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index 04237a8..835b1a7 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2020, 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
@@ -185,7 +185,6 @@
 struct PPHWAttributes : HWResourceInfo, HWPanelInfo, DisplayConfigVariableInfo {
   char panel_name[256] = "generic_panel";
   PPFeatureVersion version;
-  int panel_max_brightness = 0;
 
   void Set(const HWResourceInfo &hw_res, const HWPanelInfo &panel_info,
            const DisplayConfigVariableInfo &attr, const PPFeatureVersion &feature_ver);
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 1192875..240b1c4 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015-2020, 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:
@@ -396,7 +396,8 @@
   HWSplitInfo split_info;             // Panel split configuration
   char panel_name[256] = {0};         // Panel name
   HWS3DMode s3d_mode = kS3DModeNone;  // Panel's current s3d mode.
-  int panel_max_brightness = 0;       // Max panel brightness
+  float panel_max_brightness = 255.0f;  // Max panel brightness
+  float panel_min_brightness = 1.0f;  // Min panel brightness
   uint32_t left_roi_count = 1;        // Number if ROI supported on left panel
   uint32_t right_roi_count = 1;       // Number if ROI supported on right panel
   bool hdr_enabled = false;           // HDR feature supported
diff --git a/sdm/libs/core/color_manager.cpp b/sdm/libs/core/color_manager.cpp
index fe42556..27f7eab 100644
--- a/sdm/libs/core/color_manager.cpp
+++ b/sdm/libs/core/color_manager.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015 - 2019, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015 - 2020, 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
@@ -203,7 +203,6 @@
   DisplayConfigVariableInfo &attributes = *this;
   attributes = attr;
   version = feature_ver;
-  panel_max_brightness = panel_info.panel_max_brightness;
 
   if (strlen(panel_info.panel_name)) {
     snprintf(&panel_name[0], sizeof(panel_name), "%s", &panel_info.panel_name[0]);
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 9981e77..4ca6254 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2020, 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:
@@ -85,7 +85,7 @@
   virtual bool IsUnderscanSupported() {
     return false;
   }
-  virtual DisplayError SetPanelBrightness(int level) {
+  virtual DisplayError SetPanelBrightness(float brightness) {
     return kErrorNotSupported;
   }
   virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
@@ -116,7 +116,7 @@
   virtual DisplayError GetDefaultColorMode(std::string *color_mode);
   virtual DisplayError SetCursorPosition(int x, int y);
   virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate);
-  virtual DisplayError GetPanelBrightness(int *level) {
+  virtual DisplayError GetPanelBrightness(float *brightness) {
     return kErrorNotSupported;
   }
   virtual DisplayError SetVSyncState(bool enable);
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index eaed45b..328364c 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2020, 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:
@@ -346,9 +346,39 @@
   return error;
 }
 
-DisplayError DisplayBuiltIn::SetPanelBrightness(int level) {
+DisplayError DisplayBuiltIn::SetPanelBrightness(float brightness) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
-  return hw_intf_->SetPanelBrightness(level);
+
+  if (brightness != -1.0f && !(0.0f <= brightness && brightness <= 1.0f)) {
+    DLOGE("Bad brightness value = %f", brightness);
+    return kErrorParameters;
+  }
+
+  // -1.0f = off, 0.0f = min, 1.0f = max
+  level_remainder_ = 0.0f;
+  int level = 0;
+  if (brightness == -1.0f) {
+    level = 0;
+  } else {
+    // Node only supports int level, so store the float remainder for accurate GetPanelBrightness
+    float max = hw_panel_info_.panel_max_brightness;
+    float min = hw_panel_info_.panel_min_brightness;
+    if (min >= max) {
+      DLOGE("Minimum brightness is greater than or equal to maximum brightness");
+      return kErrorDriverData;
+    }
+    float t = (brightness * (max - min)) + min;
+    level = static_cast<int>(t);
+    level_remainder_ = t - level;
+  }
+
+  DisplayError err = kErrorNone;
+  if ((err = hw_intf_->SetPanelBrightness(level)) == kErrorNone) {
+    DLOGI_IF(kTagDisplay, "Setting brightness to level %d (%f percent)", level,
+             brightness * 100);
+  }
+
+  return err;
 }
 
 DisplayError DisplayBuiltIn::GetRefreshRateRange(uint32_t *min_refresh_rate,
@@ -461,9 +491,32 @@
   DisplayBase::HwRecovery(sdm_event_code);
 }
 
-DisplayError DisplayBuiltIn::GetPanelBrightness(int *level) {
+DisplayError DisplayBuiltIn::GetPanelBrightness(float *brightness) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
-  return hw_intf_->GetPanelBrightness(level);
+
+  DisplayError err = kErrorNone;
+  int level = 0;
+  if ((err = hw_intf_->GetPanelBrightness(&level)) != kErrorNone) {
+    return err;
+  }
+
+  // -1.0f = off, 0.0f = min, 1.0f = max
+  float max = hw_panel_info_.panel_max_brightness;
+  float min = hw_panel_info_.panel_min_brightness;
+  if (level == 0) {
+    *brightness = -1.0f;
+  } else if ((max > min) && (min <= level && level <= max)) {
+    *brightness = (static_cast<float>(level) + level_remainder_ - min) / (max - min);
+  } else {
+    min >= max ? DLOGE("Minimum brightness is greater than or equal to maximum brightness") :
+                 DLOGE("Invalid brightness level %d", level);
+    return kErrorDriverData;
+  }
+
+
+  DLOGI_IF(kTagDisplay, "Received level %d (%f percent)", level, *brightness * 100);
+
+  return kErrorNone;
 }
 
 DisplayError DisplayBuiltIn::ControlPartialUpdate(bool enable, uint32_t *pending) {
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index 6dd8305..fde57e1 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2020, 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:
@@ -111,8 +111,8 @@
   virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate);
   virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate);
   virtual DisplayError GetRefreshRate(uint32_t *refresh_rate);
-  virtual DisplayError SetPanelBrightness(int level);
-  virtual DisplayError GetPanelBrightness(int *level);
+  virtual DisplayError SetPanelBrightness(float brightness);
+  virtual DisplayError GetPanelBrightness(float *brightness);
   virtual DisplayError HandleSecureEvent(SecureEvent secure_event, LayerStack *layer_stack);
   virtual DisplayError SetDisplayDppsAdROI(void *payload);
   virtual DisplayError SetQSyncMode(QSyncMode qsync_mode);
@@ -157,6 +157,7 @@
   bool first_cycle_ = true;
   int previous_retire_fence_ = -1;
   DeferFpsConfig deferred_config_ = {};
+  float level_remainder_ = 0.0f;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 133d0c3..95d5845 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2020, 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
@@ -803,27 +803,6 @@
   return;
 }
 
-void HWDeviceDRM::GetHWPanelMaxBrightness() {
-  char brightness[kMaxStringLength] = {0};
-  string kMaxBrightnessNode = "/sys/class/backlight/panel0-backlight/max_brightness";
-
-  hw_panel_info_.panel_max_brightness = 255;
-  int fd = Sys::open_(kMaxBrightnessNode.c_str(), O_RDONLY);
-  if (fd < 0) {
-    DLOGW("Failed to open max brightness node = %s, error = %s", kMaxBrightnessNode.c_str(),
-          strerror(errno));
-    return;
-  }
-
-  if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
-    hw_panel_info_.panel_max_brightness = atoi(brightness);
-    DLOGI_IF(kTagDisplay, "Max brightness level = %d", hw_panel_info_.panel_max_brightness);
-  } else {
-    DLOGW("Failed to read max brightness level. error = %s", strerror(errno));
-  }
-
-  Sys::close_(fd);
-}
 
 DisplayError HWDeviceDRM::GetActiveConfig(uint32_t *active_config) {
   *active_config = current_mode_index_;
@@ -1710,59 +1689,7 @@
   return kErrorNotSupported;
 }
 
-DisplayError HWDeviceDRM::SetPanelBrightness(int level) {
-  DisplayError err = kErrorNone;
-  char buffer[kMaxSysfsCommandLength] = {0};
 
-  DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level);
-  int fd = Sys::open_(kBrightnessNode, O_RDWR);
-  if (fd < 0) {
-    DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode,
-             strerror(errno));
-    return kErrorFileDescriptor;
-  }
-
-  int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level);
-  ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
-  if (ret <= 0) {
-    DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode,
-             strerror(errno));
-    err = kErrorHardware;
-  }
-
-  Sys::close_(fd);
-
-  return err;
-}
-
-DisplayError HWDeviceDRM::GetPanelBrightness(int *level) {
-  DisplayError err = kErrorNone;
-  char brightness[kMaxStringLength] = {0};
-
-  if (!level) {
-    DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer.");
-    return kErrorParameters;
-  }
-
-  int fd = Sys::open_(kBrightnessNode, O_RDWR);
-  if (fd < 0) {
-    DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode,
-             strerror(errno));
-    return kErrorFileDescriptor;
-  }
-
-  if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
-    *level = atoi(brightness);
-    DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level);
-  } else {
-    DLOGV_IF(kTagDriverConfig, "Failed to read panel brightness");
-    err = kErrorHardware;
-  }
-
-  Sys::close_(fd);
-
-  return err;
-}
 
 DisplayError HWDeviceDRM::GetHWScanInfo(HWScanInfo *scan_info) {
   return kErrorNotSupported;
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 747e51e..fe3dbc1 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2020, 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
@@ -96,13 +96,14 @@
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
   virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode);
   virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
-  virtual DisplayError SetPanelBrightness(int level);
+  virtual DisplayError SetPanelBrightness(int level) { return kErrorNotSupported; }
   virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info);
   virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format);
   virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format);
   virtual DisplayError SetCursorPosition(HWLayers *hw_layers, int x, int y);
   virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
-  virtual DisplayError GetPanelBrightness(int *level);
+  virtual DisplayError GetPanelBrightness(int *level) { return kErrorNotSupported; }
+  virtual void GetHWPanelMaxBrightness() { return; }
   virtual DisplayError SetAutoRefresh(bool enable) { autorefresh_ = enable; return kErrorNone; }
   virtual DisplayError SetS3DMode(HWS3DMode s3d_mode);
   virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info);
@@ -135,15 +136,12 @@
   static const int kMaxStringLength = 1024;
   static const int kNumPhysicalDisplays = 2;
   static const int kMaxSysfsCommandLength = 12;
-  static constexpr const char *kBrightnessNode =
-    "/sys/class/backlight/panel0-backlight/brightness";
 
   DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target);
   DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format, uint32_t width,
                          uint32_t *target);
   DisplayError PopulateDisplayAttributes(uint32_t index);
   void GetHWDisplayPortAndMode();
-  void GetHWPanelMaxBrightness();
   bool EnableHotPlugDetection(int enable);
   void UpdateMixerAttributes();
   void SetSolidfillStages();
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
index c974c09..e0ebad4 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.cpp
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+Copyright (c) 2017-2020, 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
@@ -27,8 +27,11 @@
 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+#include <fcntl.h>
 #include <utils/debug.h>
+#include <utils/sys.h>
 #include <vector>
+#include <string>
 #include <cstring>
 #include <algorithm>
 
@@ -488,4 +491,96 @@
   return err;
 }
 
+DisplayError HWPeripheralDRM::SetPanelBrightness(int level) {
+  char buffer[kMaxSysfsCommandLength] = {0};
+
+  if (brightness_base_path_.empty()) {
+    return kErrorHardware;
+  }
+
+  std::string brightness_node(brightness_base_path_ + "brightness");
+  int fd = Sys::open_(brightness_node.c_str(), O_RDWR);
+  if (fd < 0) {
+    DLOGE("Failed to open node = %s, error = %s ", brightness_node.c_str(),
+          strerror(errno));
+    return kErrorFileDescriptor;
+  }
+
+  int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level);
+  ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
+  if (ret <= 0) {
+    DLOGE("Failed to write to node = %s, error = %s ", brightness_node.c_str(),
+          strerror(errno));
+    Sys::close_(fd);
+    return kErrorHardware;
+  }
+
+  Sys::close_(fd);
+
+  return kErrorNone;
+}
+
+DisplayError HWPeripheralDRM::GetPanelBrightness(int *level) {
+  char value[kMaxStringLength] = {0};
+
+  if (!level) {
+    DLOGE("Invalid input, null pointer.");
+    return kErrorParameters;
+  }
+
+  if (brightness_base_path_.empty()) {
+    return kErrorHardware;
+  }
+
+  std::string brightness_node(brightness_base_path_ + "brightness");
+  int fd = Sys::open_(brightness_node.c_str(), O_RDWR);
+  if (fd < 0) {
+    DLOGE("Failed to open brightness node = %s, error = %s", brightness_node.c_str(),
+           strerror(errno));
+    return kErrorFileDescriptor;
+  }
+
+  if (Sys::pread_(fd, value, sizeof(value), 0) > 0) {
+    *level = atoi(value);
+  } else {
+    DLOGE("Failed to read panel brightness");
+    Sys::close_(fd);
+    return kErrorHardware;
+  }
+
+  Sys::close_(fd);
+
+  return kErrorNone;
+}
+
+void HWPeripheralDRM::GetHWPanelMaxBrightness() {
+  char value[kMaxStringLength] = {0};
+  hw_panel_info_.panel_max_brightness = 255.0f;
+
+  // Panel nodes, driver connector creation, and DSI probing all occur in sync, for each DSI. This
+  // means that the connector_type_id - 1 will reflect the same # as the panel # for panel node.
+  char s[kMaxStringLength] = {};
+  snprintf(s, sizeof(s), "/sys/class/backlight/panel%d-backlight/",
+           static_cast<int>(connector_info_.type_id - 1));
+  brightness_base_path_.assign(s);
+
+  std::string brightness_node(brightness_base_path_ + "max_brightness");
+  int fd = Sys::open_(brightness_node.c_str(), O_RDONLY);
+  if (fd < 0) {
+    DLOGE("Failed to open max brightness node = %s, error = %s", brightness_node.c_str(),
+          strerror(errno));
+    return;
+  }
+
+  if (Sys::pread_(fd, value, sizeof(value), 0) > 0) {
+    hw_panel_info_.panel_max_brightness = static_cast<float>(atof(value));
+    DLOGI_IF(kTagDriverConfig, "Max brightness = %f", hw_panel_info_.panel_max_brightness);
+  } else {
+    DLOGE("Failed to read max brightness. error = %s", strerror(errno));
+  }
+
+  Sys::close_(fd);
+  return;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.h b/sdm/libs/core/drm/hw_peripheral_drm.h
index 518657d..5df95dd 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.h
+++ b/sdm/libs/core/drm/hw_peripheral_drm.h
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+Copyright (c) 2017-2018, 2020, 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
@@ -31,6 +31,7 @@
 #define __HW_PERIPHERAL_DRM_H__
 
 #include <vector>
+#include <string>
 #include "hw_device_drm.h"
 
 namespace sdm {
@@ -61,6 +62,9 @@
   virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
   virtual DisplayError SetDisplayAttributes(uint32_t index);
   virtual DisplayError TeardownConcurrentWriteback(void);
+  virtual DisplayError SetPanelBrightness(int level);
+  virtual DisplayError GetPanelBrightness(int *level);
+  virtual void GetHWPanelMaxBrightness();
 
  private:
   void SetDestScalarData(HWLayersInfo hw_layer_info, bool validate);
@@ -88,6 +92,7 @@
   bool needs_ds_update_ = false;
   void PopulateBitClkRates();
   std::vector<uint64_t> bitclk_rates_;
+  std::string brightness_base_path_ = "";
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
index 926e03a..5ae8d8c 100644
--- a/sdm/libs/hwc2/display_null.h
+++ b/sdm/libs/hwc2/display_null.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2020, 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
@@ -77,7 +77,7 @@
   MAKE_NO_OP(ControlPartialUpdate(bool, uint32_t *))
   MAKE_NO_OP(DisablePartialUpdateOneFrame())
   MAKE_NO_OP(SetDisplayMode(uint32_t))
-  MAKE_NO_OP(SetPanelBrightness(int))
+  MAKE_NO_OP(SetPanelBrightness(float))
   MAKE_NO_OP(CachePanelBrightness(int))
   MAKE_NO_OP(OnMinHdcpEncryptionLevelChange(uint32_t))
   MAKE_NO_OP(ColorSVCRequestRoute(const PPDisplayAPIPayload &, PPDisplayAPIPayload *,
@@ -93,7 +93,7 @@
   MAKE_NO_OP(SetCursorPosition(int, int))
   MAKE_NO_OP(SetRefreshRate(uint32_t, bool))
   MAKE_NO_OP(GetRefreshRate(uint32_t *))
-  MAKE_NO_OP(GetPanelBrightness(int *))
+  MAKE_NO_OP(GetPanelBrightness(float *))
   MAKE_NO_OP(SetVSyncState(bool))
   MAKE_NO_OP(SetMixerResolution(uint32_t, uint32_t))
   MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &))
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index c33fc61..6531f98 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1985,22 +1985,6 @@
 void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) {
 }
 
-int HWCDisplay::SetPanelBrightness(int level) {
-  int ret = 0;
-  if (display_intf_) {
-    ret = display_intf_->SetPanelBrightness(level);
-    validated_ = false;
-  } else {
-    ret = -EINVAL;
-  }
-
-  return ret;
-}
-
-int HWCDisplay::GetPanelBrightness(int *level) {
-  return display_intf_->GetPanelBrightness(level);
-}
-
 int HWCDisplay::ToggleScreenUpdates(bool enable) {
   display_paused_ = enable ? false : true;
   callbacks_->Refresh(id_);
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 54a2c8a..e3eae09 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -212,8 +212,6 @@
   }
 
   uint32_t GetMaxRefreshRate() { return max_refresh_rate_; }
-  int SetPanelBrightness(int level);
-  int GetPanelBrightness(int *level);
   int ToggleScreenUpdates(bool enable);
   int ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, PPDisplayAPIPayload *out_payload,
                            PPPendingParams *pending_action);
@@ -289,6 +287,12 @@
   virtual HWC2::Error SetPendingRefresh() {
     return HWC2::Error::Unsupported;
   }
+  virtual HWC2::Error SetPanelBrightness(float brightness) {
+    return HWC2::Error::Unsupported;
+  }
+  virtual HWC2::Error GetPanelBrightness(float *brightness) {
+    return HWC2::Error::Unsupported;
+  }
   virtual HWC2::Error GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs);
   virtual HWC2::Error GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                           int32_t *out_value);
diff --git a/sdm/libs/hwc2/hwc_display_builtin.cpp b/sdm/libs/hwc2/hwc_display_builtin.cpp
index 43f4740..c85b772 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.cpp
+++ b/sdm/libs/hwc2/hwc_display_builtin.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2020, 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
@@ -977,4 +977,21 @@
   return HWCDisplay::PostCommitLayerStack(out_retire_fence);
 }
 
+HWC2::Error HWCDisplayBuiltIn::SetPanelBrightness(float brightness) {
+  DisplayError ret = display_intf_->SetPanelBrightness(brightness);
+  if (ret != kErrorNone) {
+    return HWC2::Error::NoResources;
+  }
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCDisplayBuiltIn::GetPanelBrightness(float *brightness) {
+  DisplayError ret = display_intf_->GetPanelBrightness(brightness);
+  if (ret != kErrorNone) {
+    return HWC2::Error::NoResources;
+  }
+
+  return HWC2::Error::None;
+}
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_builtin.h b/sdm/libs/hwc2/hwc_display_builtin.h
index eeeb9c3..1ec970a 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.h
+++ b/sdm/libs/hwc2/hwc_display_builtin.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020, 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
@@ -91,6 +91,8 @@
   virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates);
   virtual HWC2::Error UpdateDisplayId(hwc2_display_t id);
   virtual HWC2::Error SetPendingRefresh();
+  virtual HWC2::Error SetPanelBrightness(float brightness);
+  virtual HWC2::Error GetPanelBrightness(float *brightness);
   virtual DisplayError TeardownConcurrentWriteback(void);
   virtual void SetFastPathComposition(bool enable) {
     fast_path_composition_ = enable && !readback_buffer_queued_;
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 8663705..d1653ee 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -1310,7 +1310,7 @@
     case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport:
       return AsFP<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(HWCSession::GetDisplayBrightnessSupport);
     case HWC2::FunctionDescriptor::SetDisplayBrightness:
-      return AsFP<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(SetDisplayBrightness);
+      return AsFP<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(HWCSession::SetDisplayBrightness);
     default:
       DLOGD("Unknown/Unimplemented function descriptor: %d (%s)", int_descriptor,
             to_string(descriptor).c_str());
@@ -1580,9 +1580,14 @@
           DLOGE("QService command = %d: output_parcel needed.", command);
           break;
         }
-        int level = 0;
-        status = GetPanelBrightness(&level);
-        output_parcel->writeInt32(level);
+        float brightness = -1.0f;
+        uint32_t display = input_parcel->readUint32();
+        status = getDisplayBrightness(display, &brightness);
+        if (brightness == -1.0f) {
+          output_parcel->writeInt32(0);
+        } else {
+          output_parcel->writeInt32(INT32(brightness*254 + 1));
+        }
       }
       break;
 
@@ -1591,8 +1596,13 @@
           DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
           break;
         }
-        uint32_t level = UINT32(input_parcel->readInt32());
-        status = setPanelBrightness(level);
+        int level = input_parcel->readInt32();
+        hwc2_device_t *device = static_cast<hwc2_device_t *>(this);
+        if (level == 0) {
+          status = SetDisplayBrightness(device, HWC_DISPLAY_PRIMARY, -1.0f);
+        } else {
+          status = SetDisplayBrightness(device, HWC_DISPLAY_PRIMARY, (level - 1)/254.0f);
+        }
         output_parcel->writeInt32(status);
       }
       break;
@@ -2119,7 +2129,7 @@
 android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
   int ret = 0;
-  int32_t *brightness_value = NULL;
+  float *brightness = NULL;
   uint32_t display_id(0);
   PPPendingParams pending_action;
   PPDisplayAPIPayload resp_payload, req_payload;
@@ -2192,12 +2202,13 @@
           usleep(kSolidFillDelay);
           break;
         case kSetPanelBrightness:
-          brightness_value = reinterpret_cast<int32_t *>(resp_payload.payload);
-          if (brightness_value == NULL) {
-            DLOGE("Brightness value is Null");
-            ret = -EINVAL;
+          ret = -EINVAL;
+          brightness = reinterpret_cast<float *>(resp_payload.payload);
+          if (brightness == NULL) {
+            DLOGE("Brightness payload is Null");
           } else {
-            ret = hwc_display_[display_id]->SetPanelBrightness(*brightness_value);
+            ret = INT(SetDisplayBrightness(static_cast<hwc2_device_t *>(this),
+                      static_cast<hwc2_display_t>(display_id), *brightness));
           }
           break;
         case kEnableFrameCapture:
@@ -3294,10 +3305,6 @@
   }
 }
 
-int32_t HWCSession::SetDisplayBrightness(hwc2_device_t *device, hwc2_display_t display,
-                                         float brightness) {
-  return INT32(HWC2::Error::None);
-}
 
 int32_t HWCSession::GetDisplayBrightnessSupport(hwc2_device_t *device, hwc2_display_t display,
                                                 bool *outSupport) {
@@ -3315,12 +3322,15 @@
     DLOGE("Expected valid hwc_display");
     return HWC2_ERROR_BAD_PARAMETER;
   }
-  // This function isn't actually used in the framework
-  // The capability is used instead
   *outSupport = (hwc_display->GetDisplayClass() == DISPLAY_CLASS_BUILTIN);
   return HWC2_ERROR_NONE;
 }
 
+int32_t HWCSession::SetDisplayBrightness(hwc2_device_t *device, hwc2_display_t display,
+                                         float brightness) {
+  return CallDisplayFunction(device, display, &HWCDisplay::SetPanelBrightness, brightness);
+}
+
 android::status_t HWCSession::SetQSyncMode(const android::Parcel *input_parcel) {
   auto mode = input_parcel->readInt32();
   auto device = static_cast<hwc2_device_t *>(this);
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 1e1d1c1..dfc3bbb 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -270,11 +270,12 @@
   int32_t ControlPartialUpdate(int dpy, bool enable);
   int32_t DisplayBWTransactionPending(bool *status);
   int32_t SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status);
-  int32_t GetPanelBrightness(int *level);
   int32_t MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level);
   int32_t IsWbUbwcSupported(int *value);
   int32_t SetDynamicDSIClock(int64_t disp_id, uint32_t bitrate);
   bool HasHDRSupport(HWCDisplay *hwc_display);
+  int32_t getDisplayBrightness(uint32_t display, float *brightness);
+  int32_t setDisplayBrightness(uint32_t display, float brightness);
 
   // service methods
   void StartServices();
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index d3d889a..abd2786 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -291,38 +291,28 @@
 }
 
 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
-  int32_t error = -EINVAL;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(INT(level));
-    if (error) {
-      DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
-    }
+  if (!(0 <= level && level <= 255)) {
+    return -EINVAL;
   }
 
-  return error;
-}
-
-int32_t HWCSession::GetPanelBrightness(int *level) {
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
-  int32_t error = -EINVAL;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
-    if (error) {
-      DLOGE("Failed to get the panel brightness. Error = %d", error);
-    }
+  hwc2_device_t *device = static_cast<hwc2_device_t *>(this);
+  if (level == 0) {
+    return INT32(SetDisplayBrightness(device, HWC_DISPLAY_PRIMARY, -1.0f));
+  } else {
+    return INT32(SetDisplayBrightness(device, HWC_DISPLAY_PRIMARY, (level - 1)/254.0f));
   }
-
-  return error;
 }
 
 Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
-  int level = 0;
-  int32_t error = GetPanelBrightness(&level);
+  float brightness = -1.0f;
+  int32_t error = -EINVAL;
 
-  _hidl_cb(error, static_cast<uint32_t>(level));
+  error = getDisplayBrightness(HWC_DISPLAY_PRIMARY, &brightness);
+  if (brightness == -1.0f) {
+    _hidl_cb(error, 0);
+  } else {
+    _hidl_cb(error, static_cast<uint32_t>(254.0f*brightness + 1));
+  }
 
   return Void();
 }
@@ -902,4 +892,33 @@
   return 0;
 }
 
+int32_t HWCSession::getDisplayBrightness(uint32_t display, float *brightness) {
+  if (!brightness) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
+  if (display >= HWCCallbacks::kNumDisplays) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
+  int32_t error = -EINVAL;
+  *brightness = -1.0f;
+
+  HWCDisplay *hwc_display = hwc_display_[display];
+  if (hwc_display && hwc_display_[display]->GetDisplayClass() == DISPLAY_CLASS_BUILTIN) {
+    error = INT32(hwc_display_[display]->GetPanelBrightness(brightness));
+    if (error) {
+      DLOGE("Failed to get the panel brightness. Error = %d", error);
+    }
+  }
+
+  return error;
+}
+
+int32_t HWCSession::setDisplayBrightness(uint32_t display, float brightness) {
+  return SetDisplayBrightness(static_cast<hwc2_device_t *>(this),
+                              static_cast<hwc2_display_t>(display), brightness);
+}
+
 }  // namespace sdm