sdm: Add support for scaler

Add support for scaler v2 / qseed3

Change-Id: If3d48e6ac8e1cf25ac1b0af774dcc34226c0ed9b
CRs-fixed: 1114808
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index bf46200..9f74cdb 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -116,6 +116,12 @@
    */
   PLANE_SET_INPUT_FENCE,
   /*
+   * Op: Sets scaler config on this plane.
+   * Arg: uint32_t - Plane ID
+   *      uint64_t - Address of the scaler config object (version based)
+   */
+  PLANE_SET_SCALER_CONFIG,
+  /*
    * Op: Activate or deactivate a CRTC
    * Arg: uint32_t - CRTC ID
    *      uint32_t - 1 to enable, 0 to disable
@@ -305,6 +311,15 @@
   void *payload;
 };
 
+struct DRMScalerLUTInfo {
+  uint32_t dir_lut_size = 0;
+  uint32_t cir_lut_size = 0;
+  uint32_t sep_lut_size = 0;
+  uint64_t dir_lut = 0;
+  uint64_t cir_lut = 0;
+  uint64_t sep_lut = 0;
+};
+
 /* DRM Atomic Request Property Set.
  *
  * Helper class to create and populate atomic properties of DRM components
@@ -413,6 +428,13 @@
    * [return]: Error code if the API fails, 0 on success.
    */
   virtual int DestroyAtomicReq(DRMAtomicReqInterface *intf) = 0;
+  /*
+   * Sets the global scaler LUT
+   * [input]: LUT Info
+   * [return]: Error code if the API fails, 0 on success.
+   */
+  virtual int SetScalerLUT(const DRMScalerLUTInfo &lut_info) = 0;
 };
+
 }  // namespace sde_drm
 #endif  // __DRM_INTERFACE_H__
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
index 874b150..7d71eec 100644
--- a/sdm/libs/core/Android.mk
+++ b/sdm/libs/core/Android.mk
@@ -58,6 +58,7 @@
     LOCAL_SRC_FILES           += $(LOCAL_HW_INTF_PATH_2)/hw_info_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_device_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_events_drm.cpp \
+                                 $(LOCAL_HW_INTF_PATH_2)/hw_scale_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_color_manager_drm.cpp
 endif
 
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 7708c83..8746095 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -126,10 +126,16 @@
   UpdateMixerAttributes();
   hw_info_intf_->GetHWResourceInfo(&hw_resource_);
 
+  // TODO(user): In future, remove has_qseed3 member, add version and pass version to constructor
+  if (hw_resource_.has_qseed3) {
+    hw_scale_ = new HWScaleDRM(HWScaleDRM::Version::V2);
+  }
+
   return kErrorNone;
 }
 
 DisplayError HWDeviceDRM::Deinit() {
+  delete hw_scale_;
   drm_mgr_intf_->DestroyAtomicReq(drm_atomic_intf_);
   drm_atomic_intf_ = {};
   drm_mgr_intf_->UnregisterDisplay(token_);
@@ -423,6 +429,15 @@
           drm_atomic_intf_->Perform(DRMOps::PLANE_SET_INPUT_FENCE, pipe_id,
                                     input_buffer->acquire_fence_fd);
         }
+        if (hw_scale_) {
+          SDEScaler scaler_output = {};
+          hw_scale_->SetPlaneScaler(pipe_info->scale_data, &scaler_output);
+          // TODO(user): Remove qseed3 and add version check, then send appropriate scaler object
+          if (hw_resource_.has_qseed3) {
+            drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SCALER_CONFIG, pipe_id,
+                                      reinterpret_cast<uint64_t>(&scaler_output.scaler_v2));
+          }
+        }
       }
     }
 
@@ -719,6 +734,15 @@
 }
 
 DisplayError HWDeviceDRM::SetScaleLutConfig(HWScaleLutInfo *lut_info) {
+  sde_drm::DRMScalerLUTInfo drm_lut_info = {};
+  drm_lut_info.cir_lut = lut_info->cir_lut;
+  drm_lut_info.dir_lut = lut_info->dir_lut;
+  drm_lut_info.sep_lut = lut_info->sep_lut;
+  drm_lut_info.cir_lut_size = lut_info->cir_lut_size;
+  drm_lut_info.dir_lut_size = lut_info->dir_lut_size;
+  drm_lut_info.sep_lut_size = lut_info->sep_lut_size;
+  drm_mgr_intf_->SetScalerLUT(drm_lut_info);
+
   return kErrorNone;
 }
 
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 034826c..41aec9e 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -38,6 +38,7 @@
 #include <vector>
 
 #include "hw_interface.h"
