xref: /linux/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c (revision 1fc5a74b108fc90951890ec513ac81869f5eaff1)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2026 Advanced Micro Devices, Inc.
4 
5 #include "reg_helper.h"
6 #include "core_types.h"
7 #include "dcn35/dcn35_dccg.h"
8 #include "dcn42_dccg.h"
9 #include "dcn20/dcn20_dccg.h"
10 
11 #define TO_DCN_DCCG(dccg)\
12 	container_of(dccg, struct dcn_dccg, base)
13 
14 #define REG(reg) \
15 	(dccg_dcn->regs->reg)
16 
17 #undef FN
18 #define FN(reg_name, field_name) \
19 	dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
20 
21 #define CTX \
22 	dccg_dcn->base.ctx
23 #define DC_LOGGER \
24 	dccg->ctx->logger
25 
dccg42_otg_add_pixel(struct dccg * dccg,uint32_t otg_inst)26 void dccg42_otg_add_pixel(struct dccg *dccg,
27 		uint32_t otg_inst)
28 {
29 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
30 
31 	switch (otg_inst) {
32 	case 0:
33 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
34 				OTG0_ADD_PIXEL, 1);
35 		break;
36 	case 1:
37 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
38 				OTG1_ADD_PIXEL, 1);
39 		break;
40 	case 2:
41 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
42 				OTG2_ADD_PIXEL, 1);
43 		break;
44 	case 3:
45 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
46 				OTG3_ADD_PIXEL, 1);
47 		break;
48 	default:
49 		ASSERT(0);
50 	}
51 }
52 
dccg42_otg_drop_pixel(struct dccg * dccg,uint32_t otg_inst)53 void dccg42_otg_drop_pixel(struct dccg *dccg,
54 		uint32_t otg_inst)
55 {
56 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
57 
58 	switch (otg_inst) {
59 	case 0:
60 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
61 				OTG0_DROP_PIXEL, 1);
62 		break;
63 	case 1:
64 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
65 				OTG1_DROP_PIXEL, 1);
66 		break;
67 	case 2:
68 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
69 				OTG2_DROP_PIXEL, 1);
70 		break;
71 	case 3:
72 		REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
73 				OTG3_DROP_PIXEL, 1);
74 		break;
75 	default:
76 		ASSERT(0);
77 	}
78 }
79 
dccg42_enable_global_fgcg(struct dccg * dccg,bool enable)80 void dccg42_enable_global_fgcg(struct dccg *dccg, bool enable)
81 {
82 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
83 
84 	/* Temporary workaround for IOMMU mismatch issue.
85 	 * Fine grain control via bit2 of debug flag.
86 	 */
87 	if (dccg->ctx->dc->debug.disable_clock_gate || (dccg->ctx->dc->debug.iommu_mismatch_temp_wka & 0x4))
88 		enable = false;
89 
90 	REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !enable);
91 }
92 
dccg42_get_global_fgcg_status(struct dccg * dccg)93 bool dccg42_get_global_fgcg_status(struct dccg *dccg)
94 {
95 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
96 	uint32_t disabled = 0;
97 
98 	REG_GET(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, &disabled);
99 	return disabled & 0x1;
100 }
101 
dccg42_set_physymclk(struct dccg * dccg,int phy_inst,enum physymclk_clock_source clk_src,bool force_enable)102 void dccg42_set_physymclk(
103 		struct dccg *dccg,
104 		int phy_inst,
105 		enum physymclk_clock_source clk_src,
106 		bool force_enable)
107 {
108 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
109 
110 	switch (phy_inst) {
111 	case 0:
112 		if (force_enable) {
113 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
114 					PHYASYMCLK_ROOT_GATE_DISABLE, 1);
115 			REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
116 					PHYASYMCLK_EN, 1,
117 					PHYASYMCLK_SRC_SEL, clk_src);
118 		} else {
119 			REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
120 					PHYASYMCLK_EN, 0,
121 					PHYASYMCLK_SRC_SEL, 0);
122 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
123 					PHYASYMCLK_ROOT_GATE_DISABLE,
124 					dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
125 		}
126 		break;
127 	case 1:
128 		if (force_enable) {
129 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
130 					PHYBSYMCLK_ROOT_GATE_DISABLE, 1);
131 			REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
132 					PHYBSYMCLK_EN, 1,
133 					PHYBSYMCLK_SRC_SEL, clk_src);
134 		} else {
135 			REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
136 					PHYBSYMCLK_EN, 0,
137 					PHYBSYMCLK_SRC_SEL, 0);
138 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
139 					PHYBSYMCLK_ROOT_GATE_DISABLE,
140 					dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
141 		}
142 		break;
143 	case 2:
144 		if (force_enable) {
145 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
146 					PHYCSYMCLK_ROOT_GATE_DISABLE, 1);
147 			REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
148 					PHYCSYMCLK_EN, 1,
149 					PHYCSYMCLK_SRC_SEL, clk_src);
150 		} else {
151 			REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
152 					PHYCSYMCLK_EN, 0,
153 					PHYCSYMCLK_SRC_SEL, 0);
154 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
155 					PHYCSYMCLK_ROOT_GATE_DISABLE,
156 					dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
157 		}
158 		break;
159 	case 3:
160 		if (force_enable) {
161 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
162 					PHYDSYMCLK_ROOT_GATE_DISABLE, 1);
163 			REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
164 					PHYDSYMCLK_EN, 1,
165 					PHYDSYMCLK_SRC_SEL, clk_src);
166 		} else {
167 			REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
168 					PHYDSYMCLK_EN, 0,
169 					PHYDSYMCLK_SRC_SEL, 0);
170 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
171 					PHYDSYMCLK_ROOT_GATE_DISABLE,
172 					dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
173 		}
174 		break;
175 	case 4:
176 		if (force_enable) {
177 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
178 					PHYESYMCLK_ROOT_GATE_DISABLE, 1);
179 			REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
180 					PHYESYMCLK_EN, 1,
181 					PHYESYMCLK_SRC_SEL, clk_src);
182 		} else {
183 			REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
184 					PHYESYMCLK_EN, 0,
185 					PHYESYMCLK_SRC_SEL, 0);
186 			REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
187 					PHYESYMCLK_ROOT_GATE_DISABLE,
188 					dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
189 		}
190 		break;
191 	default:
192 		BREAK_TO_DEBUGGER();
193 		return;
194 	}
195 }
196 
dccg42_disable_hdmistreamclk(struct dccg * dccg)197 static void dccg42_disable_hdmistreamclk(struct dccg *dccg)
198 {
199 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
200 
201 	REG_UPDATE_2(HDMISTREAMCLK_CNTL,
202 				HDMISTREAMCLK0_EN, 0,
203 				HDMISTREAMCLK0_SRC_SEL, 0);
204 
205 	REG_UPDATE(DCCG_GATE_DISABLE_CNTL6,
206 				HDMISTREAMCLK0_ROOT_GATE_DISABLE,
207 				dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream ? 0 : 1);
208 }
209 
dccg42_disable_hdmicharclk(struct dccg * dccg,int hpo_inst)210 static void dccg42_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
211 {
212 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
213 
214 	ASSERT(hpo_inst >= 0);
215 	REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
216 
217 	REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
218 			HDMICHARCLK0_GATE_DISABLE, 0);
219 	REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
220 			HDMICHARCLK0_ROOT_GATE_DISABLE, dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar ? 0 : 1);
221 }
222 
dccg42_set_pixel_rate_div(struct dccg * dccg,uint32_t otg_inst,enum pixel_rate_div tmds_div,enum pixel_rate_div unused)223 void dccg42_set_pixel_rate_div(
224 		struct dccg *dccg,
225 		uint32_t otg_inst,
226 		enum pixel_rate_div tmds_div,
227 		enum pixel_rate_div unused)
228 {
229 	(void)unused;
230 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
231 	uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
232 	uint32_t dp_dto_int;
233 	uint32_t reg_val;
234 
235 	// only 2 and 4 are valid on dcn401
236 	if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
237 		return;
238 	}
239 
240 	dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
241 	if (tmds_div == cur_tmds_div)
242 		return;
243 
244 	// encode enum to register value
245 	reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
246 
247 	switch (otg_inst) {
248 	case 0:
249 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
250 				OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
251 		break;
252 	case 1:
253 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
254 				OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
255 		break;
256 	case 2:
257 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
258 				OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
259 		break;
260 	case 3:
261 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
262 				OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
263 		break;
264 	default:
265 		BREAK_TO_DEBUGGER();
266 		return;
267 	}
268 }
269 
dccg42_trigger_dio_fifo_resync(struct dccg * dccg)270 void dccg42_trigger_dio_fifo_resync(struct dccg *dccg)
271 {
272 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
273 
274 	REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 1);
275 	REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 0);
276 	REG_WAIT(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_FREQ_RAMP_DONE, 1, 50, 2000);
277 }
278 
dccg42_init(struct dccg * dccg)279 static void dccg42_init(struct dccg *dccg)
280 {
281 	unsigned int i;
282 	struct resource_pool *res_pool = dccg->ctx->dc->res_pool;
283 
284 	/* Set HPO stream encoder to use refclk to avoid case where PHY is
285 	 * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which
286 	 * will cause DCN to hang.
287 	 */
288 	for (i = 0; i < res_pool->hpo_dp_stream_enc_count; i++)
289 		dccg35_disable_symclk32_se(dccg, i);
290 
291 	if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) {
292 		for (i = 0; i < res_pool->hpo_dp_link_enc_count; i++)
293 			dccg401_disable_symclk32_le(dccg, i);
294 	}
295 
296 	if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) {
297 		for (i = 0; i < res_pool->hpo_dp_stream_enc_count; i++)
298 			dccg401_disable_dpstreamclk(dccg, i);
299 	}
300 
301 	dccg42_disable_hdmistreamclk(dccg);
302 	if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
303 		dccg42_disable_hdmicharclk(dccg, 0);
304 
305 	if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) {
306 		for (i = 0; i < res_pool->pipe_count; i++) {
307 			dccg35_dpp_root_clock_control(dccg, i, true);
308 		}
309 	}
310 }
311 
312 
313 static const struct dccg_funcs dccg42_funcs = {
314 	.enable_hdmicharclk = dccg401_enable_hdmicharclk,
315 	.disable_hdmicharclk = dccg42_disable_hdmicharclk,
316 	.set_hdmistreamclk = dccg35_set_hdmistreamclk,
317 	.set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
318 	.update_dpp_dto = dccg35_update_dpp_dto,
319 	.dpp_root_clock_control = dccg35_dpp_root_clock_control,
320 	.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
321 	.dccg_init = dccg42_init,
322 	.set_dpstreamclk = dccg401_set_dpstreamclk,
323 	/* Redundant with above^ */
324 	/* .set_dpstreamclk_root_clock_gating = dccg35_set_dpstreamclk_root_clock_gating, */
325 	.enable_symclk32_se = dccg31_enable_symclk32_se,
326 	.disable_symclk32_se = dccg35_disable_symclk32_se,
327 	.enable_symclk32_le = dccg401_enable_symclk32_le,
328 	.disable_symclk32_le = dccg401_disable_symclk32_le,
329 	.set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating,
330 	.set_physymclk = dccg42_set_physymclk,
331 	.set_dtbclk_dto = NULL,
332 	.set_dto_dscclk = dccg401_set_dto_dscclk,
333 	.set_ref_dscclk = dccg401_set_ref_dscclk,
334 	.set_valid_pixel_rate = NULL,
335 	.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
336 	.set_audio_dtbclk_dto = NULL,
337 	.otg_add_pixel = dccg42_otg_add_pixel,
338 	.otg_drop_pixel = dccg42_otg_drop_pixel,
339 	.disable_dsc = dccg35_disable_dscclk,
340 	.enable_dsc = dccg35_enable_dscclk,
341 	.set_pixel_rate_div = dccg42_set_pixel_rate_div,
342 	.get_pixel_rate_div = dccg401_get_pixel_rate_div,
343 	.trigger_dio_fifo_resync = dccg42_trigger_dio_fifo_resync,
344 	.set_dp_dto = dccg401_set_dp_dto,
345 	.enable_symclk_se = dccg35_enable_symclk_se,
346 	.disable_symclk_se = dccg35_disable_symclk_se,
347 	.set_dtbclk_p_src = dccg401_set_dtbclk_p_src,
348 	.dccg_root_gate_disable_control = dccg35_root_gate_disable_control,
349 	.dccg_read_reg_state = dccg31_read_reg_state,
350 	.dccg_enable_global_fgcg = dccg42_enable_global_fgcg,
351 	.allow_clock_gating = dccg2_allow_clock_gating,
352 	.dccg_get_global_fgcg_status = dccg42_get_global_fgcg_status,
353 };
354 
dccg42_create(struct dc_context * ctx,const struct dccg_registers * regs,const struct dccg_shift * dccg_shift,const struct dccg_mask * dccg_mask)355 struct dccg *dccg42_create(
356 	struct dc_context *ctx,
357 	const struct dccg_registers *regs,
358 	const struct dccg_shift *dccg_shift,
359 	const struct dccg_mask *dccg_mask)
360 {
361 	struct dcn_dccg *dccg_dcn = kzalloc_obj(*dccg_dcn);
362 	struct dccg *base;
363 
364 	if (dccg_dcn == NULL) {
365 		BREAK_TO_DEBUGGER();
366 		return NULL;
367 	}
368 
369 	base = &dccg_dcn->base;
370 	base->ctx = ctx;
371 	base->funcs = &dccg42_funcs;
372 
373 	dccg_dcn->regs = regs;
374 	dccg_dcn->dccg_shift = dccg_shift;
375 	dccg_dcn->dccg_mask = dccg_mask;
376 
377 	return &dccg_dcn->base;
378 }
379