xref: /linux/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4 #include "reg_helper.h"
5 #include "dc.h"
6 #include "dcn60_mpc.h"
7 #include "dcn10/dcn10_cm_common.h"
8 #include "basics/conversion.h"
9 #include "mpc.h"
10 
11 #define REG(reg)\
12 	mpc60->mpc_regs->reg
13 
14 #define CTX \
15 	mpc60->base.ctx
16 
17 #undef FN
18 #define FN(reg_name, field_name) \
19 	mpc60->mpc_shift->field_name, mpc60->mpc_mask->field_name
20 
21 /*
22  * Insert DPP into MPC tree based on specified blending position.
23  * Only used for planes that are part of blending chain for OPP output
24  *
25  * Parameters:
26  * [in/out] mpc		- MPC context.
27  * [in/out] tree	- MPC tree structure that plane will be added to.
28  * [in]	blnd_cfg	- MPCC blending configuration for the new blending layer.
29  * [in]	sm_cfg		- MPCC stereo mix configuration for the new blending layer.
30  *			  stereo mix must disable for the very bottom layer of the tree config.
31  * [in]	insert_above_mpcc - Insert new plane above this MPCC.  If NULL, insert as bottom plane.
32  * [in]	dpp_id		- DPP instance for the plane to be added.
33  * [in]	mpcc_id		- The MPCC physical instance to use for blending.
34  *
35  * Return:  struct mpcc* - MPCC that was added.
36  */
37 static struct mpcc *mpc60_insert_plane(
38 	struct mpc *mpc,
39 	struct mpc_tree *tree,
40 	struct mpcc_blnd_cfg *blnd_cfg,
41 	struct mpcc_sm_cfg *sm_cfg,
42 	struct mpcc *insert_above_mpcc,
43 	int dpp_id,
44 	int mpcc_id)
45 {
46 	(void)sm_cfg;
47 	struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
48 	struct mpcc *new_mpcc = NULL;
49 
50 	/* sanity check parameters */
51 	ASSERT(mpcc_id < mpc60->num_mpcc);
52 	ASSERT(!(mpc60->mpcc_in_use_mask & 1 << mpcc_id));
53 
54 	if (insert_above_mpcc) {
55 		/* check insert_above_mpcc exist in tree->opp_list */
56 		struct mpcc *temp_mpcc = tree->opp_list;
57 
58 		if (temp_mpcc != insert_above_mpcc)
59 			while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
60 				temp_mpcc = temp_mpcc->mpcc_bot;
61 		if (temp_mpcc == NULL)
62 			return NULL;
63 	}
64 
65 	/* Get and update MPCC struct parameters */
66 	new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
67 	new_mpcc->dpp_id = dpp_id;
68 
69 	/* program mux and MPCC_MODE */
70 	if (insert_above_mpcc) {
71 		new_mpcc->mpcc_bot = insert_above_mpcc;
72 		REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id);
73 		REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
74 	} else {
75 		new_mpcc->mpcc_bot = NULL;
76 		REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
77 		REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY);
78 	}
79 	REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);
80 	REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id);
81 
82 	/* Configure VUPDATE lock set for this MPCC to map to the OPP */
83 	REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id);
84 
85 	/* update mpc tree mux setting */
86 	if (tree->opp_list == insert_above_mpcc) {
87 		/* insert the toppest mpcc */
88 		tree->opp_list = new_mpcc;
89 		REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
90 	} else {
91 		/* find insert position */
92 		struct mpcc *temp_mpcc = tree->opp_list;
93 
94 		while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
95 			temp_mpcc = temp_mpcc->mpcc_bot;
96 		if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) {
97 			REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id);
98 			temp_mpcc->mpcc_bot = new_mpcc;
99 			if (!insert_above_mpcc)
100 				REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
101 					MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
102 		}
103 	}
104 
105 	/* update the blending configuration */
106 	mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id);
107 
108 	/* mark this mpcc as in use */
109 	mpc60->mpcc_in_use_mask |= 1 << mpcc_id;
110 
111 	return new_mpcc;
112 }
113 
114 void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id,
115 	bool lut_bank_a, bool enabled, int mpcc_id)
116 {
117 	struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
118 
119 	switch (id) {
120 	case MCM_LUT_3DLUT:
121 		REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE,
122 			(!enabled) ? 0 :
123 			(lut_bank_a) ? 1 : 2);
124 		break;
125 
126 	case MCM_LUT_SHAPER:
127 		REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
128 			MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
129 
130 		REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
131 			MPC_RMCM_SHAPER_LUT_WRITE_SEL,
132 			lut_bank_a == true ? 0 : 1);
133 
134 		REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0,
135 			MPC_RMCM_SHAPER_LUT_INDEX, 0);
136 		break;
137 	default:
138 		break;
139 	}
140 }
141 
142 static void mpc60_program_lut_read_write_control(struct mpc *mpc,
143 		const enum MCM_LUT_ID id,
144 		const bool lut_bank_a,
145 		const unsigned int bit_depth,
146 		const int mpcc_id)
147 {
148 	struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
149 
150 	switch (id) {
151 	case MCM_LUT_3DLUT:
152 		mpc32_select_3dlut_ram_mask(mpc, 0xf, mpcc_id);
153 		REG_UPDATE(MPCC_MCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
154 				MPCC_MCM_3DLUT_30BIT_EN, (bit_depth == 10) ? 1 : 0);
155 		break;
156 	case MCM_LUT_SHAPER:
157 		mpc32_configure_shaper_lut(mpc, lut_bank_a, mpcc_id);
158 		break;
159 	case MCM_LUT_1DLUT:
160 		mpc32_configure_post1dlut(mpc, lut_bank_a, mpcc_id);
161 		break;
162 	}
163 }
164 
165 static uint32_t mpc60_cm_lut_size_to_3dlut_size(const enum dc_cm_lut_size cm_size)
166 {
167 	uint32_t size = 0;
168 
169 	switch (cm_size) {
170 	case CM_LUT_SIZE_999:
171 		size = 1;
172 		break;
173 	case CM_LUT_SIZE_171717:
174 		size = 0;
175 		break;
176 	default:
177 		/* invalid LUT size for MCM */
178 		ASSERT(false);
179 		size = 0;
180 		break;
181 	}
182 
183 	return size;
184 }
185 
186 static void mpc60_program_lut_mode(
187 		struct mpc *mpc,
188 		const enum MCM_LUT_ID id,
189 		const bool enable,
190 		const bool lut_bank_a,
191 		const enum dc_cm_lut_size size,
192 		const int mpcc_id)
193 {
194 	uint32_t lut_size;
195 	struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
196 
197 	switch (id) {
198 	case MCM_LUT_3DLUT:
199 		if (enable) {
200 			lut_size = mpc60_cm_lut_size_to_3dlut_size(size);
201 			REG_UPDATE_2(MPCC_MCM_3DLUT_MODE[mpcc_id],
202 					MPCC_MCM_3DLUT_MODE, 1,
203 					MPCC_MCM_3DLUT_SIZE, lut_size);
204 		} else {
205 			if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
206 				mpc32_power_on_shaper_3dlut(mpc, mpcc_id, false);
207 			REG_UPDATE(MPCC_MCM_3DLUT_MODE[mpcc_id], MPCC_MCM_3DLUT_MODE, 0);
208 		}
209 		break;
210 	case MCM_LUT_SHAPER:
211 		if (enable) {
212 			REG_UPDATE(MPCC_MCM_SHAPER_CONTROL[mpcc_id], MPCC_MCM_SHAPER_LUT_MODE, lut_bank_a ? 1 : 2);
213 		} else {
214 			if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
215 				mpc32_power_on_shaper_3dlut(mpc, mpcc_id, false);
216 			REG_UPDATE(MPCC_MCM_SHAPER_CONTROL[mpcc_id], MPCC_MCM_SHAPER_LUT_MODE, 0);
217 		}
218 		break;
219 	case MCM_LUT_1DLUT:
220 		if (enable) {
221 			REG_UPDATE(MPCC_MCM_1DLUT_CONTROL[mpcc_id],
222 					MPCC_MCM_1DLUT_MODE, 2);
223 		} else {
224 			if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
225 				mpc32_power_on_blnd_lut(mpc, mpcc_id, false);
226 			REG_UPDATE(MPCC_MCM_1DLUT_CONTROL[mpcc_id],
227 					MPCC_MCM_1DLUT_MODE, 0);
228 		}
229 		REG_UPDATE(MPCC_MCM_1DLUT_CONTROL[mpcc_id],
230 				MPCC_MCM_1DLUT_SELECT, lut_bank_a ? 0 : 1);
231 		break;
232 	}
233 }
234 
235 static bool mpc60_program_3dlut(
236 	struct mpc *mpc,
237 	const struct tetrahedral_params *params,
238 	int mpcc_id)
239 {
240 	union mcm_lut_params lut_params = { 0 };
241 	lut_params.lut3d = params;
242 
243 	mpc60_program_lut_read_write_control(mpc,
244 			MCM_LUT_3DLUT,
245 			true,
246 			params->use_12bits ? 12 : 10,
247 			mpcc_id);
248 	mpc401_populate_lut(mpc, MCM_LUT_3DLUT, &lut_params, true, mpcc_id);
249 	mpc60_program_lut_mode(mpc,
250 		MCM_LUT_3DLUT,
251 		true,
252 		true,
253 		params->use_tetrahedral_9 ? CM_LUT_SIZE_999 : CM_LUT_SIZE_171717,
254 		mpcc_id);
255 
256 	return true;
257 }
258 
259 static const struct mpc_funcs dcn60_mpc_funcs = {
260 	.read_mpcc_state = mpc1_read_mpcc_state,
261 	.insert_plane = mpc60_insert_plane,
262 	.remove_mpcc = mpc1_remove_mpcc,
263 	.mpc_init = mpc32_mpc_init,
264 	.mpc_init_single_inst = mpc3_mpc_init_single_inst,
265 	.update_blending = mpc42_update_blending,
266 	.cursor_lock = mpc1_cursor_lock,
267 	.get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
268 	.wait_for_idle = mpc2_assert_idle_mpcc,
269 	.assert_mpcc_idle_before_connect = mpc2_assert_mpcc_idle_before_connect,
270 	.init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
271 	.set_denorm = mpc3_set_denorm,
272 	.set_denorm_clamp = mpc3_set_denorm_clamp,
273 	.set_output_csc = mpc3_set_output_csc,
274 	.set_ocsc_default = mpc3_set_ocsc_default,
275 	.set_output_gamma = mpc3_set_output_gamma,
276 	.set_gamut_remap = mpc401_set_gamut_remap,
277 	.program_shaper = mpc32_program_shaper,
278 	.program_3dlut = mpc60_program_3dlut,
279 	.program_1dlut = mpc32_program_post1dlut,
280 	.power_on_mpc_mem_pwr = mpc3_power_on_ogam_lut,
281 	.get_mpc_out_mux = mpc1_get_mpc_out_mux,
282 	.mpc_read_reg_state = mpc3_read_reg_state,
283 	.set_bg_color = mpc1_set_bg_color,
284 	.set_movable_cm_location = mpc401_set_movable_cm_location,
285 	.update_3dlut_fast_load_select = mpc401_update_3dlut_fast_load_select,
286 	.get_3dlut_fast_load_status = mpc401_get_3dlut_fast_load_status,
287 	.populate_lut = mpc401_populate_lut,
288 	.program_lut_read_write_control = mpc60_program_lut_read_write_control,
289 	.program_lut_mode = mpc60_program_lut_mode,
290 	.get_lut_mode = mpc401_get_lut_mode,
291 	.rmcm = {
292 		.enable_3dlut_fl = mpc42_enable_3dlut_fl,
293 		.update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select,
294 		.program_lut_read_write_control = mpc60_program_rmcm_lut_read_write_control,
295 		.program_lut_mode = mpc42_program_lut_mode,
296 		.program_3dlut_size = mpc42_program_rmcm_3dlut_size,
297 		.program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale,
298 		.program_bit_depth = mpc42_program_rmcm_bit_depth,
299 		.power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut,
300 		.populate_lut = mpc42_populate_rmcm_lut,
301 		.get_3dlut_mode = mpc42_get_rmcm_3dlut_mode,
302 	},
303 };
304 
305 void dcn60_mpc_construct(struct dcn60_mpc *mpc60,
306 	struct dc_context *ctx,
307 	const struct dcn60_mpc_registers *mpc_regs,
308 	const struct dcn60_mpc_shift *mpc_shift,
309 	const struct dcn60_mpc_mask *mpc_mask,
310 	int num_mpcc,
311 	int num_rmu)
312 {
313 	int i;
314 
315 	mpc60->base.ctx = ctx;
316 
317 	mpc60->base.funcs = &dcn60_mpc_funcs;
318 
319 	mpc60->mpc_regs = mpc_regs;
320 	mpc60->mpc_shift = mpc_shift;
321 	mpc60->mpc_mask = mpc_mask;
322 
323 	mpc60->mpcc_in_use_mask = 0;
324 	mpc60->num_mpcc = num_mpcc;
325 	mpc60->num_rmu = num_rmu;
326 
327 	for (i = 0; i < MAX_MPCC; i++)
328 		mpc42_init_mpcc(&mpc60->base.mpcc_array[i], i);
329 }
330 
331