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