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 | |
44 | static 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 | |
68 | static 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 | |
103 | static 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 | |
145 | static 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 | |
192 | static 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) */ |
248 | static 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 | |
322 | static 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 | |
358 | static 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 | |
395 | static 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 | |
466 | static 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 | |
482 | static 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 | |
509 | static 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 | |
567 | void 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 | |
596 | void 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 | |
603 | static 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 | |
639 | static 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 | |
677 | static 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*/ |
734 | static 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 | |
779 | static 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 | |
842 | static 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 | |
870 | struct 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 | |