xref: /linux/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp_dscl.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4 
5 #include "dm_services.h"
6 
7 #include "core_types.h"
8 
9 #include "reg_helper.h"
10 #include "dcn60/dcn60_dpp.h"
11 #include "basics/conversion.h"
12 
13 #define REG(reg)\
14 	dpp->tf_regs->reg
15 
16 #define CTX \
17 	dpp->base.ctx
18 
19 #undef FN
20 #define FN(reg_name, field_name) \
21 	dpp->tf_shift->field_name, dpp->tf_mask->field_name
22 
23 static void dpp60_power_on_dscl(struct dpp *dpp_base, bool power_on)
24 {
25 	struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
26 
27 	if (power_on) {
28 		REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0);
29 		REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_DIS, 1);
30 		REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 100);
31 	} else {
32 		if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) {
33 			dpp->base.ctx->dc->optimized_required = true;
34 			dpp->base.deferred_reg_writes.bits.disable_dscl = true;
35 		}
36 	}
37 }
38 
39 void dpp60_dscl_set_lb(
40 	struct dcn60_dpp *dpp,
41 	const struct line_buffer_params *lb_params,
42 	enum lb_memory_config mem_size_config)
43 {
44 	/* LB */
45 	REG_SET(LB_DATA_FORMAT, 0,
46 			LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */
47 
48 	REG_SET_2(LB_MEMORY_CTRL, 0,
49 		MEMORY_CONFIG, mem_size_config,
50 		LB_MAX_PARTITIONS, dpp->base.caps->max_lb_partitions);
51 }
52 
53 void dpp60_dscl_set_manual_ratio_init(
54 	struct dcn60_dpp *dpp, const struct scaler_data *data)
55 {
56 	uint32_t init_frac = 0;
57 	uint32_t init_int = 0;
58 	if ((dpp->base.ctx->dc->config.use_spl) && (!dpp->base.ctx->dc->debug.disable_spl)) {
59 		REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
60 			SCL_H_SCALE_RATIO, data->dscl_prog_data.ratios.h_scale_ratio);
61 
62 		REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
63 			SCL_V_SCALE_RATIO, data->dscl_prog_data.ratios.v_scale_ratio);
64 
65 		REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
66 			SCL_H_SCALE_RATIO_C, data->dscl_prog_data.ratios.h_scale_ratio_c);
67 
68 		REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
69 			SCL_V_SCALE_RATIO_C, data->dscl_prog_data.ratios.v_scale_ratio_c);
70 
71 		REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
72 			SCL_H_INIT_FRAC, data->dscl_prog_data.init.h_filter_init_frac,
73 			SCL_H_INIT_INT, data->dscl_prog_data.init.h_filter_init_int);
74 
75 		REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0,
76 			SCL_H_INIT_FRAC_C, data->dscl_prog_data.init.h_filter_init_frac_c,
77 			SCL_H_INIT_INT_C, data->dscl_prog_data.init.h_filter_init_int_c);
78 
79 		REG_SET_2(SCL_VERT_FILTER_INIT, 0,
80 			SCL_V_INIT_FRAC, data->dscl_prog_data.init.v_filter_init_frac,
81 			SCL_V_INIT_INT, data->dscl_prog_data.init.v_filter_init_int);
82 
83 		REG_SET_2(SCL_VERT_FILTER_INIT_C, 0,
84 			SCL_V_INIT_FRAC_C, data->dscl_prog_data.init.v_filter_init_frac_c,
85 			SCL_V_INIT_INT_C, data->dscl_prog_data.init.v_filter_init_int_c);
86 
87 		return;
88 	}
89 	REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
90 		SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5);
91 
92 	REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
93 		SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5);
94 
95 	REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
96 		SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5);
97 
98 	REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
99 		SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5);
100 
101 	/*
102 	 * 0.24 format for fraction, first five bits zeroed
103 	 */
104 	init_frac = dc_fixpt_u0d19(data->inits.h) << 5;
105 	init_int = dc_fixpt_floor(data->inits.h);
106 	REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
107 		SCL_H_INIT_FRAC, init_frac,
108 		SCL_H_INIT_INT, init_int);
109 
110 	init_frac = dc_fixpt_u0d19(data->inits.h_c) << 5;
111 	init_int = dc_fixpt_floor(data->inits.h_c);
112 	REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0,
113 		SCL_H_INIT_FRAC_C, init_frac,
114 		SCL_H_INIT_INT_C, init_int);
115 
116 	init_frac = dc_fixpt_u0d19(data->inits.v) << 5;
117 	init_int = dc_fixpt_floor(data->inits.v);
118 	REG_SET_2(SCL_VERT_FILTER_INIT, 0,
119 		SCL_V_INIT_FRAC, init_frac,
120 		SCL_V_INIT_INT, init_int);
121 
122 	init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5;
123 	init_int = dc_fixpt_floor(data->inits.v_c);
124 	REG_SET_2(SCL_VERT_FILTER_INIT_C, 0,
125 		SCL_V_INIT_FRAC_C, init_frac,
126 		SCL_V_INIT_INT_C, init_int);
127 }
128 
129 /**
130  * dpp60_dscl_set_scaler_manual_scale - Manually program scaler and line buffer
131  *
132  * @dpp_base: High level DPP struct
133  * @scl_data: scalaer_data info
134  *
135  * This is the primary function to program scaler and line buffer in manual
136  * scaling mode. To execute the required operations for manual scale, we need
137  * to disable AutoCal first.
138  */
139 void dpp60_dscl_set_scaler_manual_scale(struct dpp *dpp_base,
140 				       const struct scaler_data *scl_data)
141 {
142 	enum lb_memory_config lb_config;
143 	struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
144 	struct dcn401_dpp *dpp401 = TO_DCN401_DPP(dpp_base);
145 	const struct rect *rect = &scl_data->recout;
146 	uint32_t mpc_width = scl_data->h_active;
147 	uint32_t mpc_height = scl_data->v_active;
148 	uint32_t v_num_taps = scl_data->taps.v_taps - 1;
149 	uint32_t v_num_taps_c = scl_data->taps.v_taps_c - 1;
150 	uint32_t h_num_taps = scl_data->taps.h_taps - 1;
151 	uint32_t h_num_taps_c = scl_data->taps.h_taps_c - 1;
152 	enum dcn401_dscl_mode_sel dscl_mode = dpp401_dscl_get_dscl_mode(
153 			dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale);
154 	bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN
155 				&& scl_data->format <= PIXEL_FORMAT_VIDEO_END;
156 	bool program_isharp_1dlut = false;
157 	bool bs_coeffs_updated = false;
158 
159 	if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0)
160 		return;
161 
162 	PERF_TRACE();
163 
164 	/* If only sharpness has changed, then only update 1dlut, then return */
165 	if (scl_data->dscl_prog_data.isharp_en &&
166 		(dpp->scl_data.dscl_prog_data.sharpness_level
167 		!= scl_data->dscl_prog_data.sharpness_level)) {
168 		/* ISHARP_DELTA_LUT */
169 		dpp401_dscl_set_isharp_filter(dpp401, scl_data->dscl_prog_data.isharp_delta);
170 		dpp->scl_data.dscl_prog_data.sharpness_level = scl_data->dscl_prog_data.sharpness_level;
171 		memcpy(dpp->scl_data.dscl_prog_data.isharp_delta, scl_data->dscl_prog_data.isharp_delta,
172 			sizeof(uint32_t) * ISHARP_LUT_TABLE_SIZE);
173 
174 		if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0)
175 			return;
176 		program_isharp_1dlut = true;
177 	}
178 
179 	dpp->scl_data = *scl_data;
180 
181 	if ((dpp->base.ctx->dc->config.use_spl) && (!dpp->base.ctx->dc->debug.disable_spl)) {
182 		dscl_mode = (enum dcn401_dscl_mode_sel) scl_data->dscl_prog_data.dscl_mode;
183 		rect = (struct rect *)&scl_data->dscl_prog_data.recout;
184 		mpc_width = scl_data->dscl_prog_data.mpc_size.width;
185 		mpc_height = scl_data->dscl_prog_data.mpc_size.height;
186 		v_num_taps = scl_data->dscl_prog_data.taps.v_taps;
187 		v_num_taps_c = scl_data->dscl_prog_data.taps.v_taps_c;
188 		h_num_taps = scl_data->dscl_prog_data.taps.h_taps;
189 		h_num_taps_c = scl_data->dscl_prog_data.taps.h_taps_c;
190 	}
191 
192 	/* Unconditionally power on DSCL - can be in light sleep otherwise. */
193 	if (dscl_mode != DCN401_DSCL_MODE_DSCL_BYPASS)
194 		dpp60_power_on_dscl(dpp_base, true);
195 
196 	/* Autocal off */
197 	REG_SET_4(DSCL_AUTOCAL, 0,
198 		AUTOCAL_MODE, 0,
199 		AUTOCAL_FRAC_MODE, 0,
200 		AUTOCAL_NUM_PIPE, 0,
201 		AUTOCAL_PIPE_ID, 0);
202 
203 	/*clean scaler boundary mode when Autocal off*/
204 	REG_SET(DSCL_CONTROL, 0,
205 		SCL_BOUNDARY_MODE, 0);
206 
207 	/* Recout */
208 	dpp401_dscl_set_recout(dpp401, rect);
209 
210 	/* MPC Size */
211 	REG_SET_2(MPC_SIZE, 0,
212 		/* Number of horizontal pixels of MPC */
213 			 MPC_WIDTH, mpc_width,
214 		/* Number of vertical lines of MPC */
215 			 MPC_HEIGHT, mpc_height);
216 
217 	/* SCL mode */
218 	REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode);
219 
220 	if (dscl_mode == DCN401_DSCL_MODE_DSCL_BYPASS) {
221 		dpp60_power_on_dscl(dpp_base, false);
222 		return;
223 	}
224 
225 	/* LB */
226 	lb_config =  dpp401_dscl_find_lb_memory_config(dpp401, scl_data);
227 	dpp60_dscl_set_lb(dpp, &scl_data->lb_params, lb_config);
228 
229 	if (dscl_mode == DCN401_DSCL_MODE_SCALING_444_BYPASS) {
230 		if (dpp->base.ctx->dc->config.prefer_easf)
231 			dpp401_dscl_disable_easf(dpp_base, scl_data);
232 		dpp401_dscl_program_isharp(dpp_base, scl_data, program_isharp_1dlut, &bs_coeffs_updated);
233 		return;
234 	}
235 
236 	/* Black color */
237 	if (ycbcr)
238 		REG_SET_2(SCL_BLACK_COLOR, 0,
239 				SCL_BLACK_COLOR_RGB_Y, BLACK_OFFSET_RGB_Y,
240 				SCL_BLACK_COLOR_CBCR, BLACK_OFFSET_CBCR);
241 	else
242 		REG_SET_2(SCL_BLACK_COLOR, 0,
243 				SCL_BLACK_COLOR_RGB_Y, BLACK_OFFSET_RGB_Y,
244 				SCL_BLACK_COLOR_CBCR, BLACK_OFFSET_RGB_Y);
245 
246 	/* Manually calculate scale ratio and init values */
247 	dpp60_dscl_set_manual_ratio_init(dpp, scl_data);
248 
249 	/* HTaps/VTaps */
250 	REG_SET_4(SCL_TAP_CONTROL, 0,
251 		SCL_V_NUM_TAPS, v_num_taps,
252 		SCL_H_NUM_TAPS, h_num_taps,
253 		SCL_V_NUM_TAPS_C, v_num_taps_c,
254 		SCL_H_NUM_TAPS_C, h_num_taps_c);
255 
256 	/* ISharp configuration
257 	 * - B&S coeffs are written to same coeff RAM as WB scaler coeffs
258 	 * - coeff RAM toggle is in EASF programming
259 	 * - if we are only programming B&S coeffs, then need to reprogram
260 	 *   WB scaler coeffs and toggle coeff RAM together
261 	 */
262 	//if (dpp->base.ctx->dc->config.prefer_easf)
263 	dpp401_dscl_program_isharp(dpp_base, scl_data, program_isharp_1dlut, &bs_coeffs_updated);
264 
265 	dpp401_dscl_set_scl_filter(dpp401, scl_data, ycbcr, bs_coeffs_updated);
266 	/* Edge adaptive scaler function configuration */
267 	if (dpp->base.ctx->dc->config.prefer_easf)
268 		dpp401_dscl_program_easf(dpp_base, scl_data);
269 	PERF_TRACE();
270 }
271 
272 /**
273  * dpp60_dscl_program_upsp - Manually program UPSP registers
274  *
275  * @dpp_base: High level DPP struct
276  * @dscl_prog_data: dscl_prog_data info
277  */
278 void dpp60_dscl_program_upsp(struct dpp *dpp_base,
279 		const struct dscl_prog_data *dscl_prog_data)
280 {
281 	struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
282 
283 	REG_SET_8(UPSP_MODE, 0,
284 			UPSP_MODE, dscl_prog_data->upsp_mode,
285 			UPSP_V_NUM_TAPS, dscl_prog_data->upsp_v_num_taps,
286 			UPSP_V_INIT_INT, dscl_prog_data->upsp_v_init_int,
287 			UPSP_V_INIT_FRAC, dscl_prog_data->upsp_v_init_frac,
288 			UPSP_H_NUM_TAPS, dscl_prog_data->upsp_h_num_taps,
289 			UPSP_H_INIT_INT, dscl_prog_data->upsp_h_init_int,
290 			UPSP_H_INIT_FRAC, dscl_prog_data->upsp_h_init_frac,
291 			UPSP_BOUNDARY_MODE, dscl_prog_data->upsp_boundary_mode);
292 	REG_SET_4(UPSP_V_COEF_P0, 0,
293 			UPSP_V_COEF_TAP0_P0, dscl_prog_data->upsp_v_coef_tap0_p0,
294 			UPSP_V_COEF_TAP1_P0, dscl_prog_data->upsp_v_coef_tap1_p0,
295 			UPSP_V_COEF_TAP2_P0, dscl_prog_data->upsp_v_coef_tap2_p0,
296 			UPSP_V_COEF_TAP3_P0, dscl_prog_data->upsp_v_coef_tap3_p0);
297 	REG_SET_4(UPSP_V_COEF_P1, 0,
298 			UPSP_V_COEF_TAP0_P1, dscl_prog_data->upsp_v_coef_tap0_p1,
299 			UPSP_V_COEF_TAP1_P1, dscl_prog_data->upsp_v_coef_tap1_p1,
300 			UPSP_V_COEF_TAP2_P1, dscl_prog_data->upsp_v_coef_tap2_p1,
301 			UPSP_V_COEF_TAP3_P1, dscl_prog_data->upsp_v_coef_tap3_p1);
302 	REG_SET_4(UPSP_H_COEF_P0, 0,
303 			UPSP_H_COEF_TAP0_P0, dscl_prog_data->upsp_h_coef_tap0_p0,
304 			UPSP_H_COEF_TAP1_P0, dscl_prog_data->upsp_h_coef_tap1_p0,
305 			UPSP_H_COEF_TAP2_P0, dscl_prog_data->upsp_h_coef_tap2_p0,
306 			UPSP_H_COEF_TAP3_P0, dscl_prog_data->upsp_h_coef_tap3_p0);
307 	REG_SET_4(UPSP_H_COEF_P1, 0,
308 			UPSP_H_COEF_TAP0_P1, dscl_prog_data->upsp_h_coef_tap0_p1,
309 			UPSP_H_COEF_TAP1_P1, dscl_prog_data->upsp_h_coef_tap1_p1,
310 			UPSP_H_COEF_TAP2_P1, dscl_prog_data->upsp_h_coef_tap2_p1,
311 			UPSP_H_COEF_TAP3_P1, dscl_prog_data->upsp_h_coef_tap3_p1);
312 	REG_SET_2(UPSP_CLAMP, 0,
313 			UPSP_CLAMP_MAX, dscl_prog_data->upsp_clamp_max,
314 			UPSP_CLAMP_MIN, dscl_prog_data->upsp_clamp_min);
315 }
316