From: Alvin Lee <[email protected]>

[Description]
- Gamcor light sleep must be disabled before gamcor programming
- Mirror the programming sequence for DSCL light sleep
- Create a dcn60 version for gamcor programming
- Make dcn30 helper functions public so they can be called from the
  new dcn60 function

Signed-off-by: Alvin Lee <[email protected]>
Signed-off-by: Fangzhi Zuo <[email protected]>
Reviewed-by: Nicholas Kazlauskas <[email protected]>
---
 drivers/gpu/drm/amd/display/dc/dpp/Makefile   |   2 +-
 .../drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h  |  22 ++++
 .../amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c   |  10 +-
 .../drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c  |   2 +-
 .../drm/amd/display/dc/dpp/dcn60/dcn60_dpp.h  |   3 +
 .../amd/display/dc/dpp/dcn60/dcn60_dpp_cm.c   | 124 ++++++++++++++++++
 6 files changed, 156 insertions(+), 7 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp_cm.c

diff --git a/drivers/gpu/drm/amd/display/dc/dpp/Makefile 
b/drivers/gpu/drm/amd/display/dc/dpp/Makefile
index f5da45aacfca..2aaa0e8a8bd6 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dpp/Makefile
@@ -99,7 +99,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_DPP_DCN50)
 
 ###############################################################################
 
