sdm: Add support for SSPP Tonemapping

- Add interfaces in SDM to support SSPP Tonemapping.
- Get the SSPP tonemap caps from the drm interface and
  populate the SDM private interfaces.
- Add support to set the sspp tonemap config to drm planes.
- Handle Idle PowerCollapse event for SSPP luts.

Crs-fixed: 2200881
Change-Id: I38590915fd05e5cc77f38cd1df4724f43990045b
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index afa120e..f85a337 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -193,6 +193,10 @@
       uint32_t flip_buffer: 1;  //!< This flag will be set by SDM when the layer needs FBT flip
       uint32_t dest_tone_map : 1;  //!< This flag will be set by SDM when the layer needs
                                    //!< destination tone map
+      uint32_t src_3d_tone_map: 1;  //!< This flag will be set by SDM when the layer needs
+                                    //!< 3d tonemap
+      uint32_t src_1d_tone_map: 1;  //!< This flag will be set by SDM when the layer needs
+                                    //!< 1d tone map
     };
     uint32_t request_flags = 0;  //!< For initialization purpose only.
                                  //!< Shall not be refered directly.
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index c9b5782..7526544 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -32,6 +32,7 @@
 #include <map>
 #include <string>
 #include <bitset>
+#include <memory>
 
 namespace sdm {
 using std::string;
@@ -44,6 +45,11 @@
 #define MINOR 16
 #define SDEVERSION(major, minor, hw_rev) ((major) << MAJOR) | ((minor) << MINOR) | (hw_rev)
 
+// CSC Max Size
+#define MAX_CSC_MATRIX_COEFF_SIZE   9
+#define MAX_CSC_CLAMP_SIZE          6
+#define MAX_CSC_BIAS_SIZE           3
+
 enum HWDeviceType {
   kDevicePrimary,
   kDeviceHDMI,
@@ -131,6 +137,25 @@
   kHdrEOTFHLG = 0x8,
 };
 
+enum HWSrcTonemap {
+  kSrcTonemap1d,  // DMA
+  kSrcTonemap3d,  // VIG
+};
+
+enum HWToneMapLut {
+  kLutNone,     // No valid lut
+  kDma1dIgc,    // DMA IGC Lut
+  kDma1dGc,     // DMA GC Lut
+  kVig1dIgc,    // VIG IGC Lut
+  kVig3dGamut,  // 3D Gamut Lut
+};
+
+enum HWWriteOperation {
+  kNoOp,   // No-op, previously set config holds good
+  kSet,    // Sets the new config
+  kReset,  // Resets/Clears the previously set config
+};
+
 typedef std::map<HWSubBlockType, std::vector<LayerBufferFormat>> FormatsMap;
 typedef std::map<LayerBufferFormat, float> CompRatioMap;
 
@@ -158,6 +183,9 @@
   uint32_t id = 0;
   uint32_t master_pipe_id = 0;
   uint32_t max_rects = 1;
+  bool inverse_pma = 0;
+  uint32_t dgm_csc_version = 0;
+  std::map<HWToneMapLut, uint32_t> tm_lut_version_map = {};
 };
 
 struct HWRotatorInfo {
@@ -257,6 +285,7 @@
   HWQseedStepVersion pipe_qseed3_version = kQseed3v2;  // only valid when has_qseed3=true
   uint32_t min_prefill_lines = 0;
   InlineRotationVersion inrot_version = kInlineRotationNone;
+  std::bitset<32> src_tone_map = 0;  //!< Stores the bit mask of src tone map capability
 };
 
 struct HWSplitInfo {
@@ -447,6 +476,14 @@
   uint32_t src_height = 0;
 };
 