+#include "hw_scale_drm.h"
 
 #define IOCTL_LOGE(ioctl, type) \
   DLOGE("ioctl %s, device = %d errno = %d, desc = %s", #ioctl, type, errno, strerror(errno))
@@ -134,6 +135,7 @@
   sde_drm::DRMConnectorInfo connector_info_ = {};
   std::string interface_str_ = "DSI";
   const char *kBrightnessNode = "/sys/class/backlight/panel0-backlight/brightness";
+  HWScaleDRM *hw_scale_ = {};
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_scale_drm.cpp b/sdm/libs/core/drm/hw_scale_drm.cpp
new file mode 100644
index 0000000..96f084e
--- /dev/null
+++ b/sdm/libs/core/drm/hw_scale_drm.cpp
@@ -0,0 +1,157 @@
+/*
+* Copyright (c) 2016-2017, 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:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <utils/debug.h>
+
+#include "hw_scale_drm.h"
+
+#define __CLASS__ "HWScaleDRM"
+
+namespace sdm {
+
+static uint32_t GetScalingFilter(ScalingFilterConfig filter_cfg) {
+  switch (filter_cfg) {
+    case kFilterEdgeDirected:
+      return FILTER_EDGE_DIRECTED_2D;
+    case kFilterCircular:
+      return FILTER_CIRCULAR_2D;
+    case kFilterSeparable:
+      return FILTER_SEPARABLE_1D;
+    case kFilterBilinear:
+      return FILTER_BILINEAR;
+    default:
+      DLOGE("Invalid Scaling Filter");
+      return kFilterMax;
+  }
+}
+
+static uint32_t GetAlphaInterpolation(HWAlphaInterpolation alpha_filter_cfg) {
+  switch (alpha_filter_cfg) {
+    case kInterpolationPixelRepeat:
+      return FILTER_ALPHA_DROP_REPEAT;
+    case kInterpolationBilinear:
+      return FILTER_ALPHA_BILINEAR;
+    default:
+      DLOGE("Invalid Alpha Interpolation");
+      return kInterpolationMax;
+  }
+}
+
+void HWScaleDRM::SetPlaneScaler(const HWScaleData &scale_data, SDEScaler *scaler) {
+  if (version_ == Version::V2) {
+    SetPlaneScalerV2(scale_data, &scaler->scaler_v2);
+  }
+}
+
+void HWScaleDRM::SetPlaneScalerV2(const HWScaleData &scale_data, sde_drm_scaler_v2 *scaler) {
+  if (!scale_data.enable.scale && !scale_data.enable.direction_detection &&
+      !scale_data.enable.detail_enhance) {
+    return;
+  }
+
+  scaler->enable = scale_data.enable.scale;
+  scaler->dir_en = scale_data.enable.direction_detection;
+  scaler->de.enable = scale_data.detail_enhance.enable;
+
+  for (int i = 0; i < SDE_MAX_PLANES; i++) {
+    const HWPlane &plane = scale_data.plane[i];
+    scaler->init_phase_x[i] = plane.init_phase_x;
+    scaler->phase_step_x[i] = plane.phase_step_x;
+    scaler->init_phase_y[i] = plane.init_phase_y;
+    scaler->phase_step_y[i] = plane.phase_step_y;
+
+    // TODO(user): Remove right, bottom from HWPlane and rename to LR, TB similar to qseed3
+    // Also remove roi_width which is unused.
+    scaler->pe.num_ext_pxls_lr[i] = plane.left.extension;
+    scaler->pe.num_ext_pxls_tb[i] = plane.top.extension;
+
+    scaler->pe.left_ftch[i] = plane.left.overfetch;
+    scaler->pe.top_ftch[i] = plane.top.overfetch;
+    scaler->pe.right_ftch[i] = plane.right.overfetch;
+    scaler->pe.btm_ftch[i] = plane.bottom.overfetch;
+
+    scaler->pe.left_rpt[i] = plane.left.repeat;
+    scaler->pe.top_rpt[i] = plane.top.repeat;
+    scaler->pe.right_rpt[i] = plane.right.repeat;
+    scaler->pe.btm_rpt[i] = plane.bottom.repeat;
+
+    scaler->preload_x[i] = UINT32(plane.preload_x);
+    scaler->preload_y[i] = UINT32(plane.preload_y);
+
+    scaler->src_width[i] = plane.src_width;
+    scaler->src_height[i] = plane.src_height;
+  }
+
+  scaler->dst_width = scale_data.dst_width;
+  scaler->dst_height = scale_data.dst_height;
+
+  scaler->y_rgb_filter_cfg = GetScalingFilter(scale_data.y_rgb_filter_cfg);
+  scaler->uv_filter_cfg = GetScalingFilter(scale_data.uv_filter_cfg);
+  scaler->alpha_filter_cfg = GetAlphaInterpolation(scale_data.alpha_filter_cfg);
+  scaler->blend_cfg = scale_data.blend_cfg;
+
+  scaler->lut_flag = (scale_data.lut_flag.lut_swap ? SCALER_LUT_SWAP : 0) |
+                     (scale_data.lut_flag.lut_dir_wr ? SCALER_LUT_DIR_WR : 0) |
+                     (scale_data.lut_flag.lut_y_cir_wr ? SCALER_LUT_Y_CIR_WR : 0) |
+                     (scale_data.lut_flag.lut_uv_cir_wr ? SCALER_LUT_UV_CIR_WR : 0) |
+                     (scale_data.lut_flag.lut_y_sep_wr ? SCALER_LUT_Y_SEP_WR : 0) |
+                     (scale_data.lut_flag.lut_uv_sep_wr ? SCALER_LUT_UV_SEP_WR : 0);
+
+  scaler->dir_lut_idx = scale_data.dir_lut_idx;
+  scaler->y_rgb_cir_lut_idx = scale_data.y_rgb_cir_lut_idx;
+  scaler->uv_cir_lut_idx = scale_data.uv_cir_lut_idx;
+  scaler->y_rgb_sep_lut_idx = scale_data.y_rgb_sep_lut_idx;
+  scaler->uv_sep_lut_idx = scale_data.uv_sep_lut_idx;
+
+  /* TODO(user): Uncomment when de support is added
+  if (scaler->de.enable) {
+    sde_drm_de_v1 *det_enhance = &scaler->de;
+    det_enhance->sharpen_level1 = scale_data.detail_enhance.sharpen_level1;
+    det_enhance->sharpen_level2 = scale_data.detail_enhance.sharpen_level2;
+    det_enhance->clip = scale_data.detail_enhance.clip;
+    det_enhance->limit = scale_data.detail_enhance.limit;
+    det_enhance->thr_quiet = scale_data.detail_enhance.thr_quiet;
+    det_enhance->thr_dieout = scale_data.detail_enhance.thr_dieout;
+    det_enhance->thr_low = scale_data.detail_enhance.thr_low;
+    det_enhance->thr_high = scale_data.detail_enhance.thr_high;
+    det_enhance->prec_shift = scale_data.detail_enhance.prec_shift;
+
+    for (int i = 0; i < SDE_MAX_DE_CURVES; i++) {
+      det_enhance->adjust_a[i] = scale_data.detail_enhance.adjust_a[i];
+      det_enhance->adjust_b[i] = scale_data.detail_enhance.adjust_b[i];
+      det_enhance->adjust_c[i] = scale_data.detail_enhance.adjust_c[i];
+    }
+  }
+  */
+
+  return;
+}
+
+}  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_scale_drm.h b/sdm/libs/core/drm/hw_scale_drm.h
new file mode 100644
index 0000000..8a4be70
--- /dev/null
+++ b/sdm/libs/core/drm/hw_scale_drm.h
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2016-2017, 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:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_SCALE_DRM_H__
+#define __HW_SCALE_DRM_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <drm.h>
+// The 3 headers above are a workaround to prevent kernel drm.h from being used that has the
+// "virtual" keyword used for a variable. In future replace libdrm version drm.h with kernel
+// version drm/drm.h
+#include <drm/sde_drm.h>
+#include <private/hw_info_types.h>
+
+namespace sdm {
+
+struct SDEScaler {
+  struct sde_drm_scaler_v2 scaler_v2 = {};
+  // More here, maybe in a union
+};
+
+class HWScaleDRM {
+ public:
+  enum class Version { V2 };
+  explicit HWScaleDRM(Version v) : version_(v) {}
+  void SetPlaneScaler(const HWScaleData &scale, SDEScaler *scaler);
+
+ private:
+  void SetPlaneScalerV2(const HWScaleData &scale, sde_drm_scaler_v2 *scaler_v2);
+
+  Version version_ = Version::V2;
+};
+
+}  // namespace sdm
+
+#endif  // __HW_SCALE_DRM_H__