1/* SPDX-License-Identifier: MIT */
2/*
3 * Copyright 2023 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 */
24
25#include "reg_helper.h"
26#include "core_types.h"
27#include "dcn35_dccg.h"
28
29#define TO_DCN_DCCG(dccg)\
30 container_of(dccg, struct dcn_dccg, base)
31
32#define REG(reg) \
33 (dccg_dcn->regs->reg)
34
35#undef FN
36#define FN(reg_name, field_name) \
37 dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
38
39#define CTX \
40 dccg_dcn->base.ctx
41#define DC_LOGGER \
42 dccg->ctx->logger
43
44static void dcn35_set_dppclk_enable(struct dccg *dccg,
45 uint32_t dpp_inst, uint32_t enable)
46{
47 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
48
49 switch (dpp_inst) {
50 case 0:
51 REG_UPDATE(DPPCLK_CTRL, DPPCLK0_EN, enable);
52 break;
53 case 1:
54 REG_UPDATE(DPPCLK_CTRL, DPPCLK1_EN, enable);
55 break;
56 case 2:
57 REG_UPDATE(DPPCLK_CTRL, DPPCLK2_EN, enable);
58 break;
59 case 3:
60 REG_UPDATE(DPPCLK_CTRL, DPPCLK3_EN, enable);
61 break;
62 default:
63 break;
64 }
65
66}
67
68static void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst,
69 int req_dppclk)
70{
71 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
72
73 if (dccg->dpp_clock_gated[dpp_inst]) {
74 /*
75 * Do not update the DPPCLK DTO if the clock is stopped.
76 */
77 return;
78 }
79
80 if (dccg->ref_dppclk && req_dppclk) {
81 int ref_dppclk = dccg->ref_dppclk;
82 int modulo, phase;
83
84 // phase / modulo = dpp pipe clk / dpp global clk
85 modulo = 0xff; // use FF at the end
86 phase = ((modulo * req_dppclk) + ref_dppclk - 1) / ref_dppclk;
87
88 if (phase > 0xff) {
89 ASSERT(false);
90 phase = 0xff;
91 }
92
93 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
94 DPPCLK0_DTO_PHASE, phase,
95 DPPCLK0_DTO_MODULO, modulo);
96
97 dcn35_set_dppclk_enable(dccg, dpp_inst, enable: true);
98 } else
99 dcn35_set_dppclk_enable(dccg, dpp_inst, enable: false);
100 dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk;
101}
102
103static void dccg35_get_pixel_rate_div(
104 struct dccg *dccg,
105 uint32_t otg_inst,
106 enum pixel_rate_div *k1,
107 enum pixel_rate_div *k2)
108{
109 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
110 uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA;
111
112 *k1 = PIXEL_RATE_DIV_NA;
113 *k2 = PIXEL_RATE_DIV_NA;
114
115 switch (otg_inst) {
116 case 0:
117 REG_GET_2(OTG_PIXEL_RATE_DIV,
118 OTG0_PIXEL_RATE_DIVK1, &val_k1,
119 OTG0_PIXEL_RATE_DIVK2, &val_k2);
120 break;
121 case 1:
122 REG_GET_2(OTG_PIXEL_RATE_DIV,
123 OTG1_PIXEL_RATE_DIVK1, &val_k1,
124 OTG1_PIXEL_RATE_DIVK2, &val_k2);
125 break;
126 case 2:
127 REG_GET_2(OTG_PIXEL_RATE_DIV,
128 OTG2_PIXEL_RATE_DIVK1, &val_k1,
129 OTG2_PIXEL_RATE_DIVK2, &val_k2);
130 break;
131 case 3:
132 REG_GET_2(OTG_PIXEL_RATE_DIV,
133 OTG3_PIXEL_RATE_DIVK1, &val_k1,
134 OTG3_PIXEL_RATE_DIVK2, &val_k2);
135 break;
136 default:
137 BREAK_TO_DEBUGGER();
138 return;
139 }
140
141 *k1 = (enum pixel_rate_div)val_k1;
142 *k2 = (enum pixel_rate_div)val_k2;
143}
144
145static void dccg35_set_pixel_rate_div(
146 struct dccg *dccg,
147 uint32_t otg_inst,
148 enum pixel_rate_div k1,
149 enum pixel_rate_div k2)
150{
151 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
152 enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA;
153
154 // Don't program 0xF into the register field. Not valid since
155 // K1 / K2 field is only 1 / 2 bits wide
156 if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA) {
157 BREAK_TO_DEBUGGER();
158 return;
159 }
160
161 dccg35_get_pixel_rate_div(dccg, otg_inst, k1: &cur_k1, k2: &cur_k2);
162 if (k1 == cur_k1 && k2 == cur_k2)
163 return;
164
165 switch (otg_inst) {
166 case 0:
167 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
168 OTG0_PIXEL_RATE_DIVK1, k1,
169 OTG0_PIXEL_RATE_DIVK2, k2);
170 break;
171 case 1:
172 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
173 OTG1_PIXEL_RATE_DIVK1, k1,
174 OTG1_PIXEL_RATE_DIVK2, k2);
175 break;
176 case 2:
177 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
178 OTG2_PIXEL_RATE_DIVK1, k1,
179 OTG2_PIXEL_RATE_DIVK2, k2);
180 break;
181 case 3:
182 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,
183 OTG3_PIXEL_RATE_DIVK1, k1,
184 OTG3_PIXEL_RATE_DIVK2, k2);
185 break;
186 default:
187 BREAK_TO_DEBUGGER();
188 return;
189 }
190}
191
192static void dccg35_set_dtbclk_p_src(
193 struct dccg *dccg,
194 enum streamclk_source src,
195 uint32_t otg_inst)
196{
197 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
198
199 uint32_t p_src_sel = 0; /* selects dprefclk */
200 if (src == DTBCLK0)
201 p_src_sel = 2; /* selects dtbclk0 */
202
203 switch (otg_inst) {
204 case 0:
205 if (src == REFCLK)
206 REG_UPDATE(DTBCLK_P_CNTL,
207 DTBCLK_P0_EN, 0);
208 else
209 REG_UPDATE_2(DTBCLK_P_CNTL,
210 DTBCLK_P0_SRC_SEL, p_src_sel,
211 DTBCLK_P0_EN, 1);
212 break;
213 case 1:
214 if (src == REFCLK)
215 REG_UPDATE(DTBCLK_P_CNTL,
216 DTBCLK_P1_EN, 0);
217 else
218 REG_UPDATE_2(DTBCLK_P_CNTL,
219 DTBCLK_P1_SRC_SEL, p_src_sel,
220 DTBCLK_P1_EN, 1);
221 break;
222 case 2:
223 if (src == REFCLK)
224 REG_UPDATE(DTBCLK_P_CNTL,
225 DTBCLK_P2_EN, 0);
226 else
227 REG_UPDATE_2(DTBCLK_P_CNTL,
228 DTBCLK_P2_SRC_SEL, p_src_sel,
229 DTBCLK_P2_EN, 1);
230 break;
231 case 3:
232 if (src == REFCLK)
233 REG_UPDATE(DTBCLK_P_CNTL,
234 DTBCLK_P3_EN, 0);
235 else
236 REG_UPDATE_2(DTBCLK_P_CNTL,
237 DTBCLK_P3_SRC_SEL, p_src_sel,
238 DTBCLK_P3_EN, 1);
239 break;
240 default:
241 BREAK_TO_DEBUGGER();
242 return;
243 }
244
245}
246
247/* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */
248static void dccg35_set_dtbclk_dto(
249 struct dccg *dccg,
250 const struct dtbclk_dto_params *params)
251{
252 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
253 /* DTO Output Rate / Pixel Rate = 1/4 */
254 int req_dtbclk_khz = params->pixclk_khz / 4;
255
256 if (params->ref_dtbclk_khz && req_dtbclk_khz) {
257 uint32_t modulo, phase;
258
259 switch (params->otg_inst) {
260 case 0:
261 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 1);
262 break;
263 case 1:
264 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 1);
265 break;
266 case 2:
267 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 1);
268 break;
269 case 3:
270 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 1);
271 break;
272 }
273
274 // phase / modulo = dtbclk / dtbclk ref
275 modulo = params->ref_dtbclk_khz * 1000;
276 phase = req_dtbclk_khz * 1000;
277
278 REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], modulo);
279 REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], phase);
280
281 REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
282 DTBCLK_DTO_ENABLE[params->otg_inst], 1);
283
284 REG_WAIT(OTG_PIXEL_RATE_CNTL[params->otg_inst],
285 DTBCLKDTO_ENABLE_STATUS[params->otg_inst], 1,
286 1, 100);
287
288 /* program OTG_PIXEL_RATE_DIV for DIVK1 and DIVK2 fields */
289 dccg35_set_pixel_rate_div(dccg, otg_inst: params->otg_inst, k1: PIXEL_RATE_DIV_BY_1, k2: PIXEL_RATE_DIV_BY_1);
290
291 /* The recommended programming sequence to enable DTBCLK DTO to generate
292 * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should
293 * be set only after DTO is enabled
294 */
295 REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
296 PIPE_DTO_SRC_SEL[params->otg_inst], 2);
297 } else {
298 switch (params->otg_inst) {
299 case 0:
300 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 0);
301 break;
302 case 1:
303 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 0);
304 break;
305 case 2:
306 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 0);
307 break;
308 case 3:
309 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 0);
310 break;
311 }
312
313 REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst],
314 DTBCLK_DTO_ENABLE[params->otg_inst], 0,
315 PIPE_DTO_SRC_SEL[params->otg_inst], params->is_hdmi ? 0 : 1);
316
317 REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], 0);
318 REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], 0);
319 }
320}
321
322static void dccg35_set_dpstreamclk(
323 struct dccg *dccg,
324 enum streamclk_source src,
325 int otg_inst,
326 int dp_hpo_inst)
327{
328 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
329
330 /* set the dtbclk_p source */
331 dccg35_set_dtbclk_p_src(dccg, src, otg_inst);
332
333 /* enabled to select one of the DTBCLKs for pipe */
334 switch (dp_hpo_inst) {
335 case 0:
336 REG_UPDATE_2(DPSTREAMCLK_CNTL,
337 DPSTREAMCLK0_EN,
338 (src == REFCLK) ? 0 : 1, DPSTREAMCLK0_SRC_SEL, otg_inst);
339 break;
340 case 1:
341 REG_UPDATE_2(DPSTREAMCLK_CNTL, DPSTREAMCLK1_EN,
342 (src == REFCLK) ? 0 : 1, DPSTREAMCLK1_SRC_SEL, otg_inst);
343 break;
344 case 2:
345 REG_UPDATE_2(DPSTREAMCLK_CNTL, DPSTREAMCLK2_EN,
346 (src == REFCLK) ? 0 : 1, DPSTREAMCLK2_SRC_SEL, otg_inst);
347 break;
348 case 3:
349 REG_UPDATE_2(DPSTREAMCLK_CNTL, DPSTREAMCLK3_EN,
350 (src == REFCLK) ? 0 : 1, DPSTREAMCLK3_SRC_SEL, otg_inst);
351 break;
352 default:
353 BREAK_TO_DEBUGGER();
354 return;
355 }
356}
357
358static void dccg35_set_physymclk_root_clock_gating(
359 struct dccg *dccg,
360 int phy_inst,
361 bool enable)
362{
363 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
364
365 if (!dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
366 return;
367
368 switch (phy_inst) {
369 case 0:
370 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
371 PHYASYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0);
372 break;
373 case 1:
374 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
375 PHYBSYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0);
376 break;
377 case 2:
378 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
379 PHYCSYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0);
380 break;
381 case 3:
382 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
383 PHYDSYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0);
384 break;
385 case 4:
386 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
387 PHYESYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0);
388 break;
389 default:
390 BREAK_TO_DEBUGGER();
391 return;
392 }
393}
394
395static void dccg35_set_physymclk(
396 struct dccg *dccg,
397 int phy_inst,
398 enum physymclk_clock_source clk_src,
399 bool force_enable)
400{
401 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
402
403 /* Force PHYSYMCLK on and Select phyd32clk as the source of clock which is output to PHY through DCIO */
404 switch (phy_inst) {
405 case 0:
406 if (force_enable) {
407 REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
408 PHYASYMCLK_EN, 1,
409 PHYASYMCLK_SRC_SEL, clk_src);
410 } else {
411 REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
412 PHYASYMCLK_EN, 0,
413 PHYASYMCLK_SRC_SEL, 0);
414 }
415 break;
416 case 1:
417 if (force_enable) {
418 REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
419 PHYBSYMCLK_EN, 1,
420 PHYBSYMCLK_SRC_SEL, clk_src);
421 } else {
422 REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
423 PHYBSYMCLK_EN, 0,
424 PHYBSYMCLK_SRC_SEL, 0);
425 }
426 break;
427 case 2:
428 if (force_enable) {
429 REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
430 PHYCSYMCLK_EN, 1,
431 PHYCSYMCLK_SRC_SEL, clk_src);
432 } else {
433 REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
434 PHYCSYMCLK_EN, 0,
435 PHYCSYMCLK_SRC_SEL, 0);
436 }
437 break;
438 case 3:
439 if (force_enable) {
440 REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
441 PHYDSYMCLK_EN, 1,
442 PHYDSYMCLK_SRC_SEL, clk_src);
443 } else {
444 REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
445 PHYDSYMCLK_EN, 0,
446 PHYDSYMCLK_SRC_SEL, 0);
447 }
448 break;
449 case 4:
450 if (force_enable) {
451 REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
452 PHYESYMCLK_EN, 1,
453 PHYESYMCLK_SRC_SEL, clk_src);
454 } else {
455 REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
456 PHYESYMCLK_EN, 0,
457 PHYESYMCLK_SRC_SEL, 0);
458 }
459 break;
460 default:
461 BREAK_TO_DEBUGGER();
462 return;
463 }
464}
465
466static void dccg35_set_valid_pixel_rate(
467 struct dccg *dccg,
468 int ref_dtbclk_khz,
469 int otg_inst,
470 int pixclk_khz)
471{
472 struct dtbclk_dto_params dto_params = {0};
473
474 dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
475 dto_params.otg_inst = otg_inst;
476 dto_params.pixclk_khz = pixclk_khz;
477 dto_params.is_hdmi = true;
478
479 dccg35_set_dtbclk_dto(dccg, params: &dto_params);
480}
481
482static void dccg35_dpp_root_clock_control(
483 struct dccg *dccg,
484 unsigned int dpp_inst,
485 bool clock_on)
486{
487 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
488
489 if (dccg->dpp_clock_gated[dpp_inst] == clock_on)
490 return;
491
492 if (clock_on) {
493 /* turn off the DTO and leave phase/modulo at max */
494 dcn35_set_dppclk_enable(dccg, dpp_inst, enable: 0);
495 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
496 DPPCLK0_DTO_PHASE, 0xFF,
497 DPPCLK0_DTO_MODULO, 0xFF);
498 } else {
499 dcn35_set_dppclk_enable(dccg, dpp_inst, enable: 1);
500 /* turn on the DTO to generate a 0hz clock */
501 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
502 DPPCLK0_DTO_PHASE, 0,
503 DPPCLK0_DTO_MODULO, 1);
504 }
505
506 dccg->dpp_clock_gated[dpp_inst] = !clock_on;
507}
508
509static void dccg35_disable_symclk32_se(
510 struct dccg *dccg,
511 int hpo_se_inst)
512{
513 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
514
515 /* set refclk as the source for symclk32_se */
516 switch (hpo_se_inst) {
517 case 0:
518 REG_UPDATE_2(SYMCLK32_SE_CNTL,
519 SYMCLK32_SE0_SRC_SEL, 0,
520 SYMCLK32_SE0_EN, 0);
521 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) {
522 REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
523 SYMCLK32_SE0_GATE_DISABLE, 0);
524// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
525// SYMCLK32_ROOT_SE0_GATE_DISABLE, 0);
526 }
527 break;
528 case 1:
529 REG_UPDATE_2(SYMCLK32_SE_CNTL,
530 SYMCLK32_SE1_SRC_SEL, 0,
531 SYMCLK32_SE1_EN, 0);
532 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) {
533 REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
534 SYMCLK32_SE1_GATE_DISABLE, 0);
535// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
536// SYMCLK32_ROOT_SE1_GATE_DISABLE, 0);
537 }
538 break;
539 case 2:
540 REG_UPDATE_2(SYMCLK32_SE_CNTL,
541 SYMCLK32_SE2_SRC_SEL, 0,
542 SYMCLK32_SE2_EN, 0);
543 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) {
544 REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
545 SYMCLK32_SE2_GATE_DISABLE, 0);
546// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
547// SYMCLK32_ROOT_SE2_GATE_DISABLE, 0);
548 }
549 break;
550 case 3:
551 REG_UPDATE_2(SYMCLK32_SE_CNTL,
552 SYMCLK32_SE3_SRC_SEL, 0,
553 SYMCLK32_SE3_EN, 0);
554 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) {
555 REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
556 SYMCLK32_SE3_GATE_DISABLE, 0);
557// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
558// SYMCLK32_ROOT_SE3_GATE_DISABLE, 0);
559 }
560 break;
561 default:
562 BREAK_TO_DEBUGGER();
563 return;
564 }
565}
566
567void dccg35_init(struct dccg *dccg)
568{
569 int otg_inst;
570 /* Set HPO stream encoder to use refclk to avoid case where PHY is
571 * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which
572 * will cause DCN to hang.
573 */
574 for (otg_inst = 0; otg_inst < 4; otg_inst++)
575 dccg35_disable_symclk32_se(dccg, hpo_se_inst: otg_inst);
576
577 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)
578 for (otg_inst = 0; otg_inst < 2; otg_inst++)
579 dccg31_disable_symclk32_le(dccg, hpo_le_inst: otg_inst);
580
581 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)
582 for (otg_inst = 0; otg_inst < 4; otg_inst++)
583 dccg314_set_dpstreamclk(dccg, src: REFCLK, otg_inst,
584 dp_hpo_inst: otg_inst);
585
586 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
587 for (otg_inst = 0; otg_inst < 5; otg_inst++)
588 dccg35_set_physymclk_root_clock_gating(dccg, phy_inst: otg_inst,
589 enable: false);
590/*
591 dccg35_enable_global_fgcg_rep(
592 dccg, dccg->ctx->dc->debug.enable_fine_grain_clock_gating.bits
593 .dccg_global_fgcg_rep);*/
594}
595
596void dccg35_enable_global_fgcg_rep(struct dccg *dccg, bool value)
597{
598 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
599
600 REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !value);
601}
602
603static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
604{
605 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
606
607 //Disable DTO
608 switch (inst) {
609 case 0:
610 REG_UPDATE_2(DSCCLK0_DTO_PARAM,
611 DSCCLK0_DTO_PHASE, 0,
612 DSCCLK0_DTO_MODULO, 0);
613 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);
614 break;
615 case 1:
616 REG_UPDATE_2(DSCCLK1_DTO_PARAM,
617 DSCCLK1_DTO_PHASE, 0,
618 DSCCLK1_DTO_MODULO, 0);
619 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
620 break;
621 case 2:
622 REG_UPDATE_2(DSCCLK2_DTO_PARAM,
623 DSCCLK2_DTO_PHASE, 0,
624 DSCCLK2_DTO_MODULO, 0);
625 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
626 break;
627 case 3:
628 REG_UPDATE_2(DSCCLK3_DTO_PARAM,
629 DSCCLK3_DTO_PHASE, 0,
630 DSCCLK3_DTO_MODULO, 0);
631 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);
632 break;
633 default:
634 BREAK_TO_DEBUGGER();
635 return;
636 }
637}
638
639static void dccg35_disable_dscclk(struct dccg *dccg,
640 int inst)
641{
642 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
643
644 if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
645 return;
646
647 switch (inst) {
648 case 0:
649 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 0);
650 REG_UPDATE_2(DSCCLK0_DTO_PARAM,
651 DSCCLK0_DTO_PHASE, 0,
652 DSCCLK0_DTO_MODULO, 1);
653 break;
654 case 1:
655 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 0);
656 REG_UPDATE_2(DSCCLK1_DTO_PARAM,
657 DSCCLK1_DTO_PHASE, 0,
658 DSCCLK1_DTO_MODULO, 1);
659 break;
660 case 2:
661 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 0);
662 REG_UPDATE_2(DSCCLK2_DTO_PARAM,
663 DSCCLK2_DTO_PHASE, 0,
664 DSCCLK2_DTO_MODULO, 1);
665 break;
666 case 3:
667 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 0);
668 REG_UPDATE_2(DSCCLK3_DTO_PARAM,
669 DSCCLK3_DTO_PHASE, 0,
670 DSCCLK3_DTO_MODULO, 1);
671 break;
672 default:
673 return;
674 }
675}
676
677static void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
678{
679 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
680
681 switch (link_enc_inst) {
682 case 0:
683 REG_UPDATE(SYMCLKA_CLOCK_ENABLE,
684 SYMCLKA_CLOCK_ENABLE, 1);
685 break;
686 case 1:
687 REG_UPDATE(SYMCLKB_CLOCK_ENABLE,
688 SYMCLKB_CLOCK_ENABLE, 1);
689 break;
690 case 2:
691 REG_UPDATE(SYMCLKC_CLOCK_ENABLE,
692 SYMCLKC_CLOCK_ENABLE, 1);
693 break;
694 case 3:
695 REG_UPDATE(SYMCLKD_CLOCK_ENABLE,
696 SYMCLKD_CLOCK_ENABLE, 1);
697 break;
698 case 4:
699 REG_UPDATE(SYMCLKE_CLOCK_ENABLE,
700 SYMCLKE_CLOCK_ENABLE, 1);
701 break;
702 }
703
704 switch (stream_enc_inst) {
705 case 0:
706 REG_UPDATE_2(SYMCLKA_CLOCK_ENABLE,
707 SYMCLKA_FE_EN, 1,
708 SYMCLKA_FE_SRC_SEL, link_enc_inst);
709 break;
710 case 1:
711 REG_UPDATE_2(SYMCLKB_CLOCK_ENABLE,
712 SYMCLKB_FE_EN, 1,
713 SYMCLKB_FE_SRC_SEL, link_enc_inst);
714 break;
715 case 2:
716 REG_UPDATE_2(SYMCLKC_CLOCK_ENABLE,
717 SYMCLKC_FE_EN, 1,
718 SYMCLKC_FE_SRC_SEL, link_enc_inst);
719 break;
720 case 3:
721 REG_UPDATE_2(SYMCLKD_CLOCK_ENABLE,
722 SYMCLKD_FE_EN, 1,
723 SYMCLKD_FE_SRC_SEL, link_enc_inst);
724 break;
725 case 4:
726 REG_UPDATE_2(SYMCLKE_CLOCK_ENABLE,
727 SYMCLKE_FE_EN, 1,
728 SYMCLKE_FE_SRC_SEL, link_enc_inst);
729 break;
730 }
731}
732
733/*get other front end connected to this backend*/
734static uint8_t dccg35_get_other_enabled_symclk_fe(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
735{
736 uint8_t num_enabled_symclk_fe = 0;
737 uint32_t be_clk_en = 0, fe_clk_en[5] = {0}, be_clk_sel[5] = {0};
738 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
739
740 switch (link_enc_inst) {
741 case 0:
742 REG_GET_3(SYMCLKA_CLOCK_ENABLE, SYMCLKA_CLOCK_ENABLE, &be_clk_en,
743 SYMCLKA_FE_EN, &fe_clk_en[0],
744 SYMCLKA_FE_SRC_SEL, &be_clk_sel[0]);
745 break;
746 case 1:
747 REG_GET_3(SYMCLKB_CLOCK_ENABLE, SYMCLKB_CLOCK_ENABLE, &be_clk_en,
748 SYMCLKB_FE_EN, &fe_clk_en[1],
749 SYMCLKB_FE_SRC_SEL, &be_clk_sel[1]);
750 break;
751 case 2:
752 REG_GET_3(SYMCLKC_CLOCK_ENABLE, SYMCLKC_CLOCK_ENABLE, &be_clk_en,
753 SYMCLKC_FE_EN, &fe_clk_en[2],
754 SYMCLKC_FE_SRC_SEL, &be_clk_sel[2]);
755 break;
756 case 3:
757 REG_GET_3(SYMCLKD_CLOCK_ENABLE, SYMCLKD_CLOCK_ENABLE, &be_clk_en,
758 SYMCLKD_FE_EN, &fe_clk_en[3],
759 SYMCLKD_FE_SRC_SEL, &be_clk_sel[3]);
760 break;
761 case 4:
762 REG_GET_3(SYMCLKE_CLOCK_ENABLE, SYMCLKE_CLOCK_ENABLE, &be_clk_en,
763 SYMCLKE_FE_EN, &fe_clk_en[4],
764 SYMCLKE_FE_SRC_SEL, &be_clk_sel[4]);
765 break;
766 }
767 if (be_clk_en) {
768 /* for DPMST, this backend could be used by multiple front end.
769 only disable the backend if this stream_enc_ins is the last active stream enc connected to this back_end*/
770 uint8_t i;
771 for (i = 0; i != link_enc_inst && i < sizeof(fe_clk_en); i++) {
772 if (fe_clk_en[i] && be_clk_sel[i] == link_enc_inst)
773 num_enabled_symclk_fe++;
774 }
775 }
776 return num_enabled_symclk_fe;
777}
778
779static void dccg35_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
780{
781 uint8_t num_enabled_symclk_fe = 0;
782 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
783
784 switch (stream_enc_inst) {
785 case 0:
786 REG_UPDATE_2(SYMCLKA_CLOCK_ENABLE,
787 SYMCLKA_FE_EN, 0,
788 SYMCLKA_FE_SRC_SEL, 0);
789 break;
790 case 1:
791 REG_UPDATE_2(SYMCLKB_CLOCK_ENABLE,
792 SYMCLKB_FE_EN, 0,
793 SYMCLKB_FE_SRC_SEL, 0);
794 break;
795 case 2:
796 REG_UPDATE_2(SYMCLKC_CLOCK_ENABLE,
797 SYMCLKC_FE_EN, 0,
798 SYMCLKC_FE_SRC_SEL, 0);
799 break;
800 case 3:
801 REG_UPDATE_2(SYMCLKD_CLOCK_ENABLE,
802 SYMCLKD_FE_EN, 0,
803 SYMCLKD_FE_SRC_SEL, 0);
804 break;
805 case 4:
806 REG_UPDATE_2(SYMCLKE_CLOCK_ENABLE,
807 SYMCLKE_FE_EN, 0,
808 SYMCLKE_FE_SRC_SEL, 0);
809 break;
810 }
811
812 /*check other enabled symclk fe */
813 num_enabled_symclk_fe = dccg35_get_other_enabled_symclk_fe(dccg, stream_enc_inst, link_enc_inst);
814 /*only turn off backend clk if other front end attachecd to this backend are all off,
815 for mst, only turn off the backend if this is the last front end*/
816 if (num_enabled_symclk_fe == 0) {
817 switch (link_enc_inst) {
818 case 0:
819 REG_UPDATE(SYMCLKA_CLOCK_ENABLE,
820 SYMCLKA_CLOCK_ENABLE, 0);
821 break;
822 case 1:
823 REG_UPDATE(SYMCLKB_CLOCK_ENABLE,
824 SYMCLKB_CLOCK_ENABLE, 0);
825 break;
826 case 2:
827 REG_UPDATE(SYMCLKC_CLOCK_ENABLE,
828 SYMCLKC_CLOCK_ENABLE, 0);
829 break;
830 case 3:
831 REG_UPDATE(SYMCLKD_CLOCK_ENABLE,
832 SYMCLKD_CLOCK_ENABLE, 0);
833 break;
834 case 4:
835 REG_UPDATE(SYMCLKE_CLOCK_ENABLE,
836 SYMCLKE_CLOCK_ENABLE, 0);
837 break;
838 }
839 }
840}
841
842static const struct dccg_funcs dccg35_funcs = {
843 .update_dpp_dto = dccg35_update_dpp_dto,
844 .dpp_root_clock_control = dccg35_dpp_root_clock_control,
845 .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
846 .dccg_init = dccg35_init,
847 .set_dpstreamclk = dccg35_set_dpstreamclk,
848 .enable_symclk32_se = dccg31_enable_symclk32_se,
849 .disable_symclk32_se = dccg35_disable_symclk32_se,
850 .enable_symclk32_le = dccg31_enable_symclk32_le,
851 .disable_symclk32_le = dccg31_disable_symclk32_le,
852 .set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating,
853 .set_physymclk = dccg35_set_physymclk,
854 .set_physymclk_root_clock_gating = dccg35_set_physymclk_root_clock_gating,
855 .set_dtbclk_dto = dccg35_set_dtbclk_dto,
856 .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,
857 .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
858 .otg_add_pixel = dccg31_otg_add_pixel,
859 .otg_drop_pixel = dccg31_otg_drop_pixel,
860 .set_dispclk_change_mode = dccg31_set_dispclk_change_mode,
861 .disable_dsc = dccg35_disable_dscclk,
862 .enable_dsc = dccg35_enable_dscclk,
863 .set_pixel_rate_div = dccg35_set_pixel_rate_div,
864 .set_valid_pixel_rate = dccg35_set_valid_pixel_rate,
865 .enable_symclk_se = dccg35_enable_symclk_se,
866 .disable_symclk_se = dccg35_disable_symclk_se,
867 .set_dtbclk_p_src = dccg35_set_dtbclk_p_src,
868};
869
870struct dccg *dccg35_create(
871 struct dc_context *ctx,
872 const struct dccg_registers *regs,
873 const struct dccg_shift *dccg_shift,
874 const struct dccg_mask *dccg_mask)
875{
876 struct dcn_dccg *dccg_dcn = kzalloc(size: sizeof(*dccg_dcn), GFP_KERNEL);
877 struct dccg *base;
878
879 if (dccg_dcn == NULL) {
880 BREAK_TO_DEBUGGER();
881 return NULL;
882 }
883
884 base = &dccg_dcn->base;
885 base->ctx = ctx;
886 base->funcs = &dccg35_funcs;
887
888 dccg_dcn->regs = regs;
889 dccg_dcn->dccg_shift = dccg_shift;
890 dccg_dcn->dccg_mask = dccg_mask;
891
892 return &dccg_dcn->base;
893}
894

source code of linux/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c