+struct HWCsc {
+  int64_t ctm_coeff[MAX_CSC_MATRIX_COEFF_SIZE] = {0};
+  uint32_t pre_bias[MAX_CSC_BIAS_SIZE] = {0};
+  uint32_t post_bias[MAX_CSC_BIAS_SIZE] = {0};
+  uint32_t pre_clamp[MAX_CSC_CLAMP_SIZE] = {0};
+  uint32_t post_clamp[MAX_CSC_CLAMP_SIZE] = {0};
+};
+
 struct HWScaleData {
   struct enable {
     uint8_t scale = 0;
@@ -495,6 +532,22 @@
   HWAVRModes mode = kContinuousMode;  // Specifies the AVR mode
 };
 
+struct HWPipeCscInfo {
+  HWWriteOperation op = kNoOp;
+  HWCsc csc = {};
+};
+
+struct HWPipeTonemapLutInfo {
+  HWWriteOperation op = kNoOp;
+  HWToneMapLut type = kLutNone;
+  std::shared_ptr<PPFeatureInfo> pay_load = nullptr;
+};
+
+struct HWPipeTonemapInversePma {
+  HWWriteOperation op = kNoOp;
+  bool inverse_pma = false;
+};
+
 struct HWPipeInfo {
   HWPipeInfo *pair = NULL;
   uint8_t rect = 255;
@@ -510,6 +563,9 @@
   uint8_t flags = 0;
   bool valid = false;
   bool is_virtual = 0;
+  HWPipeTonemapInversePma inverse_pma_info = {};
+  HWPipeCscInfo dgm_csc_info = {};
+  std::vector<HWPipeTonemapLutInfo> lut_info = {};
 };
 
 struct HWSolidfillStage {
diff --git a/sdm/include/private/resource_interface.h b/sdm/include/private/resource_interface.h
index 1e75298..b9d047c 100644
--- a/sdm/include/private/resource_interface.h
+++ b/sdm/include/private/resource_interface.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015 - 2018, 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:
@@ -33,7 +33,7 @@
 class ResourceInterface {
  public:
   enum ResourceCmd {
-    kCmdResetScalarLUT,
+    kCmdResetLUT,
     kCmdMax,
   };
 
diff --git a/sdm/include/utils/utils.h b/sdm/include/utils/utils.h
index b1c55c4..b10fd6b 100644
--- a/sdm/include/utils/utils.h
+++ b/sdm/include/utils/utils.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2016 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2016 - 2018, 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
@@ -30,6 +30,8 @@
 #ifndef __UTILS_H__
 #define __UTILS_H__
 
+#include <cstring>
+
 namespace sdm {
 
 float gcd(float a, float b);
@@ -43,6 +45,11 @@
 
 DriverType GetDriverType();
 
+template<class T>
+bool SameConfig(T *t1, T *t2, unsigned int size) {
+  return !(std::memcmp(t1, t2, size));
+}
+
 }  // namespace sdm
 
 #endif  // __UTILS_H__
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 3acdcf0..45fc57d 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -426,7 +426,7 @@
           reinterpret_cast<DisplayCompositionContext *>(display_ctx);
 
   if (display_comp_ctx) {
-    resource_intf_->Perform(ResourceInterface::kCmdResetScalarLUT,
+    resource_intf_->Perform(ResourceInterface::kCmdResetLUT,
                             display_comp_ctx->display_resource_ctx);
   }
 }
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index fa413bb..18de450 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -102,6 +102,24 @@
 
 namespace sdm {
 
+static PPBlock GetPPBlock(const HWToneMapLut &lut_type) {
+  PPBlock pp_block = kPPBlockMax;
+  switch (lut_type) {
+    case kDma1dIgc:
+    case kDma1dGc:
+      pp_block = kDGM;
+      break;
+    case kVig1dIgc:
+    case kVig3dGamut:
+      pp_block = kVIG;
+      break;
+    default:
+      DLOGE("Unknown PP Block");
+      break;
+  }
+  return pp_block;
+}
+
 static void GetDRMFormat(LayerBufferFormat format, uint32_t *drm_format,
                          uint64_t *drm_format_modifier) {
   switch (format) {
@@ -951,6 +969,8 @@
         DRMMultiRectMode multirect_mode;
         SetMultiRectMode(pipe_info->flags, &multirect_mode);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_MULTIRECT_MODE, pipe_id, multirect_mode);
+
+        SetSsppTonemapFeatures(pipe_info);
       }
     }
   }
@@ -1608,6 +1628,7 @@
   }
 }
 
+
 void HWDeviceDRM::SetMultiRectMode(const uint32_t flags, DRMMultiRectMode *target) {
   *target = DRMMultiRectMode::NONE;
   if (flags & kMultiRect) {
@@ -1618,4 +1639,74 @@
   }
 }
 
