[PATCH 16/31] drm/amd/display: Implement input gamma LUT

Harry Wentland harry.wentland at amd.com
Tue May 23 14:08:54 UTC 2017


From: "Leo (Sunpeng) Li" <sunpeng.li at amd.com>

1. Implemented dcn10_ipp_program_input_lut(), following the existing
   interface.
2. Added missing registers as needed
3. Change to REG_GET for *ram_select() funcs.
4. Removed gamma table init from DiagsDM::make_surface() for resolving
   CRC errors. Reason: Legacy LUT will be deprecated soon for Raven in
   favor of degamma/regamma.

Change-Id: I4c25bd0b70603d5aeae5b171b83e739e4b1382c5
Signed-off-by: Leo (Sunpeng) Li <sunpeng.li at amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng at amd.com>
Acked-by: Harry Wentland <Harry.Wentland at amd.com>
---
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  6 +-
 drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c   | 82 +++++++++++++++++++++-
 drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h   | 22 ++++++
 3 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 28b47bed72cf..62a77f48d437 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -29,9 +29,9 @@
 #include "core_types.h"
 #include "core_status.h"
 #include "resource.h"
-#include "hw_sequencer.h"
 #include "dcn10_hw_sequencer.h"
 #include "dce110/dce110_hw_sequencer.h"
+#include "dce/dce_hwseq.h"
 #include "abm.h"
 
 #include "dcn10/dcn10_transform.h"
@@ -952,6 +952,10 @@ static bool dcn10_set_input_transfer_func(
 	if (surface->public.in_transfer_func)
 		tf = DC_TRANSFER_FUNC_TO_CORE(surface->public.in_transfer_func);
 
+	if (surface->public.gamma_correction && dce_use_lut(surface))
+	    ipp->funcs->ipp_program_input_lut(ipp,
+			    surface->public.gamma_correction);
+
 	if (tf == NULL)
 		ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
 	else if (tf->public.type == TF_TYPE_PREDEFINED) {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c
index 082c98c11293..1e7a55d9e9ec 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c
@@ -814,7 +814,9 @@ static bool dcn10_degamma_ram_inuse(struct input_pixel_processor *ipp,
 	uint32_t status_reg = 0;
 	struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
 
-	status_reg = (REG_READ(CM_IGAM_LUT_RW_CONTROL) & 0x0F00) >>16;
+	REG_GET(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS,
+			&status_reg);
+
 	if (status_reg == 9) {
 		*ram_a_inuse = true;
 		ret = true;
@@ -825,6 +827,28 @@ static bool dcn10_degamma_ram_inuse(struct input_pixel_processor *ipp,
 	return ret;
 }
 
+static bool dcn10_ingamma_ram_inuse(struct input_pixel_processor *ipp,
+							bool *ram_a_inuse)
+{
+	bool in_use = false;
+	uint32_t status_reg = 0;
+	struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
+
+	REG_GET(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS,
+				&status_reg);
+
+	// 1 => IGAM_RAMA, 3 => IGAM_RAMA & DGAM_ROMA, 4 => IGAM_RAMA & DGAM_ROMB
+	if (status_reg == 1 || status_reg == 3 || status_reg == 4) {
+		*ram_a_inuse = true;
+		in_use = true;
+	// 2 => IGAM_RAMB, 5 => IGAM_RAMB & DGAM_ROMA, 6 => IGAM_RAMB & DGAM_ROMB
+	} else if (status_reg == 2 || status_reg == 5 || status_reg == 6) {
+		*ram_a_inuse = false;
+		in_use = true;
+	}
+	return in_use;
+}
+
 static void dcn10_degamma_ram_select(struct input_pixel_processor *ipp,
 							bool use_ram_a)
 {
@@ -855,6 +879,61 @@ static void dcn10_ipp_set_degamma_pwl(struct input_pixel_processor *ipp,
 	dcn10_degamma_ram_select(ipp, !is_ram_a);
 }
 
+/*
+ * Input gamma LUT currently supports 256 values only. This means input color
+ * can have a maximum of 8 bits per channel (= 256 possible values) in order to
+ * have a one-to-one mapping with the LUT. Truncation will occur with color
+ * values greater than 8 bits.
+ *
+ * In the future, this function should support additional input gamma methods,
+ * such as piecewise linear mapping, and input gamma bypass.
+ */
+void dcn10_ipp_program_input_lut(
+		struct input_pixel_processor *ipp,
+		const struct dc_gamma *gamma)
+{
+	int i;
+	struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
+	bool rama_occupied = false;
+	uint32_t ram_num;
+	// Power on LUT memory.
+	REG_SET(CM_MEM_PWR_CTRL, 0, SHARED_MEM_PWR_DIS, 1);
+	dcn10_ipp_enable_cm_block(ipp);
+	// Determine whether to use RAM A or RAM B
+	dcn10_ingamma_ram_inuse(ipp, &rama_occupied);
+	if (!rama_occupied)
+		REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, 0);
+	else
+		REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, 1);
+	// RW mode is 256-entry LUT
+	REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_RW_MODE, 0);
+	// IGAM Input format should be 8 bits per channel.
+	REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 0);
+	// Do not mask any R,G,B values
+	REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_WRITE_EN_MASK, 7);
+	// LUT-256, unsigned, integer, new u0.12 format
+	REG_UPDATE_3(
+		CM_IGAM_CONTROL,
+		CM_IGAM_LUT_FORMAT_R, 3,
+		CM_IGAM_LUT_FORMAT_G, 3,
+		CM_IGAM_LUT_FORMAT_B, 3);
+	// Start at index 0 of IGAM LUT
+	REG_UPDATE(CM_IGAM_LUT_RW_INDEX, CM_IGAM_LUT_RW_INDEX, 0);
+	for (i = 0; i < INPUT_LUT_ENTRIES; i++) {
+		REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR,
+					gamma->red[i]);
+		REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR,
+					gamma->green[i]);
+		REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR,
+					gamma->blue[i]);
+	}
+	// Power off LUT memory
+	REG_SET(CM_MEM_PWR_CTRL, 0, SHARED_MEM_PWR_DIS, 0);
+	// Enable IGAM LUT on ram we just wrote to. 2 => RAMA, 3 => RAMB
+	REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, rama_occupied ? 3 : 2);
+	REG_GET(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, &ram_num);
+}
+
 /*****************************************/
 /* Constructor, Destructor               */
 /*****************************************/
