1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2022 Advanced Micro Devices, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: AMD
24  *
25  */
26 
27 #include "reg_helper.h"
28 #include "core_types.h"
29 
30 #include "dcn31/dcn31_dccg.h"
31 #include "dcn314_dccg.h"
32 
33 #define TO_DCN_DCCG(dccg)\
34 	container_of(dccg, struct dcn_dccg, base)
35 
36 #define REG(reg) \
37 	(dccg_dcn->regs->reg)
38 
39 #undef FN
40 #define FN(reg_name, field_name) \
41 	dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
42 
43 #define CTX \
44 	dccg_dcn->base.ctx
45 #define DC_LOGGER \
46 	dccg->ctx->logger
47 
48 static void dccg314_get_pixel_rate_div(
49 		struct dccg *dccg,
50 		uint32_t otg_inst,
51 		enum pixel_rate_div *k1,
52 		enum pixel_rate_div *k2)
53 {
54 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
55 	uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA;
56 
57 	*k1 = PIXEL_RATE_DIV_NA;
58 	*k2 = PIXEL_RATE_DIV_NA;
59 
60 	switch (otg_inst) {
61 	case 0:
62 		REG_GET_2(OTG_PIXEL_RATE_DIV,
63 			OTG0_PIXEL_RATE_DIVK1, &val_k1,
64 			OTG0_PIXEL_RATE_DIVK2, &val_k2);
65 		break;
66 	case 1:
67 		REG_GET_2(OTG_PIXEL_RATE_DIV,
68 			OTG1_PIXEL_RATE_DIVK1, &val_k1,
69 			OTG1_PIXEL_RATE_DIVK2, &val_k2);
70 		break;
71 	case 2:
72 		REG_GET_2(OTG_PIXEL_RATE_DIV,
73 			OTG2_PIXEL_RATE_DIVK1, &val_k1,
74 			OTG2_PIXEL_RATE_DIVK2, &val_k2);
75 		break;
76 	case 3:
77 		REG_GET_2(OTG_PIXEL_RATE_DIV,
78 			OTG3_PIXEL_RATE_DIVK1, &val_k1,
79 			OTG3_PIXEL_RATE_DIVK2, &val_k2);
80 		break;
81 	default:
82 		BREAK_TO_DEBUGGER();
83 		return;
84 	}
85 
86 	*k1 = (enum pixel_rate_div)val_k1;
87 	*k2 = (enum pixel_rate_div)val_k2;
88 }
89 
90 static void dccg314_set_pixel_rate_div(
91 		struct dccg *dccg,
92 		uint32_t otg_inst,
93 		enum pixel_rate_div k1,
94 		enum pixel_rate_div k2)
95 {
96 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
97 	enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA;
98 
99 	// Don't program 0xF into the register field. Not valid since
100 	// K1 / K2 field is only 1 / 2 bits wide
101 	if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA) {
102 		BREAK_TO_DEBUGGER();
103 		return;
104 	}
105 
106 	dccg314_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2);
107 	if (k1 == cur_k1 && k2 == cur_k2)
108 		return;
109 
110 	switch (otg_inst) {
111 	case 0:
112 		REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
113 				OTG0_PIXEL_RATE_DIVK1, k1,
114 				OTG0_PIXEL_RATE_DIVK2, k2);
115 		break;
116 	case 1:
117 		REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
118 				OTG1_PIXEL_RATE_DIVK1, k1,
119 				OTG1_PIXEL_RATE_DIVK2, k2);
120 		break;
121 	case 2:
122 		REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
123 				OTG2_PIXEL_RATE_DIVK1, k1,
124 				OTG2_PIXEL_RATE_DIVK2, k2);
125 		break;
126 	case 3:
127 		REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
128 				OTG3_PIXEL_RATE_DIVK1, k1,
129 				OTG3_PIXEL_RATE_DIVK2, k2);
130 		break;
131 	default:
132 		BREAK_TO_DEBUGGER();
133 		return;
134 	}
135 }
136 
137 static void dccg314_set_dtbclk_p_src(
138 		struct dccg *dccg,
139 		enum streamclk_source src,
140 		uint32_t otg_inst)
141 {
142 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
143 
144 	uint32_t p_src_sel = 0; /* selects dprefclk */
145 
146 	if (src == DTBCLK0)
147 		p_src_sel = 2;  /* selects dtbclk0 */
148 
149 	switch (otg_inst) {
150 	case 0:
151 		if (src == REFCLK)
152 			REG_UPDATE(DTBCLK_P_CNTL,
153 					DTBCLK_P0_EN, 0);
154 		else
155 			REG_UPDATE_2(DTBCLK_P_CNTL,
156 					DTBCLK_P0_SRC_SEL, p_src_sel,
157 					DTBCLK_P0_EN, 1);
158 		break;
159 	case 1:
160 		if (src == REFCLK)
161 			REG_UPDATE(DTBCLK_P_CNTL,
162 					DTBCLK_P1_EN, 0);
163 		else
164 			REG_UPDATE_2(DTBCLK_P_CNTL,
165 					DTBCLK_P1_SRC_SEL, p_src_sel,
166 					DTBCLK_P1_EN, 1);
167 		break;
168 	case 2:
169 		if (src == REFCLK)
170 			REG_UPDATE(DTBCLK_P_CNTL,
171 					DTBCLK_P2_EN, 0);
172 		else
173 			REG_UPDATE_2(DTBCLK_P_CNTL,
174 					DTBCLK_P2_SRC_SEL, p_src_sel,
175 					DTBCLK_P2_EN, 1);
176 		break;
177 	case 3:
178 		if (src == REFCLK)
179 			REG_UPDATE(DTBCLK_P_CNTL,
180 					DTBCLK_P3_EN, 0);
181 		else
182 			REG_UPDATE_2(DTBCLK_P_CNTL,
183 					DTBCLK_P3_SRC_SEL, p_src_sel,
184 					DTBCLK_P3_EN, 1);
185 		break;
186 	default:
187 		BREAK_TO_DEBUGGER();
188 		return;
189 	}
190 
191 }
192 
193 /* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */
194 static void dccg314_set_dtbclk_dto(
195 		struct dccg *dccg,
196 		const struct dtbclk_dto_params *params)
197 {
198 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
199 	/* DTO Output Rate / Pixel Rate = 1/4 */
200 	int req_dtbclk_khz = params->pixclk_khz / 4;
201 
202 	if (params->ref_dtbclk_khz && req_dtbclk_khz) {
203 		uint32_t modulo, phase;
204 
205 		// phase / modulo = dtbclk / dtbclk ref
206 		modulo = params->ref_dtbclk_khz * 1000;
207 		phase = req_dtbclk_khz * 1000;
208 
209 		REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], modulo);
210 		REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], phase);
211 
212 		REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
213 				DTBCLK_DTO_ENABLE[params->otg_inst], 1);
214 
215 		REG_WAIT(OTG_PIXEL_RATE_CNTL[params->otg_inst],
216 				DTBCLKDTO_ENABLE_STATUS[params->otg_inst], 1,
217 				1, 100);
218 
219 		/* program OTG_PIXEL_RATE_DIV for DIVK1 and DIVK2 fields */
220 		dccg314_set_pixel_rate_div(dccg, params->otg_inst, PIXEL_RATE_DIV_BY_1, PIXEL_RATE_DIV_BY_1);
221 
222 		/* The recommended programming sequence to enable DTBCLK DTO to generate
223 		 * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should
224 		 * be set only after DTO is enabled
225 		 */
226 		REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
227 				PIPE_DTO_SRC_SEL[params->otg_inst], 2);
228 	} else {
229 		REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst],
230 				DTBCLK_DTO_ENABLE[params->otg_inst], 0,
231 				PIPE_DTO_SRC_SEL[params->otg_inst], 1);
232 
233 		REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], 0);
234 		REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], 0);
235 	}
236 }
237 
238 static void dccg314_set_dpstreamclk(
239 		struct dccg *dccg,
240 		enum streamclk_source src,
241 		int otg_inst,
242 		int dp_hpo_inst)
243 {
244 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
245 
246 	/* set the dtbclk_p source */
247 	dccg314_set_dtbclk_p_src(dccg, src, otg_inst);
248 
249 	/* enabled to select one of the DTBCLKs for pipe */
250 	switch (dp_hpo_inst) {
251 	case 0:
252 		REG_UPDATE_2(DPSTREAMCLK_CNTL,
253 					DPSTREAMCLK0_EN, (src == REFCLK) ? 0 : 1,
254 					DPSTREAMCLK0_SRC_SEL, otg_inst);
255 		break;
256 	case 1:
257 		REG_UPDATE_2(DPSTREAMCLK_CNTL,
258 					DPSTREAMCLK1_EN, (src == REFCLK) ? 0 : 1,
259 					DPSTREAMCLK1_SRC_SEL, otg_inst);
260 		break;
261 	case 2:
262 		REG_UPDATE_2(DPSTREAMCLK_CNTL,
263 					DPSTREAMCLK2_EN, (src == REFCLK) ? 0 : 1,
264 					DPSTREAMCLK2_SRC_SEL, otg_inst);
265 		break;
266 	case 3:
267 		REG_UPDATE_2(DPSTREAMCLK_CNTL,
268 					DPSTREAMCLK3_EN, (src == REFCLK) ? 0 : 1,
269 					DPSTREAMCLK3_SRC_SEL, otg_inst);
270 		break;
271 	default:
272 		BREAK_TO_DEBUGGER();
273 		return;
274 	}
275 }
276 
277 static void dccg314_set_valid_pixel_rate(
278 		struct dccg *dccg,
279 		int ref_dtbclk_khz,
280 		int otg_inst,
281 		int pixclk_khz)
282 {
283 	struct dtbclk_dto_params dto_params = {0};
284 
285 	dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
286 	dto_params.otg_inst = otg_inst;
287 	dto_params.pixclk_khz = pixclk_khz;
288 
289 	dccg314_set_dtbclk_dto(dccg, &dto_params);
290 }
291 
292 static const struct dccg_funcs dccg314_funcs = {
293 	.update_dpp_dto = dccg31_update_dpp_dto,
294 	.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
295 	.dccg_init = dccg31_init,
296 	.set_dpstreamclk = dccg314_set_dpstreamclk,
297 	.enable_symclk32_se = dccg31_enable_symclk32_se,
298 	.disable_symclk32_se = dccg31_disable_symclk32_se,
299 	.enable_symclk32_le = dccg31_enable_symclk32_le,
300 	.disable_symclk32_le = dccg31_disable_symclk32_le,
301 	.set_physymclk = dccg31_set_physymclk,
302 	.set_dtbclk_dto = dccg314_set_dtbclk_dto,
303 	.set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,
304 	.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
305 	.otg_add_pixel = dccg31_otg_add_pixel,
306 	.otg_drop_pixel = dccg31_otg_drop_pixel,
307 	.set_dispclk_change_mode = dccg31_set_dispclk_change_mode,
308 	.disable_dsc = dccg31_disable_dscclk,
309 	.enable_dsc = dccg31_enable_dscclk,
310 	.set_pixel_rate_div = dccg314_set_pixel_rate_div,
311 	.set_valid_pixel_rate = dccg314_set_valid_pixel_rate,
312 };
313 
314 struct dccg *dccg314_create(
315 	struct dc_context *ctx,
316 	const struct dccg_registers *regs,
317 	const struct dccg_shift *dccg_shift,
318 	const struct dccg_mask *dccg_mask)
319 {
320 	struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
321 	struct dccg *base;
322 
323 	if (dccg_dcn == NULL) {
324 		BREAK_TO_DEBUGGER();
325 		return NULL;
326 	}
327 
328 	base = &dccg_dcn->base;
329 	base->ctx = ctx;
330 	base->funcs = &dccg314_funcs;
331 
332 	dccg_dcn->regs = regs;
333 	dccg_dcn->dccg_shift = dccg_shift;
334 	dccg_dcn->dccg_mask = dccg_mask;
335 
336 	return &dccg_dcn->base;
337 }
338