+void HWDeviceDRM::SetSsppTonemapFeatures(HWPipeInfo *pipe_info) {
+  if (pipe_info->dgm_csc_info.op != kNoOp) {
+    SDECsc csc = {};
+    SetDGMCsc(pipe_info->dgm_csc_info, &csc);
+    DLOGV_IF(kTagDriverConfig, "Call Perform DGM CSC Op = %s",
+            (pipe_info->dgm_csc_info.op == kSet) ? "Set" : "Reset");
+    drm_atomic_intf_->Perform(DRMOps::PLANE_SET_DGM_CSC_CONFIG, pipe_info->pipe_id,
+                              reinterpret_cast<uint64_t>(&csc.csc_v1));
+  }
+  if (pipe_info->inverse_pma_info.op != kNoOp) {
+    DLOGV_IF(kTagDriverConfig, "Call Perform Inverse PMA Op = %s",
+            (pipe_info->inverse_pma_info.op == kSet) ? "Set" : "Reset");
+    drm_atomic_intf_->Perform(DRMOps::PLANE_SET_INVERSE_PMA, pipe_info->pipe_id,
+                             (pipe_info->inverse_pma_info.inverse_pma) ? 1: 0);
+  }
+  SetSsppLutFeatures(pipe_info);
+}
+
+void HWDeviceDRM::SetDGMCsc(const HWPipeCscInfo &dgm_csc_info, SDECsc *csc) {
+  SetDGMCscV1(dgm_csc_info.csc, &csc->csc_v1);
+}
+
+void HWDeviceDRM::SetDGMCscV1(const HWCsc &dgm_csc, sde_drm_csc_v1 *csc_v1) {
+  uint32_t i = 0;
+  for (i = 0; i < MAX_CSC_MATRIX_COEFF_SIZE; i++) {
+    csc_v1->ctm_coeff[i] = dgm_csc.ctm_coeff[i];
+    DLOGV_IF(kTagDriverConfig, " DGM csc_v1[%d] = %d", i, csc_v1->ctm_coeff[i]);
+  }
+  for (i = 0; i < MAX_CSC_BIAS_SIZE; i++) {
+    csc_v1->pre_bias[i] = dgm_csc.pre_bias[i];
+    csc_v1->post_bias[i] = dgm_csc.post_bias[i];
+  }
+  for (i = 0; i < MAX_CSC_CLAMP_SIZE; i++) {
+    csc_v1->pre_clamp[i] = dgm_csc.pre_clamp[i];
+    csc_v1->post_clamp[i] = dgm_csc.post_clamp[i];
+  }
+}
+
+void HWDeviceDRM::SetSsppLutFeatures(HWPipeInfo *pipe_info) {
+  for (HWPipeTonemapLutInfo &lut_info : pipe_info->lut_info) {
+    if (lut_info.op != kNoOp) {
+      std::shared_ptr<PPFeatureInfo> feature = lut_info.pay_load;
+      if (feature == nullptr) {
+        DLOGE("Null Pointer for Op = %d lut type = %d", lut_info.op, lut_info.type);
+        continue;
+      }
+      DRMPPFeatureInfo kernel_params = {};
+      std::vector<DRMPPFeatureID> drm_id = {};
+      PPBlock pp_block = GetPPBlock(lut_info.type);
+      hw_color_mgr_->ToDrmFeatureId(pp_block, feature->feature_id_, &drm_id);
+      for (DRMPPFeatureID id : drm_id) {
+        kernel_params.id = id;
+        bool disable = (lut_info.op == kReset);
+        DLOGV_IF(kTagDriverConfig, "Lut Type = %d PPBlock = %d Op = %s Disable = %d Feature = %p",
+                 lut_info.type, pp_block, (lut_info.op ==kSet) ? "Set" : "Reset", disable,
+                 feature.get());
+        int ret = hw_color_mgr_->GetDrmFeature(feature.get(), &kernel_params, disable);
+        if (!ret) {
+          drm_atomic_intf_->Perform(DRMOps::PLANE_SET_POST_PROC, pipe_info->pipe_id,
+                                    &kernel_params);
+          hw_color_mgr_->FreeDrmFeatureData(&kernel_params);
+        } else {
+          DLOGE("GetDrmFeature failed for Lut type = %d", lut_info.type);
+        }
+      }
+      drm_id.clear();
+    }
+  }
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index a5ed40b..a0782c4 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -49,6 +49,11 @@
 namespace sdm {
 class HWInfoInterface;
 
+struct SDECsc {
+  struct sde_drm_csc_v1 csc_v1 = {};
+  // More here, maybe in a union
+};
+
 class HWDeviceDRM : public HWInterface {
  public:
   HWDeviceDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
@@ -135,6 +140,10 @@
   bool IsResolutionSwitchEnabled() const { return resolution_switch_enabled_; }
   void SetTopology(sde_drm::DRMTopology drm_topology, HWTopology *hw_topology);
   void SetMultiRectMode(const uint32_t flags, sde_drm::DRMMultiRectMode *target);
+  void SetSsppTonemapFeatures(HWPipeInfo *pipe_info);
+  void SetDGMCsc(const HWPipeCscInfo &dgm_csc_info, SDECsc *csc);
+  void SetDGMCscV1(const HWCsc &dgm_csc, sde_drm_csc_v1 *csc_v1);
+  void SetSsppLutFeatures(HWPipeInfo *pipe_info);
 
   class Registry {
    public:
diff --git a/sdm/libs/core/drm/hw_info_drm.cpp b/sdm/libs/core/drm/hw_info_drm.cpp
index dc5a557..f15749a 100644
--- a/sdm/libs/core/drm/hw_info_drm.cpp
+++ b/sdm/libs/core/drm/hw_info_drm.cpp
@@ -73,6 +73,7 @@
 using sde_drm::DRMPlanesInfo;
 using sde_drm::DRMCrtcInfo;
 using sde_drm::DRMPlaneType;
+using sde_drm::DRMTonemapLutType;
 
 using std::vector;
 using std::map;
@@ -225,6 +226,7 @@
   DLOGI("Has QSEED3 = %d", hw_resource->has_qseed3);
   DLOGI("Has UBWC = %d", hw_resource->has_ubwc);
   DLOGI("Has Concurrent Writeback = %d", hw_resource->has_concurrent_writeback);
+  DLOGI("Has Src Tonemap = %d", hw_resource->src_tone_map);
   DLOGI("Max Low Bw = %" PRIu64 "", hw_resource->max_bandwidth_low);
   DLOGI("Max High Bw = % " PRIu64 "", hw_resource->max_bandwidth_high);
   DLOGI("Max Pipe Bw = %" PRIu64 " KBps", hw_resource->max_pipe_bw);
@@ -329,6 +331,8 @@
   uint32_t vig_pipe_count = 0;
   uint32_t dma_pipe_count = 0;
   uint32_t virtual_pipe_count = 0;
+  int disable_src_tonemap = 0;
+  Debug::Get()->GetProperty("sdm.disable_src_tonemap", &disable_src_tonemap);
 
   for (auto &pipe_obj : planes) {
     if (max_vig_pipes && max_dma_pipes) {
@@ -392,6 +396,39 @@
     pipe_caps.master_pipe_id = pipe_obj.second.master_plane_id;
     DLOGI("Adding %s Pipe : Id %x, master_pipe_id : Id %x",
           name.c_str(), pipe_obj.first, pipe_obj.second.master_plane_id);
+    pipe_caps.inverse_pma = pipe_obj.second.inverse_pma;
+    pipe_caps.dgm_csc_version = pipe_obj.second.dgm_csc_version;
+    // disable src tonemap feature if its disabled using property.
+    if (!disable_src_tonemap) {
+      for (auto &it : pipe_obj.second.tonemap_lut_version_map) {
+        HWToneMapLut tonemap_lut = kLutNone;
+        switch (it.first) {
+          case DRMTonemapLutType::DMA_1D_IGC:
+            tonemap_lut = kDma1dIgc;
+            break;
+          case DRMTonemapLutType::DMA_1D_GC:
+            tonemap_lut = kDma1dGc;
+            break;
+          case DRMTonemapLutType::VIG_1D_IGC:
+            tonemap_lut = kVig1dIgc;
+            break;
+          case DRMTonemapLutType::VIG_3D_GAMUT:
+            tonemap_lut = kVig3dGamut;
+            break;
+          default:
+            DLOGE("Unknown Tonemap Lut");
+            break;
+        }
+        if (tonemap_lut != kLutNone) {
+          pipe_caps.tm_lut_version_map[tonemap_lut] = it.second;
+          if (pipe_caps.type == kPipeTypeVIG) {
+            hw_resource->src_tone_map[kSrcTonemap3d] = 1;
+          } else if (pipe_caps.type == kPipeTypeDMA) {
+            hw_resource->src_tone_map[kSrcTonemap1d] = 1;
+          }
+        }
+      }
+    }
     hw_resource->hw_pipes.push_back(std::move(pipe_caps));
   }
   hw_resource->has_excl_rect = planes[0].second.has_excl_rect;