Merge "gralloc1: Add support for P010 usage flag"
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 6bf7f97..6ff192e 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -304,6 +304,12 @@
    *      uint32_t - CRTC ID
    */
   CONNECTOR_SET_CRTC,
+  /*
+   * Op: Sets connector hdr metadata
+   * Arg: uint32_t - Connector ID
+   *      drm_msm_ext_hdr_metadata - hdr_metadata
+   */
+  CONNECTOR_SET_HDR_METADATA,
 };
 
 enum struct DRMRotation {
@@ -370,6 +376,7 @@
 /* Per CRTC Resource Info*/
 struct DRMCrtcInfo {
   bool has_src_split;
+  bool has_hdr;
   uint32_t max_blend_stages;
   uint32_t max_solidfill_stages;
   QSEEDVersion qseed_version;
@@ -476,6 +483,7 @@
   DRMRotation panel_orientation;
   drm_panel_hdr_properties panel_hdr_prop;
   uint32_t transfer_time_us;
+  drm_msm_ext_hdr_properties ext_hdr_prop;
 };
 
 /* Identifier token for a display */
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 92efd9f..303c89b 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -153,6 +153,8 @@
   bool secure = false;      //!< If this display is capable of handling secure content.
   bool is_cmdmode = false;  //!< If panel is command mode panel.
   bool hdr_supported = false;  //!< if HDR is enabled
+  bool hdr_metadata_type_one = false;  //!< Metadata type one obtained from HDR sink
+  uint32_t hdr_eotf = 0;  //!< Electro optical transfer function
   uint32_t max_luminance = 0;  //!< From Panel's peak luminance
   uint32_t average_luminance = 0;  //!< From Panel's average luminance
   uint32_t min_luminance = 0;  //!< From Panel's blackness level
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 9f6a5d6..b086907 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -292,6 +292,8 @@
   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
+  bool hdr_metadata_type_one = false;     // Static HDR metadata type one
+  uint32_t hdr_eotf = 0;              // Electro optical transfer function
   uint32_t peak_luminance = 0;        // Panel's peak luminance level
   uint32_t average_luminance = 0;     // Panel's average luminance level
   uint32_t blackness_level = 0;       // Panel's blackness level
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 1e948a2..5c5a45a 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -400,6 +400,8 @@
   fixed_info->max_luminance = fixed_info->hdr_supported ? hw_panel_info_.peak_luminance: 0;
   fixed_info->average_luminance = fixed_info->hdr_supported ? hw_panel_info_.average_luminance : 0;
   fixed_info->min_luminance = fixed_info->hdr_supported ?  hw_panel_info_.blackness_level: 0;
+  fixed_info->hdr_eotf = hw_panel_info_.hdr_eotf;
+  fixed_info->hdr_metadata_type_one = hw_panel_info_.hdr_metadata_type_one;
 
   return kErrorNone;
 }
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 16355c8..5b7576a 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -97,6 +97,7 @@
   virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
   virtual void InitializeConfigs();
   virtual DisplayError DumpDebugData() { return kErrorNone; }
+  virtual void PopulateHWPanelInfo();
 
   enum {
     kHWEventVSync,
@@ -113,7 +114,6 @@
   DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format, uint32_t width,
                          uint32_t *target);
   DisplayError PopulateDisplayAttributes(uint32_t index);
-  void PopulateHWPanelInfo();
   void GetHWDisplayPortAndMode();
   void GetHWPanelMaxBrightness();
   bool EnableHotPlugDetection(int enable);
diff --git a/sdm/libs/core/drm/hw_info_drm.cpp b/sdm/libs/core/drm/hw_info_drm.cpp
index 1f31727..b4c1d37 100644
--- a/sdm/libs/core/drm/hw_info_drm.cpp
+++ b/sdm/libs/core/drm/hw_info_drm.cpp
@@ -191,7 +191,6 @@
   hw_resource->has_dyn_bw_support = false;
   hw_resource->has_qseed3 = false;
   hw_resource->has_concurrent_writeback = false;