-DPP_DCN60 = dcn60_dpp.o dcn60_dpp_dscl.o
+DPP_DCN60 = dcn60_dpp.o dcn60_dpp_dscl.o dcn60_dpp_cm.o
 
 AMD_DAL_DPP_DCN60 = $(addprefix $(AMDDALPATH)/dc/dpp/dcn60/,$(DPP_DCN60))
 
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h 
b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h
index 6a61b99d6a79..f397e8222ac9 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h
@@ -587,6 +587,28 @@ bool dpp3_construct(struct dcn3_dpp *dpp3,
 bool dpp3_program_gamcor_lut(
        struct dpp *dpp_base, const struct pwl_params *params);
 
+struct dcn3_xfer_func_reg;
+
+void dpp3_enable_cm_block(
+       struct dpp *dpp_base);
+
+enum dc_lut_mode dpp30_get_gamcor_current(
+       struct dpp *dpp_base);
+
+void dpp3_program_gammcor_lut(
+       struct dpp *dpp_base,
+       const struct pwl_result_data *rgb,
+       uint32_t num,
+       bool is_ram_a);
+
+void dpp3_gamcor_reg_field(
+       struct dcn3_dpp *dpp,
+       struct dcn3_xfer_func_reg *reg);
+
+void dpp3_configure_gamcor_lut(
+       struct dpp *dpp_base,
+       bool is_ram_a);
+
 void dpp3_program_CM_dealpha(
                struct dpp *dpp_base,
                uint32_t enable, uint32_t additive_blending);
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c 
b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
index 083ab6acb687..86f47d33ec64 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
@@ -42,7 +42,7 @@
 #define FN(reg_name, field_name) \
        dpp->tf_shift->field_name, dpp->tf_mask->field_name
 
-static void dpp3_enable_cm_block(
+void dpp3_enable_cm_block(
                struct dpp *dpp_base)
 {
        struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base);
@@ -56,7 +56,7 @@ static void dpp3_enable_cm_block(
        REG_UPDATE(CM_CONTROL, CM_BYPASS, cm_bypass_mode);
 }
 
-static enum dc_lut_mode dpp30_get_gamcor_current(struct dpp *dpp_base)
+enum dc_lut_mode dpp30_get_gamcor_current(struct dpp *dpp_base)
 {
        enum dc_lut_mode mode = LUT_BYPASS;
        uint32_t state_mode;
@@ -76,7 +76,7 @@ static enum dc_lut_mode dpp30_get_gamcor_current(struct dpp 
*dpp_base)
        return mode;
 }
 
-static void dpp3_program_gammcor_lut(
+void dpp3_program_gammcor_lut(
                struct dpp *dpp_base,
                const struct pwl_result_data *rgb,
                uint32_t num,
@@ -171,7 +171,7 @@ void dpp3_program_cm_bias(
                        CM_BIAS_CB_B, bias_params->cm_bias_cb_b);
 }
 
-static void dpp3_gamcor_reg_field(
+void dpp3_gamcor_reg_field(
                struct dcn3_dpp *dpp,
                struct dcn3_xfer_func_reg *reg)
 {
@@ -204,7 +204,7 @@ static void dpp3_gamcor_reg_field(
        reg->masks.exp_resion_start_segment = 
dpp->tf_mask->CM_GAMCOR_RAMA_EXP_REGION_START_SEGMENT_B;
 }
 
-static void dpp3_configure_gamcor_lut(
+void dpp3_configure_gamcor_lut(
                struct dpp *dpp_base,
                bool is_ram_a)
 {
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c 
b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c
index f02aebcedd70..be2effb14fc3 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c
@@ -294,7 +294,7 @@ void dpp60_full_bypass(struct dpp *dpp_base)
 }
 
 static struct dpp_funcs dcn60_dpp_funcs = {
-       .dpp_program_gamcor_lut         = dpp3_program_gamcor_lut,
+       .dpp_program_gamcor_lut         = dpp6_program_gamcor_lut,
        .dpp_read_state                         = dpp401_read_state,
        .dpp_reset                                      = dpp_reset,
        .dpp_set_scaler                         = 
dpp60_dscl_set_scaler_manual_scale,
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.h 
b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.h
index a0cc57e79ff7..5d09fcd04553 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.h
@@ -518,5 +518,8 @@ bool dpp60_construct(struct dcn60_dpp *dpp60,
        const struct dcn60_dpp_shift *tf_shift,
        const struct dcn60_dpp_mask *tf_mask);
 
+bool dpp6_program_gamcor_lut(
+       struct dpp *dpp_base, const struct pwl_params *params);
+
 
 #endif /* __DCN60_DPP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp_cm.c 
b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp_cm.c
new file mode 100644
index 000000000000..cb34a9f856c1
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp_cm.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+
+#include "dm_services.h"
+#include "core_types.h"
+#include "reg_helper.h"
+#include "dcn60/dcn60_dpp.h"
+#include "basics/conversion.h"
+#include "dcn30/dcn30_cm_common.h"
+
+#define REG(reg)\
+       dpp->tf_regs->reg
+
+#define CTX \
+       dpp->base.ctx
+
+#undef FN
+#define FN(reg_name, field_name) \
+       dpp->tf_shift->field_name, dpp->tf_mask->field_name
+
+static void dpp6_power_on_gamcor_lut(struct dpp *dpp_base, bool power_on)
+{
+       struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
+
+       if (power_on) {
+               REG_UPDATE(CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_FORCE, 0);
+               REG_UPDATE(CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_DIS, 1);
+               REG_WAIT(CM_MEM_PWR_STATUS, GAMCOR_MEM_PWR_STATE, 0, 1, 100);
+       } else {
+               if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.cm) {
+                       dpp->base.ctx->dc->optimized_required = true;
+                       dpp->base.deferred_reg_writes.bits.disable_gamcor = 
true;
+               }
+       }
+}
+
+bool dpp6_program_gamcor_lut(
+       struct dpp *dpp_base, const struct pwl_params *params)
+{
+       enum dc_lut_mode current_mode;
+       enum dc_lut_mode next_mode;
+       struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
+       struct dcn3_xfer_func_reg gam_regs;
+
+       dpp3_enable_cm_block(dpp_base);
+
+       if (params == NULL) { //bypass if we have no pwl data
+               REG_SET(CM_GAMCOR_CONTROL, 0, CM_GAMCOR_MODE, 0);
+               if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.cm)
+                       dpp6_power_on_gamcor_lut(dpp_base, false);
+               return false;
+       }
+       dpp6_power_on_gamcor_lut(dpp_base, true);
+       REG_SET(CM_GAMCOR_CONTROL, 0, CM_GAMCOR_MODE, 2);
+
+       current_mode = dpp30_get_gamcor_current(dpp_base);
+       if (current_mode == LUT_BYPASS || current_mode == LUT_RAM_A)
+               next_mode = LUT_RAM_B;
+       else
+               next_mode = LUT_RAM_A;
+
+       dpp6_power_on_gamcor_lut(dpp_base, true);
+       dpp3_configure_gamcor_lut(dpp_base, next_mode == LUT_RAM_A);
+
+       if (next_mode == LUT_RAM_B) {
+               gam_regs.start_cntl_b = REG(CM_GAMCOR_RAMB_START_CNTL_B);
+               gam_regs.start_cntl_g = REG(CM_GAMCOR_RAMB_START_CNTL_G);
+               gam_regs.start_cntl_r = REG(CM_GAMCOR_RAMB_START_CNTL_R);
+               gam_regs.start_slope_cntl_b = 
REG(CM_GAMCOR_RAMB_START_SLOPE_CNTL_B);
+               gam_regs.start_slope_cntl_g = 
REG(CM_GAMCOR_RAMB_START_SLOPE_CNTL_G);
+               gam_regs.start_slope_cntl_r = 
REG(CM_GAMCOR_RAMB_START_SLOPE_CNTL_R);
+               gam_regs.start_end_cntl1_b = REG(CM_GAMCOR_RAMB_END_CNTL1_B);
+               gam_regs.start_end_cntl2_b = REG(CM_GAMCOR_RAMB_END_CNTL2_B);
+               gam_regs.start_end_cntl1_g = REG(CM_GAMCOR_RAMB_END_CNTL1_G);
+               gam_regs.start_end_cntl2_g = REG(CM_GAMCOR_RAMB_END_CNTL2_G);
+               gam_regs.start_end_cntl1_r = REG(CM_GAMCOR_RAMB_END_CNTL1_R);
+               gam_regs.start_end_cntl2_r = REG(CM_GAMCOR_RAMB_END_CNTL2_R);
+               gam_regs.region_start = REG(CM_GAMCOR_RAMB_REGION_0_1);
+               gam_regs.region_end = REG(CM_GAMCOR_RAMB_REGION_32_33);
+               gam_regs.offset_b =  REG(CM_GAMCOR_RAMB_OFFSET_B);
+               gam_regs.offset_g =  REG(CM_GAMCOR_RAMB_OFFSET_G);
+               gam_regs.offset_r =  REG(CM_GAMCOR_RAMB_OFFSET_R);
+               gam_regs.start_base_cntl_b = 
REG(CM_GAMCOR_RAMB_START_BASE_CNTL_B);
+               gam_regs.start_base_cntl_g = 
REG(CM_GAMCOR_RAMB_START_BASE_CNTL_G);
+               gam_regs.start_base_cntl_r = 
REG(CM_GAMCOR_RAMB_START_BASE_CNTL_R);
+       } else {
+               gam_regs.start_cntl_b = REG(CM_GAMCOR_RAMA_START_CNTL_B);
+               gam_regs.start_cntl_g = REG(CM_GAMCOR_RAMA_START_CNTL_G);
+               gam_regs.start_cntl_r = REG(CM_GAMCOR_RAMA_START_CNTL_R);
+               gam_regs.start_slope_cntl_b = 
REG(CM_GAMCOR_RAMA_START_SLOPE_CNTL_B);
+               gam_regs.start_slope_cntl_g = 
REG(CM_GAMCOR_RAMA_START_SLOPE_CNTL_G);
+               gam_regs.start_slope_cntl_r = 
REG(CM_GAMCOR_RAMA_START_SLOPE_CNTL_R);
+               gam_regs.start_end_cntl1_b = REG(CM_GAMCOR_RAMA_END_CNTL1_B);
+               gam_regs.start_end_cntl2_b = REG(CM_GAMCOR_RAMA_END_CNTL2_B);
+               gam_regs.start_end_cntl1_g = REG(CM_GAMCOR_RAMA_END_CNTL1_G);
+               gam_regs.start_end_cntl2_g = REG(CM_GAMCOR_RAMA_END_CNTL2_G);
+               gam_regs.start_end_cntl1_r = REG(CM_GAMCOR_RAMA_END_CNTL1_R);
+               gam_regs.start_end_cntl2_r = REG(CM_GAMCOR_RAMA_END_CNTL2_R);
+               gam_regs.region_start = REG(CM_GAMCOR_RAMA_REGION_0_1);
+               gam_regs.region_end = REG(CM_GAMCOR_RAMA_REGION_32_33);
+               gam_regs.offset_b =  REG(CM_GAMCOR_RAMA_OFFSET_B);
+               gam_regs.offset_g =  REG(CM_GAMCOR_RAMA_OFFSET_G);
+               gam_regs.offset_r =  REG(CM_GAMCOR_RAMA_OFFSET_R);
+               gam_regs.start_base_cntl_b = 
REG(CM_GAMCOR_RAMA_START_BASE_CNTL_B);
+               gam_regs.start_base_cntl_g = 
REG(CM_GAMCOR_RAMA_START_BASE_CNTL_G);
+               gam_regs.start_base_cntl_r = 
REG(CM_GAMCOR_RAMA_START_BASE_CNTL_R);
+       }
+
+       //get register fields
+       dpp3_gamcor_reg_field(TO_DCN30_DPP(dpp_base), &gam_regs);
+
+       //program register set for LUTA/LUTB
+       cm_helper_program_gamcor_xfer_func(dpp_base->ctx, params, &gam_regs);
+
+       dpp3_program_gammcor_lut(dpp_base, params->rgb_resulted, 
params->hw_points_num,
+                                next_mode == LUT_RAM_A);
+
+       //select Gamma LUT to use for next frame
+       REG_UPDATE(CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT, next_mode == LUT_RAM_A 
? 0:1);
+
+       return true;
+}
-- 
2.53.0

Reply via email to