The sharpness property requires the use of one of the scaler
so need to set the sharpness scaler coefficient values.
These values are based on experiments and vary for different
tap value/win size. These values are normalized by taking the
sum of all values and then dividing each value with a sum.

v2: Fix ifndef header naming issue reported by kernel test robot
v3: Rename file name[Arun]
    Replace array size number with macro[Arun]
v4: Correct the register format[Jani]
    Add brief comment and expalin about file[Jani]
    Remove coefficient value from crtc_state[Jani]
v5: Fix build issue
v6: Add new function for writing coefficients[Ankit]
v7: Add cooments and add a scaler id check [Ankit]

Signed-off-by: Nemesa Garg <nemesa.g...@intel.com>
Reviewed-by: Naga Venkata Srikanth V <nagavenkata.srikant...@intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/display/intel_casf.c     | 154 ++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_casf.h     |  16 ++
 .../gpu/drm/i915/display/intel_casf_regs.h    |  19 +++
 drivers/gpu/drm/i915/display/intel_display.c  |   1 +
 .../drm/i915/display/intel_display_types.h    |  13 ++
 drivers/gpu/drm/xe/Makefile                   |   1 +
 7 files changed, 205 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/intel_casf.c
 create mode 100644 drivers/gpu/drm/i915/display/intel_casf.h
 create mode 100644 drivers/gpu/drm/i915/display/intel_casf_regs.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index ed05b131ed3a..d7550b26cdfb 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -230,6 +230,7 @@ i915-y += \
        display/intel_bios.o \
        display/intel_bo.o \
        display/intel_bw.o \
+       display/intel_casf.o \
        display/intel_cdclk.o \
        display/intel_cmtg.o \
        display/intel_color.o \