-  hw_resource->has_hdr = true;
 
   hw_resource->hw_version = SDEVERSION(4, 0, 1);
   // TODO(user): On FB driver hw_revision comprises of major version, minor version and hw_revision.
@@ -278,6 +277,7 @@
 void HWInfoDRM::GetSystemInfo(HWResourceInfo *hw_resource) {
   DRMCrtcInfo info;
   drm_mgr_intf_->GetCrtcInfo(0 /* system_info */, &info);
+  hw_resource->has_hdr = info.has_hdr;
   hw_resource->is_src_split = info.has_src_split;
   hw_resource->has_qseed3 = (info.qseed_version == sde_drm::QSEEDVersion::V3);
   hw_resource->num_blending_stages = info.max_blend_stages;
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index 565652e..f1d0d80 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -28,6 +28,7 @@
 */
 
 #include "hw_tv_drm.h"
+#include <sys/time.h>
 #include <utils/debug.h>
 #include <utils/sys.h>
 #include <utils/formats.h>
@@ -41,9 +42,19 @@
 #include <map>
 #include <utility>
 
+#ifndef HDR_EOTF_SMTPE_ST2084
+#define HDR_EOTF_SMTPE_ST2084 2
+#endif
+#ifndef HDR_EOTF_HLG
+#define HDR_EOTF_HLG 3
+#endif
 
 #define __CLASS__ "HWTVDRM"
 
+#define HDR_DISABLE 0
+#define HDR_ENABLE 1
+#define MIN_HDR_RESET_WAITTIME 2
+
 using drm_utils::DRMMaster;
 using drm_utils::DRMResMgr;
 using drm_utils::DRMLibLoader;
@@ -60,6 +71,23 @@
 
 namespace sdm {
 
+static int32_t GetEOTF(const GammaTransfer &transfer) {
+  int32_t hdr_transfer = -1;
+
+  switch (transfer) {
+  case Transfer_SMPTE_ST2084:
+    hdr_transfer = HDR_EOTF_SMTPE_ST2084;
+    break;
+  case Transfer_HLG:
+    hdr_transfer = HDR_EOTF_HLG;
+    break;
+  default:
+    DLOGW("Unknown Transfer: %d", transfer);
+  }
+
+  return hdr_transfer;
+}
+
 HWTVDRM::HWTVDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
                      HWInfoInterface *hw_info_intf)
   : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
@@ -148,5 +176,119 @@
   return kErrorNone;
 }
 