@@ -869,6 +948,7 @@ static const struct ipp_funcs dcn10_ipp_funcs = {
 	.ipp_cursor_set_attributes	= dcn10_cursor_set_attributes,
 	.ipp_cursor_set_position	= dcn10_cursor_set_position,
 	.ipp_set_degamma		= dcn10_ipp_set_degamma,
+	.ipp_program_input_lut 		= dcn10_ipp_program_input_lut,
 	.ipp_full_bypass		= dcn10_ipp_full_bypass,
 	.ipp_setup			= dcn10_ipp_cnv_setup,
 	.ipp_program_degamma_pwl	= dcn10_ipp_set_degamma_pwl,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h
index a4ea4e774c72..511993519740 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h
@@ -87,6 +87,8 @@
 	SRI(CM_DGAM_RAMA_REGION_14_15, CM, id), \
 	SRI(CM_MEM_PWR_CTRL, CM, id), \
 	SRI(CM_IGAM_LUT_RW_CONTROL, CM, id), \
+	SRI(CM_IGAM_LUT_RW_INDEX, CM, id), \
+	SRI(CM_IGAM_LUT_SEQ_COLOR, CM, id), \
 	SRI(CM_DGAM_LUT_WRITE_EN_MASK, CM, id), \
 	SRI(CM_DGAM_LUT_INDEX, CM, id), \
 	SRI(CM_DGAM_LUT_DATA, CM, id), \
@@ -238,7 +240,13 @@
 	IPP_SF(CM0_CM_DGAM_RAMA_REGION_14_15, CM_DGAM_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh), \
 	IPP_SF(CM0_CM_DGAM_RAMA_REGION_14_15, CM_DGAM_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh), \
 	IPP_SF(CM0_CM_MEM_PWR_CTRL, SHARED_MEM_PWR_DIS, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS, mask_sh), \
 	IPP_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_HOST_EN, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_RW_MODE, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_WRITE_EN_MASK, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_LUT_RW_INDEX, CM_IGAM_LUT_RW_INDEX, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_LUT_SEQ_COLOR, CM_IGAM_LUT_SEQ_COLOR, mask_sh), \
 	IPP_SF(CM0_CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_EN_MASK, mask_sh), \
 	IPP_SF(CM0_CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_SEL, mask_sh), \
 	IPP_SF(CM0_CM_DGAM_LUT_INDEX, CM_DGAM_LUT_INDEX, mask_sh), \
@@ -251,6 +259,9 @@
 	IPP_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_EXPANSION_MODE, mask_sh), \
 	IPP_SF(CM0_CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, mask_sh), \
 	IPP_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_FORMAT_R, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_FORMAT_G, mask_sh), \
+	IPP_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_FORMAT_B, mask_sh), \
 	IPP_SF(HUBPREQ0_CURSOR_SETTINS, CURSOR0_DST_Y_OFFSET, mask_sh), \
 	IPP_SF(HUBPREQ0_CURSOR_SETTINS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \
 	IPP_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_MODE, mask_sh), \
@@ -404,7 +415,16 @@
 	type CM_DGAM_RAMA_EXP_REGION15_LUT_OFFSET; \
 	type CM_DGAM_RAMA_EXP_REGION15_NUM_SEGMENTS; \
 	type SHARED_MEM_PWR_DIS; \
+	type CM_IGAM_LUT_FORMAT_R; \
+	type CM_IGAM_LUT_FORMAT_G; \
+	type CM_IGAM_LUT_FORMAT_B; \
 	type CM_IGAM_LUT_HOST_EN; \
+	type CM_IGAM_LUT_RW_INDEX; \
+	type CM_IGAM_LUT_RW_MODE; \
+	type CM_IGAM_LUT_WRITE_EN_MASK; \
+	type CM_IGAM_LUT_SEL; \
+	type CM_IGAM_LUT_SEQ_COLOR; \
+	type CM_IGAM_DGAM_CONFIG_STATUS; \
 	type CM_DGAM_LUT_WRITE_EN_MASK; \
 	type CM_DGAM_LUT_WRITE_SEL; \
 	type CM_DGAM_LUT_INDEX; \
@@ -507,6 +527,8 @@ struct dcn10_ipp_registers {
 	uint32_t CM_DGAM_RAMA_REGION_14_15;
 	uint32_t CM_MEM_PWR_CTRL;
 	uint32_t CM_IGAM_LUT_RW_CONTROL;
+	uint32_t CM_IGAM_LUT_RW_INDEX;
+	uint32_t CM_IGAM_LUT_SEQ_COLOR;
 	uint32_t CM_DGAM_LUT_WRITE_EN_MASK;
 	uint32_t CM_DGAM_LUT_INDEX;
 	uint32_t CM_DGAM_LUT_DATA;
-- 
2.11.0



More information about the amd-gfx mailing list