diff --git a/drivers/gpu/drm/i915/display/intel_casf.c 
b/drivers/gpu/drm/i915/display/intel_casf.c
new file mode 100644
index 000000000000..1526bebae1b6
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_casf.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright ?? 2025 Intel Corporation
+ *
+ */
+#include "i915_reg.h"
+#include "intel_casf.h"
+#include "intel_casf_regs.h"
+#include "intel_de.h"
+#include "intel_display_types.h"
+#include "skl_scaler.h"
+
+#define FILTER_COEFF_0_125 125
+#define FILTER_COEFF_0_25 250
+#define FILTER_COEFF_0_5 500
+#define FILTER_COEFF_1_0 1000
+#define FILTER_COEFF_0_0 0
+#define SET_POSITIVE_SIGN(x) ((x) & (~SIGN))
+
+/**
+ * DOC: Content Adaptive Sharpness Filter (CASF)
+ *
+ * From LNL onwards the display engine based adaptive
+ * sharpening filter is supported. This helps in
+ * improving the image quality. The display hardware
+ * uses one of the pipe scaler for implementing casf.
+ * It works on a region of pixels depending on the
+ * tap size. The coefficients are used to generate an
+ * alpha value which is used to blend the sharpened image
+ * to original image.
+ */
+
+const u16 filtercoeff_1[] = {
+       FILTER_COEFF_0_0, FILTER_COEFF_0_0, FILTER_COEFF_0_5,
+       FILTER_COEFF_1_0, FILTER_COEFF_0_5, FILTER_COEFF_0_0,
+       FILTER_COEFF_0_0,
+};
+
+const u16 filtercoeff_2[] = {
+       FILTER_COEFF_0_0, FILTER_COEFF_0_25, FILTER_COEFF_0_5,
+       FILTER_COEFF_1_0, FILTER_COEFF_0_5, FILTER_COEFF_0_25,
+       FILTER_COEFF_0_0,
+};
+
+const u16 filtercoeff_3[] = {
+       FILTER_COEFF_0_125, FILTER_COEFF_0_25, FILTER_COEFF_0_5,
+       FILTER_COEFF_1_0, FILTER_COEFF_0_5, FILTER_COEFF_0_25,
+       FILTER_COEFF_0_125,
+};
+
+static int casf_coeff_tap(int i)
+{
+       return i % SCALER_FILTER_NUM_TAPS;
+}
+
+static u16 casf_coeff(struct intel_crtc_state *crtc_state, int t)
+{
+       struct scaler_filter_coeff value;
+       u16 coeff;
+
+       value = crtc_state->hw.casf_params.coeff[t];
+       coeff = SET_POSITIVE_SIGN(0) | EXPONENT(value.exp) | 
MANTISSA(value.mantissa);
+
+       return coeff;
+}
+
+/*
+ * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set.
+ * To enable casf:  program scaler coefficients with the coeffients
+ * that are calculated and stored in hw.casf_params.coeff as per
+ * SCALER_COEFFICIENT_FORMAT
+ *
+ */
+static void intel_casf_write_coeff(struct intel_crtc_state *crtc_state)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       int id = crtc_state->scaler_state.scaler_id;
+       int i;
+
+       if (id == 0) {
+               drm_WARN(display->drm, 0, "Second scaler not enabled\n");
+               return;
+       }
+
+       intel_de_write_fw(display, GLK_PS_COEF_INDEX_SET(crtc->pipe, id, 0),
+                         PS_COEF_INDEX_AUTO_INC);
+
+       intel_de_write_fw(display, GLK_PS_COEF_INDEX_SET(crtc->pipe, id, 1),
+                         PS_COEF_INDEX_AUTO_INC);
+
+       for (i = 0; i < 17 * 7; i += 2) {
+               u32 tmp;
+               int t;
+
+               t = casf_coeff_tap(i);
+               tmp = casf_coeff(crtc_state, t);
+
+               t = casf_coeff_tap(i + 1);
+               tmp |= casf_coeff(crtc_state, t) << 16;
+
+               intel_de_write_fw(display, GLK_PS_COEF_DATA_SET(crtc->pipe, id, 
0),
+                                 tmp);
+               intel_de_write_fw(display, GLK_PS_COEF_DATA_SET(crtc->pipe, id, 
1),
+                                 tmp);
+       }
+}
+
+void intel_casf_enable(struct intel_crtc_state *crtc_state)
+{
+       intel_casf_write_coeff(crtc_state);
+}
+
+static void convert_sharpness_coef_binary(struct scaler_filter_coeff *coeff,
+                                         u16 coefficient)
+{
+       if (coefficient < 25) {
+               coeff->mantissa = (coefficient * 2048) / 100;
+               coeff->exp = 3;
+       } else if (coefficient < 50) {
+               coeff->mantissa = (coefficient * 1024) / 100;
+               coeff->exp = 2;
+       } else if (coefficient < 100) {
+               coeff->mantissa = (coefficient * 512) / 100;
+               coeff->exp = 1;
+       } else {
+               coeff->mantissa = (coefficient * 256) / 100;
+               coeff->exp = 0;
+       }
+}
+
+void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state)
+{
+       const u16 *filtercoeff;
+       u16 filter_coeff[SCALER_FILTER_NUM_TAPS];
+       u16 sumcoeff = 0;
+       u8 i;
+
+       if (crtc_state->hw.casf_params.win_size == 0)
+               filtercoeff = filtercoeff_1;
+       else if (crtc_state->hw.casf_params.win_size == 1)
+               filtercoeff = filtercoeff_2;
+       else
+               filtercoeff = filtercoeff_3;
+
+       for (i = 0; i < SCALER_FILTER_NUM_TAPS; i++)
+               sumcoeff += *(filtercoeff + i);
+
+       for (i = 0; i < SCALER_FILTER_NUM_TAPS; i++) {
+               filter_coeff[i] = (*(filtercoeff + i) * 100 / sumcoeff);
+               
convert_sharpness_coef_binary(&crtc_state->hw.casf_params.coeff[i],
+                                             filter_coeff[i]);
+       }
+}
diff --git a/drivers/gpu/drm/i915/display/intel_casf.h 
b/drivers/gpu/drm/i915/display/intel_casf.h
new file mode 100644
index 000000000000..840208b277f8
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_casf.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright ?? 2025 Intel Corporation
+ */
+
+#ifndef __INTEL_CASF_H__
+#define __INTEL_CASF_H__
+
+#include <linux/types.h>
+
+struct intel_crtc_state;
+
+void intel_casf_enable(struct intel_crtc_state *crtc_state);
+void intel_casf_scaler_compute_config(struct intel_crtc_state *crtc_state);
+
+#endif /* __INTEL_CASF_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_casf_regs.h 
b/drivers/gpu/drm/i915/display/intel_casf_regs.h
new file mode 100644
index 000000000000..0b3fcdb22c0c
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_casf_regs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright ?? 2024 Intel Corporation
+ */
+
+#ifndef __INTEL_CASF_REGS_H__
+#define __INTEL_CASF_REGS_H__
+
+#include "intel_display_reg_defs.h"
+
+/* Scaler Coefficient structure */
+#define SIGN                           REG_BIT(15)
+#define EXPONENT_MASK                  REG_GENMASK(13, 12)
+#define EXPONENT(x)                    REG_FIELD_PREP(EXPONENT_MASK, (x))
+#define MANTISSA_MASK                  REG_GENMASK(11, 3)
+#define MANTISSA(x)                    REG_FIELD_PREP(MANTISSA_MASK, (x))
+
+#endif /* __INTEL_CASF_REGS__ */
+
diff --git a/drivers/gpu/drm/i915/display/intel_display.c 
b/drivers/gpu/drm/i915/display/intel_display.c
index 6c1e7441313e..da8b635f288a 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -60,6 +60,7 @@
 #include "intel_audio.h"
 #include "intel_bo.h"
 #include "intel_bw.h"
+#include "intel_casf.h"
 #include "intel_cdclk.h"
 #include "intel_clock_gating.h"
 #include "intel_color.h"
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 6a82c6ade549..7d82adc03a01 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -933,6 +933,18 @@ struct intel_csc_matrix {
        u16 postoff[3];
 };
 
+struct scaler_filter_coeff {
+       u16 sign;
+       u16 exp;
+       u16 mantissa;
+};
+
+struct intel_casf {
+#define SCALER_FILTER_NUM_TAPS 7
+       struct scaler_filter_coeff coeff[SCALER_FILTER_NUM_TAPS];
+       u8 win_size;
+};
+
 void intel_io_mmio_fw_write(void *ctx, i915_reg_t reg, u32 val);
 
 typedef void (*intel_io_reg_write)(void *ctx, i915_reg_t reg, u32 val);
@@ -973,6 +985,7 @@ struct intel_crtc_state {
                struct drm_property_blob *degamma_lut, *gamma_lut, *ctm;
                struct drm_display_mode mode, pipe_mode, adjusted_mode;
                enum drm_scaling_filter scaling_filter;
+               struct intel_casf casf_params;
        } hw;
 
        /* actual state of LUTs */
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 5ce65ccb3c08..f2418585a498 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -205,6 +205,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
        i915-display/intel_backlight.o \
        i915-display/intel_bios.o \
        i915-display/intel_bw.o \
+       i915-display/intel_casf.o \
        i915-display/intel_cdclk.o \
        i915-display/intel_cmtg.o \
        i915-display/intel_color.o \
-- 
2.25.1

Reply via email to