+void HWTVDRM::PopulateHWPanelInfo() {
+  hw_panel_info_ = {};
+
+  HWDeviceDRM::PopulateHWPanelInfo();
+  hw_panel_info_.hdr_enabled = connector_info_.ext_hdr_prop.hdr_supported;
+  hw_panel_info_.hdr_metadata_type_one = connector_info_.ext_hdr_prop.hdr_metadata_type_one;
+  hw_panel_info_.hdr_eotf = connector_info_.ext_hdr_prop.hdr_eotf;
+  hw_panel_info_.peak_luminance = connector_info_.ext_hdr_prop.hdr_max_luminance;
+  hw_panel_info_.average_luminance = connector_info_.ext_hdr_prop.hdr_avg_luminance;
+  hw_panel_info_.blackness_level = connector_info_.ext_hdr_prop.hdr_min_luminance;
+  DLOGI("TV Panel: %s, type_one = %d, eotf = %d, luminance[max = %d, min = %d, avg = %d]",
+        hw_panel_info_.hdr_enabled ? "HDR" : "Non-HDR", hw_panel_info_.hdr_metadata_type_one,
+        hw_panel_info_.hdr_eotf, hw_panel_info_.peak_luminance, hw_panel_info_.blackness_level,
+        hw_panel_info_.average_luminance);
+}
+
+DisplayError HWTVDRM::Commit(HWLayers *hw_layers) {
+  DisplayError error = UpdateHDRMetaData(hw_layers);
+  if (error != kErrorNone) {
+    return error;
+  }
+  return HWDeviceDRM::Commit(hw_layers);
+}
+
+DisplayError HWTVDRM::UpdateHDRMetaData(HWLayers *hw_layers) {
+  static struct timeval hdr_reset_start, hdr_reset_end;
+  static bool reset_hdr_flag = false;
+  const HWHDRLayerInfo &hdr_layer_info = hw_layers->info.hdr_layer_info;
+  if (!hw_panel_info_.hdr_enabled) {
+    return kErrorNone;
+  }
+
+  DisplayError error = kErrorNone;
+
+  Layer hdr_layer = {};
+  if (hdr_layer_info.operation == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) {
+    hdr_layer = *(hw_layers->info.stack->layers.at(UINT32(hdr_layer_info.layer_index)));
+  }
+
+  const LayerBuffer *layer_buffer = &hdr_layer.input_buffer;
+  const MasteringDisplay &mastering_display = layer_buffer->color_metadata.masteringDisplayInfo;
+  const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel;
+  const Primaries &primaries = mastering_display.primaries;
+
+  if (hdr_layer_info.operation == HWHDRLayerInfo::kSet) {
+    // Reset reset_hdr_flag to handle where there are two consecutive HDR video playbacks with not
+    // enough non-HDR frames in between to reset the HDR metadata.
+    reset_hdr_flag = false;
+
+    int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer);
+    hdr_metadata_.hdr_supported = 1;
+    hdr_metadata_.hdr_state = HDR_ENABLE;
+    hdr_metadata_.eotf = (eotf < 0) ? 0 : UINT32(eotf);
+    hdr_metadata_.white_point_x = primaries.whitePoint[0];
+    hdr_metadata_.white_point_y = primaries.whitePoint[1];
+    hdr_metadata_.display_primaries_x[0] = primaries.rgbPrimaries[0][0];
+    hdr_metadata_.display_primaries_y[0] = primaries.rgbPrimaries[0][1];
+    hdr_metadata_.display_primaries_x[1] = primaries.rgbPrimaries[1][0];
+    hdr_metadata_.display_primaries_y[1] = primaries.rgbPrimaries[1][1];
+    hdr_metadata_.display_primaries_x[2] = primaries.rgbPrimaries[2][0];
+    hdr_metadata_.display_primaries_y[2] = primaries.rgbPrimaries[2][1];
+    hdr_metadata_.min_luminance = mastering_display.minDisplayLuminance;
+    hdr_metadata_.max_luminance = mastering_display.maxDisplayLuminance/10000;
+    hdr_metadata_.max_content_light_level = light_level.maxContentLightLevel;
+    hdr_metadata_.max_average_light_level = light_level.minPicAverageLightLevel;
+
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_);
+    DumpHDRMetaData(hdr_layer_info.operation);
+  } else if (hdr_layer_info.operation == HWHDRLayerInfo::kReset) {
+    memset(&hdr_metadata_, 0, sizeof(hdr_metadata_));
+    hdr_metadata_.hdr_supported = 1;
+    hdr_metadata_.hdr_state = HDR_ENABLE;
+    reset_hdr_flag = true;
+    gettimeofday(&hdr_reset_start, NULL);
+
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_);
+    DumpHDRMetaData(hdr_layer_info.operation);
+  } else if (hdr_layer_info.operation == HWHDRLayerInfo::kNoOp) {
+    // TODO(user): This case handles the state transition from HDR_ENABLED to HDR_DISABLED.
+    // As per HDMI spec requirement, we need to send zero metadata for atleast 2 sec after end of
+    // playback. This timer calculates the 2 sec window after playback stops to stop sending HDR
+    // metadata. This will be replaced with an idle timer implementation in the future.
+    if (reset_hdr_flag) {
+      gettimeofday(&hdr_reset_end, NULL);
+      float hdr_reset_time_start = ((hdr_reset_start.tv_sec*1000) + (hdr_reset_start.tv_usec/1000));
+      float hdr_reset_time_end = ((hdr_reset_end.tv_sec*1000) + (hdr_reset_end.tv_usec/1000));
+
+      if (((hdr_reset_time_end-hdr_reset_time_start)/1000) >= MIN_HDR_RESET_WAITTIME) {
+        memset(&hdr_metadata_, 0, sizeof(hdr_metadata_));
+        hdr_metadata_.hdr_supported = 1;
+        hdr_metadata_.hdr_state = HDR_DISABLE;
+        reset_hdr_flag = false;
+
+        drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id,
+                                  &hdr_metadata_);
+      }
+    }
+  }
+
+  return error;
+}
+
+void HWTVDRM::DumpHDRMetaData(HWHDRLayerInfo::HDROperation operation) {
+  DLOGI("Operation = %d, HDR Metadata: MaxDisplayLuminance = %d MinDisplayLuminance = %d\n"
+        "MaxContentLightLevel = %d MaxAverageLightLevel = %d Red_x = %d Red_y = %d Green_x = %d\n"
+        "Green_y = %d Blue_x = %d Blue_y = %d WhitePoint_x = %d WhitePoint_y = %d EOTF = %d\n",
+        operation, hdr_metadata_.max_luminance, hdr_metadata_.min_luminance,
+        hdr_metadata_.max_content_light_level, hdr_metadata_.max_average_light_level,
+        hdr_metadata_.display_primaries_x[0], hdr_metadata_.display_primaries_y[0],
+        hdr_metadata_.display_primaries_x[1], hdr_metadata_.display_primaries_y[1],
+        hdr_metadata_.display_primaries_x[2], hdr_metadata_.display_primaries_y[2],
+        hdr_metadata_.white_point_x, hdr_metadata_.white_point_y, hdr_metadata_.eotf);
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/drm/hw_tv_drm.h b/sdm/libs/core/drm/hw_tv_drm.h
index 54ce327..5661bc2 100644
--- a/sdm/libs/core/drm/hw_tv_drm.h
+++ b/sdm/libs/core/drm/hw_tv_drm.h
@@ -46,10 +46,16 @@
   virtual DisplayError Doze();
   virtual DisplayError DozeSuspend();
   virtual DisplayError Standby();
+  virtual DisplayError Commit(HWLayers *hw_layers);
+  virtual void PopulateHWPanelInfo();
 
  private:
+  DisplayError UpdateHDRMetaData(HWLayers *hw_layers);
+  void DumpHDRMetaData(HWHDRLayerInfo::HDROperation operation);
+
   static const int kBitRGB  = 20;
   static const int kBitYUV  = 21;
+  drm_msm_ext_hdr_metadata hdr_metadata_ = {};
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index c846771..e5576f7 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -462,6 +462,9 @@
   bool secure_display_active = false;
   layer_stack_.flags.animating = animating_;
 
+  uint32_t color_mode_count = 0;
+  display_intf_->GetColorModeCount(&color_mode_count);
+
   // Add one layer for fb target
   // TODO(user): Add blit target layers
   for (auto hwc_layer : layer_set_) {
@@ -534,7 +537,7 @@
     bool hdr_layer = layer->input_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
                      (layer->input_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 ||
                      layer->input_buffer.color_metadata.transfer == Transfer_HLG);
-    if (hdr_layer && !disable_hdr_handling_) {
+    if (hdr_layer && !disable_hdr_handling_ && color_mode_count) {
       // dont honor HDR when its handling is disabled
       layer->input_buffer.flags.hdr = true;
       layer_stack_.flags.hdr_present = true;