projects/linux·blob master · refs

1967 lines · 61.7 KiB

1/*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "dm_services.h"
27
28
29#include "dc_types.h"
30#include "core_types.h"
31
32#include "include/grph_object_id.h"
33#include "include/logger_interface.h"
34
35#include "dce_clock_source.h"
36#include "clk_mgr.h"
37#include "dccg.h"
38
39#include "reg_helper.h"
40
41#define REG(reg)\
42 (clk_src->regs->reg)
43
44#define CTX \
45 clk_src->base.ctx
46
47#define DC_LOGGER \
48 CTX->logger
49
50#undef FN
51#define FN(reg_name, field_name) \
52 clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
53
54#define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
55#define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
56#define MAX_PLL_CALC_ERROR 0xFFFFFFFF
57
58static const struct spread_spectrum_data *get_ss_data_entry(
59 struct dce110_clk_src *clk_src,
60 enum signal_type signal,
61 uint32_t pix_clk_khz)
62{
63
64 uint32_t entrys_num;
65 uint32_t i;
66 struct spread_spectrum_data *ss_parm = NULL;
67 struct spread_spectrum_data *ret = NULL;
68
69 switch (signal) {
70 case SIGNAL_TYPE_DVI_SINGLE_LINK:
71 case SIGNAL_TYPE_DVI_DUAL_LINK:
72 ss_parm = clk_src->dvi_ss_params;
73 entrys_num = clk_src->dvi_ss_params_cnt;
74 break;
75
76 case SIGNAL_TYPE_HDMI_TYPE_A:
77 ss_parm = clk_src->hdmi_ss_params;
78 entrys_num = clk_src->hdmi_ss_params_cnt;
79 break;
80
81 case SIGNAL_TYPE_LVDS:
82 ss_parm = clk_src->lvds_ss_params;
83 entrys_num = clk_src->lvds_ss_params_cnt;
84 break;
85
86 case SIGNAL_TYPE_DISPLAY_PORT:
87 case SIGNAL_TYPE_DISPLAY_PORT_MST:
88 case SIGNAL_TYPE_EDP:
89 case SIGNAL_TYPE_VIRTUAL:
90 ss_parm = clk_src->dp_ss_params;
91 entrys_num = clk_src->dp_ss_params_cnt;
92 break;
93
94 default:
95 ss_parm = NULL;
96 entrys_num = 0;
97 break;
98 }
99
100 if (ss_parm == NULL)
101 return ret;
102
103 for (i = 0; i < entrys_num; ++i, ++ss_parm) {
104 if (ss_parm->freq_range_khz >= pix_clk_khz) {
105 ret = ss_parm;
106 break;
107 }
108 }
109
110 return ret;
111}
112
113/**
114 * calculate_fb_and_fractional_fb_divider - Calculates feedback and fractional
115 * feedback dividers values
116 *
117 * @calc_pll_cs: Pointer to clock source information
118 * @target_pix_clk_100hz: Desired frequency in 100 Hz
119 * @ref_divider: Reference divider (already known)
120 * @post_divider: Post Divider (already known)
121 * @feedback_divider_param: Pointer where to store
122 * calculated feedback divider value
123 * @fract_feedback_divider_param: Pointer where to store
124 * calculated fract feedback divider value
125 *
126 * return:
127 * It fills the locations pointed by feedback_divider_param
128 * and fract_feedback_divider_param
129 * It returns - true if feedback divider not 0
130 * - false should never happen)
131 */
132static bool calculate_fb_and_fractional_fb_divider(
133 struct calc_pll_clock_source *calc_pll_cs,
134 uint32_t target_pix_clk_100hz,
135 uint32_t ref_divider,
136 uint32_t post_divider,
137 uint32_t *feedback_divider_param,
138 uint32_t *fract_feedback_divider_param)
139{
140 uint64_t feedback_divider;
141
142 feedback_divider =
143 (uint64_t)target_pix_clk_100hz * ref_divider * post_divider;
144 feedback_divider *= 10;
145 /* additional factor, since we divide by 10 afterwards */
146 feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
147 feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz * 10ull);
148
149/*Round to the number of precision
150 * The following code replace the old code (ullfeedbackDivider + 5)/10
151 * for example if the difference between the number
152 * of fractional feedback decimal point and the fractional FB Divider precision
153 * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
154
155 feedback_divider += 5ULL *
156 calc_pll_cs->fract_fb_divider_precision_factor;
157 feedback_divider =
158 div_u64(feedback_divider,
159 calc_pll_cs->fract_fb_divider_precision_factor * 10);
160 feedback_divider *= (uint64_t)
161 (calc_pll_cs->fract_fb_divider_precision_factor);
162
163 *feedback_divider_param = (uint32_t)div_u64_rem(
164 feedback_divider, calc_pll_cs->fract_fb_divider_factor,
165 fract_feedback_divider_param);
166
167 if (*feedback_divider_param != 0)
168 return true;
169 return false;
170}
171
172/**
173 * calc_fb_divider_checking_tolerance - Calculates Feedback and
174 * Fractional Feedback divider values
175 * for passed Reference and Post divider,
176 * checking for tolerance.
177 * @calc_pll_cs: Pointer to clock source information
178 * @pll_settings: Pointer to PLL settings
179 * @ref_divider: Reference divider (already known)
180 * @post_divider: Post Divider (already known)
181 * @tolerance: Tolerance for Calculated Pixel Clock to be within
182 *
183 * return:
184 * It fills the PLLSettings structure with PLL Dividers values
185 * if calculated values are within required tolerance
186 * It returns - true if error is within tolerance
187 * - false if error is not within tolerance
188 */
189static bool calc_fb_divider_checking_tolerance(
190 struct calc_pll_clock_source *calc_pll_cs,
191 struct pll_settings *pll_settings,
192 uint32_t ref_divider,
193 uint32_t post_divider,
194 uint32_t tolerance)
195{
196 uint32_t feedback_divider;
197 uint32_t fract_feedback_divider;
198 uint32_t actual_calculated_clock_100hz;
199 uint32_t abs_err;
200 uint64_t actual_calc_clk_100hz;
201
202 calculate_fb_and_fractional_fb_divider(
203 calc_pll_cs,
204 pll_settings->adjusted_pix_clk_100hz,
205 ref_divider,
206 post_divider,
207 &feedback_divider,
208 &fract_feedback_divider);
209
210 /*Actual calculated value*/
211 actual_calc_clk_100hz = (uint64_t)feedback_divider *
212 calc_pll_cs->fract_fb_divider_factor +
213 fract_feedback_divider;
214 actual_calc_clk_100hz *= (uint64_t)calc_pll_cs->ref_freq_khz * 10;
215 actual_calc_clk_100hz =
216 div_u64(actual_calc_clk_100hz,
217 ref_divider * post_divider *
218 calc_pll_cs->fract_fb_divider_factor);
219
220 actual_calculated_clock_100hz = (uint32_t)(actual_calc_clk_100hz);
221
222 abs_err = (actual_calculated_clock_100hz >
223 pll_settings->adjusted_pix_clk_100hz)
224 ? actual_calculated_clock_100hz -
225 pll_settings->adjusted_pix_clk_100hz
226 : pll_settings->adjusted_pix_clk_100hz -
227 actual_calculated_clock_100hz;
228
229 if (abs_err <= tolerance) {
230 /*found good values*/
231 pll_settings->reference_freq = calc_pll_cs->ref_freq_khz;
232 pll_settings->reference_divider = ref_divider;
233 pll_settings->feedback_divider = feedback_divider;
234 pll_settings->fract_feedback_divider = fract_feedback_divider;
235 pll_settings->pix_clk_post_divider = post_divider;
236 pll_settings->calculated_pix_clk_100hz =
237 actual_calculated_clock_100hz;
238 pll_settings->vco_freq =
239 (uint32_t)div_u64((u64)actual_calculated_clock_100hz * post_divider, 10);
240 return true;
241 }
242 return false;
243}
244
245static bool calc_pll_dividers_in_range(
246 struct calc_pll_clock_source *calc_pll_cs,
247 struct pll_settings *pll_settings,
248 uint32_t min_ref_divider,
249 uint32_t max_ref_divider,
250 uint32_t min_post_divider,
251 uint32_t max_post_divider,
252 uint32_t err_tolerance)
253{
254 uint32_t ref_divider;
255 uint32_t post_divider;
256 uint32_t tolerance;
257
258/* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
259 * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
260 tolerance = (pll_settings->adjusted_pix_clk_100hz * err_tolerance) /
261 100000;
262 if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
263 tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
264
265 for (
266 post_divider = max_post_divider;
267 post_divider >= min_post_divider;
268 --post_divider) {
269 for (
270 ref_divider = min_ref_divider;
271 ref_divider <= max_ref_divider;
272 ++ref_divider) {
273 if (calc_fb_divider_checking_tolerance(
274 calc_pll_cs,
275 pll_settings,
276 ref_divider,
277 post_divider,
278 tolerance)) {
279 return true;
280 }
281 }
282 }
283
284 return false;
285}
286
287static uint32_t calculate_pixel_clock_pll_dividers(
288 struct dce110_clk_src *clk_src,
289 struct calc_pll_clock_source *calc_pll_cs,
290 struct pll_settings *pll_settings)
291{
292 uint32_t err_tolerance;
293 uint32_t min_post_divider;
294 uint32_t max_post_divider;
295 uint32_t min_ref_divider;
296 uint32_t max_ref_divider;
297
298 if (pll_settings->adjusted_pix_clk_100hz == 0) {
299 DC_LOG_ERROR(
300 "%s Bad requested pixel clock", __func__);
301 return MAX_PLL_CALC_ERROR;
302 }
303
304/* 1) Find Post divider ranges */
305 if (pll_settings->pix_clk_post_divider) {
306 min_post_divider = pll_settings->pix_clk_post_divider;
307 max_post_divider = pll_settings->pix_clk_post_divider;
308 } else {
309 min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
310 if (min_post_divider * pll_settings->adjusted_pix_clk_100hz <
311 calc_pll_cs->min_vco_khz * 10) {
312 min_post_divider = calc_pll_cs->min_vco_khz * 10 /
313 pll_settings->adjusted_pix_clk_100hz;
314 if ((min_post_divider *
315 pll_settings->adjusted_pix_clk_100hz) <
316 calc_pll_cs->min_vco_khz * 10)
317 min_post_divider++;
318 }
319
320 max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
321 if (max_post_divider * pll_settings->adjusted_pix_clk_100hz
322 > calc_pll_cs->max_vco_khz * 10)
323 max_post_divider = calc_pll_cs->max_vco_khz * 10 /
324 pll_settings->adjusted_pix_clk_100hz;
325 }
326
327/* 2) Find Reference divider ranges
328 * When SS is enabled, or for Display Port even without SS,
329 * pll_settings->referenceDivider is not zero.
330 * So calculate PPLL FB and fractional FB divider
331 * using the passed reference divider*/
332
333 if (pll_settings->reference_divider) {
334 min_ref_divider = pll_settings->reference_divider;
335 max_ref_divider = pll_settings->reference_divider;
336 } else {
337 min_ref_divider = ((calc_pll_cs->ref_freq_khz
338 / calc_pll_cs->max_pll_input_freq_khz)
339 > calc_pll_cs->min_pll_ref_divider)
340 ? calc_pll_cs->ref_freq_khz
341 / calc_pll_cs->max_pll_input_freq_khz
342 : calc_pll_cs->min_pll_ref_divider;
343
344 max_ref_divider = ((calc_pll_cs->ref_freq_khz
345 / calc_pll_cs->min_pll_input_freq_khz)
346 < calc_pll_cs->max_pll_ref_divider)
347 ? calc_pll_cs->ref_freq_khz /
348 calc_pll_cs->min_pll_input_freq_khz
349 : calc_pll_cs->max_pll_ref_divider;
350 }
351
352/* If some parameters are invalid we could have scenario when "min">"max"
353 * which produced endless loop later.
354 * We should investigate why we get the wrong parameters.
355 * But to follow the similar logic when "adjustedPixelClock" is set to be 0
356 * it is better to return here than cause system hang/watchdog timeout later.
357 * ## SVS Wed 15 Jul 2009 */
358
359 if (min_post_divider > max_post_divider) {
360 DC_LOG_ERROR(
361 "%s Post divider range is invalid", __func__);
362 return MAX_PLL_CALC_ERROR;
363 }
364
365 if (min_ref_divider > max_ref_divider) {
366 DC_LOG_ERROR(
367 "%s Reference divider range is invalid", __func__);
368 return MAX_PLL_CALC_ERROR;
369 }
370
371/* 3) Try to find PLL dividers given ranges
372 * starting with minimal error tolerance.
373 * Increase error tolerance until PLL dividers found*/
374 err_tolerance = MAX_PLL_CALC_ERROR;
375
376 while (!calc_pll_dividers_in_range(
377 calc_pll_cs,
378 pll_settings,
379 min_ref_divider,
380 max_ref_divider,
381 min_post_divider,
382 max_post_divider,
383 err_tolerance))
384 err_tolerance += (err_tolerance > 10)
385 ? (err_tolerance / 10)
386 : 1;
387
388 return err_tolerance;
389}
390
391static bool pll_adjust_pix_clk(
392 struct dce110_clk_src *clk_src,
393 struct pixel_clk_params *pix_clk_params,
394 struct pll_settings *pll_settings)
395{
396 uint32_t actual_pix_clk_100hz = 0;
397 uint32_t requested_clk_100hz = 0;
398 struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
399 0 };
400 enum bp_result bp_result;
401 switch (pix_clk_params->signal_type) {
402 case SIGNAL_TYPE_HDMI_TYPE_A: {
403 requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
404 if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
405 switch (pix_clk_params->color_depth) {
406 case COLOR_DEPTH_101010:
407 requested_clk_100hz = (requested_clk_100hz * 5) >> 2;
408 break; /* x1.25*/
409 case COLOR_DEPTH_121212:
410 requested_clk_100hz = (requested_clk_100hz * 6) >> 2;
411 break; /* x1.5*/
412 case COLOR_DEPTH_161616:
413 requested_clk_100hz = requested_clk_100hz * 2;
414 break; /* x2.0*/
415 default:
416 break;
417 }
418 }
419 actual_pix_clk_100hz = requested_clk_100hz;
420 }
421 break;
422
423 case SIGNAL_TYPE_DISPLAY_PORT:
424 case SIGNAL_TYPE_DISPLAY_PORT_MST:
425 case SIGNAL_TYPE_EDP:
426 requested_clk_100hz = pix_clk_params->requested_sym_clk * 10;
427 actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
428 break;
429
430 default:
431 requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
432 actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
433 break;
434 }
435
436 bp_adjust_pixel_clock_params.pixel_clock = requested_clk_100hz / 10;
437 bp_adjust_pixel_clock_params.
438 encoder_object_id = pix_clk_params->encoder_object_id;
439 bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
440 bp_adjust_pixel_clock_params.ss_enable = pix_clk_params->flags.ENABLE_SS != 0;
441 bp_result = clk_src->bios->funcs->adjust_pixel_clock(
442 clk_src->bios, &bp_adjust_pixel_clock_params);
443 if (bp_result == BP_RESULT_OK) {
444 pll_settings->actual_pix_clk_100hz = actual_pix_clk_100hz;
445 pll_settings->adjusted_pix_clk_100hz =
446 bp_adjust_pixel_clock_params.adjusted_pixel_clock * 10;
447 pll_settings->reference_divider =
448 bp_adjust_pixel_clock_params.reference_divider;
449 pll_settings->pix_clk_post_divider =
450 bp_adjust_pixel_clock_params.pixel_clock_post_divider;
451
452 return true;
453 }
454
455 return false;
456}
457
458/*
459 * Calculate PLL Dividers for given Clock Value.
460 * First will call VBIOS Adjust Exec table to check if requested Pixel clock
461 * will be Adjusted based on usage.
462 * Then it will calculate PLL Dividers for this Adjusted clock using preferred
463 * method (Maximum VCO frequency).
464 *
465 * \return
466 * Calculation error in units of 0.01%
467 */
468
469static uint32_t dce110_get_pix_clk_dividers_helper (
470 struct dce110_clk_src *clk_src,
471 struct pll_settings *pll_settings,
472 struct pixel_clk_params *pix_clk_params)
473{
474 uint32_t field = 0;
475 uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
476
477 /* Check if reference clock is external (not pcie/xtalin)
478 * HW Dce80 spec:
479 * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB
480 * 04 - HSYNCA, 05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
481 REG_GET(PLL_CNTL, PLL_REF_DIV_SRC, &field);
482 pll_settings->use_external_clk = (field > 1);
483
484 /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
485 * (we do not care any more from SI for some older DP Sink which
486 * does not report SS support, no known issues) */
487 if ((pix_clk_params->flags.ENABLE_SS) ||
488 (dc_is_dp_signal(pix_clk_params->signal_type))) {
489
490 const struct spread_spectrum_data *ss_data = get_ss_data_entry(
491 clk_src,
492 pix_clk_params->signal_type,
493 pll_settings->adjusted_pix_clk_100hz / 10);
494
495 if (NULL != ss_data)
496 pll_settings->ss_percentage = ss_data->percentage;
497 }
498
499 /* Check VBIOS AdjustPixelClock Exec table */
500 if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) {
501 /* Should never happen, ASSERT and fill up values to be able
502 * to continue. */
503 DC_LOG_ERROR(
504 "%s: Failed to adjust pixel clock!!", __func__);
505 pll_settings->actual_pix_clk_100hz =
506 pix_clk_params->requested_pix_clk_100hz;
507 pll_settings->adjusted_pix_clk_100hz =
508 pix_clk_params->requested_pix_clk_100hz;
509
510 if (dc_is_dp_signal(pix_clk_params->signal_type))
511 pll_settings->adjusted_pix_clk_100hz = 1000000;
512 }
513
514 /* Calculate Dividers */
515 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
516 /*Calculate Dividers by HDMI object, no SS case or SS case */
517 pll_calc_error =
518 calculate_pixel_clock_pll_dividers(
519 clk_src,
520 &clk_src->calc_pll_hdmi,
521 pll_settings);
522 else
523 /*Calculate Dividers by default object, no SS case or SS case */
524 pll_calc_error =
525 calculate_pixel_clock_pll_dividers(
526 clk_src,
527 &clk_src->calc_pll,
528 pll_settings);
529
530 return pll_calc_error;
531}
532
533static void dce112_get_pix_clk_dividers_helper (
534 struct dce110_clk_src *clk_src,
535 struct pll_settings *pll_settings,
536 struct pixel_clk_params *pix_clk_params)
537{
538 (void)clk_src;
539 uint32_t actual_pixel_clock_100hz;
540
541 actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz;
542 /* Calculate Dividers */
543 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
544 switch (pix_clk_params->color_depth) {
545 case COLOR_DEPTH_101010:
546 actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
547 actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
548 break;
549 case COLOR_DEPTH_121212:
550 actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
551 actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
552 break;
553 case COLOR_DEPTH_161616:
554 actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
555 break;
556 default:
557 break;
558 }
559 }
560 pll_settings->actual_pix_clk_100hz = actual_pixel_clock_100hz;
561 pll_settings->adjusted_pix_clk_100hz = actual_pixel_clock_100hz;
562 pll_settings->calculated_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
563}
564
565static uint32_t dce110_get_pix_clk_dividers(
566 struct clock_source *cs,
567 struct pixel_clk_params *pix_clk_params,
568 struct pll_settings *pll_settings)
569{
570 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
571 uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
572
573 if (pix_clk_params == NULL || pll_settings == NULL
574 || pix_clk_params->requested_pix_clk_100hz == 0) {
575 DC_LOG_ERROR(
576 "%s: Invalid parameters!!\n", __func__);
577 return pll_calc_error;
578 }
579
580 memset(pll_settings, 0, sizeof(*pll_settings));
581
582 if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
583 cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
584 pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
585 pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
586 pll_settings->actual_pix_clk_100hz =
587 pix_clk_params->requested_pix_clk_100hz;
588 return 0;
589 }
590
591 pll_calc_error = dce110_get_pix_clk_dividers_helper(clk_src,
592 pll_settings, pix_clk_params);
593
594 return pll_calc_error;
595}
596
597static uint32_t dce112_get_pix_clk_dividers(
598 struct clock_source *cs,
599 struct pixel_clk_params *pix_clk_params,
600 struct pll_settings *pll_settings)
601{
602 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
603
604 if (pix_clk_params == NULL || pll_settings == NULL
605 || pix_clk_params->requested_pix_clk_100hz == 0) {
606 DC_LOG_ERROR(
607 "%s: Invalid parameters!!\n", __func__);
608 return (uint32_t)-1;
609 }
610
611 memset(pll_settings, 0, sizeof(*pll_settings));
612
613 if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
614 cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
615 pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
616 pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
617 pll_settings->actual_pix_clk_100hz =
618 pix_clk_params->requested_pix_clk_100hz;
619 return (uint32_t)-1;
620 }
621
622 dce112_get_pix_clk_dividers_helper(clk_src,
623 pll_settings, pix_clk_params);
624
625 return 0;
626}
627
628static bool disable_spread_spectrum(struct dce110_clk_src *clk_src)
629{
630 enum bp_result result;
631 struct bp_spread_spectrum_parameters bp_ss_params = {0};
632
633 bp_ss_params.pll_id = clk_src->base.id;
634
635 /*Call ASICControl to process ATOMBIOS Exec table*/
636 result = clk_src->bios->funcs->enable_spread_spectrum_on_ppll(
637 clk_src->bios,
638 &bp_ss_params,
639 false);
640
641 return result == BP_RESULT_OK;
642}
643
644static bool calculate_ss(
645 const struct pll_settings *pll_settings,
646 const struct spread_spectrum_data *ss_data,
647 struct delta_sigma_data *ds_data)
648{
649 struct fixed31_32 fb_div;
650 struct fixed31_32 ss_amount;
651 struct fixed31_32 ss_nslip_amount;
652 struct fixed31_32 ss_ds_frac_amount;
653 struct fixed31_32 ss_step_size;
654 struct fixed31_32 modulation_time;
655
656 if (ds_data == NULL)
657 return false;
658 if (ss_data == NULL)
659 return false;
660 if (ss_data->percentage == 0)
661 return false;
662 if (pll_settings == NULL)
663 return false;
664
665 memset(ds_data, 0, sizeof(struct delta_sigma_data));
666
667 /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
668 /* 6 decimal point support in fractional feedback divider */
669 fb_div = dc_fixpt_from_fraction(
670 pll_settings->fract_feedback_divider, 1000000);
671 fb_div = dc_fixpt_add_int(fb_div, pll_settings->feedback_divider);
672
673 ds_data->ds_frac_amount = 0;
674 /*spreadSpectrumPercentage is in the unit of .01%,
675 * so have to divided by 100 * 100*/
676 ss_amount = dc_fixpt_mul(
677 fb_div, dc_fixpt_from_fraction(ss_data->percentage,
678 100 * (long long)ss_data->percentage_divider));
679 ds_data->feedback_amount = dc_fixpt_floor(ss_amount);
680
681 ss_nslip_amount = dc_fixpt_sub(ss_amount,
682 dc_fixpt_from_int(ds_data->feedback_amount));
683 ss_nslip_amount = dc_fixpt_mul_int(ss_nslip_amount, 10);
684 ds_data->nfrac_amount = dc_fixpt_floor(ss_nslip_amount);
685
686 ss_ds_frac_amount = dc_fixpt_sub(ss_nslip_amount,
687 dc_fixpt_from_int(ds_data->nfrac_amount));
688 ss_ds_frac_amount = dc_fixpt_mul_int(ss_ds_frac_amount, 65536);
689 ds_data->ds_frac_amount = dc_fixpt_floor(ss_ds_frac_amount);
690
691 /* compute SS_STEP_SIZE_DSFRAC */
692 modulation_time = dc_fixpt_from_fraction(
693 pll_settings->reference_freq * (uint64_t)1000,
694 pll_settings->reference_divider * (uint64_t)ss_data->modulation_freq_hz);
695
696 if (ss_data->flags.CENTER_SPREAD)
697 modulation_time = dc_fixpt_div_int(modulation_time, 4);
698 else
699 modulation_time = dc_fixpt_div_int(modulation_time, 2);
700
701 ss_step_size = dc_fixpt_div(ss_amount, modulation_time);
702 /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
703 ss_step_size = dc_fixpt_mul_int(ss_step_size, 65536 * 10);
704 ds_data->ds_frac_size = dc_fixpt_floor(ss_step_size);
705
706 return true;
707}
708
709static bool enable_spread_spectrum(
710 struct dce110_clk_src *clk_src,
711 enum signal_type signal, struct pll_settings *pll_settings)
712{
713 struct bp_spread_spectrum_parameters bp_params = {0};
714 struct delta_sigma_data d_s_data;
715 const struct spread_spectrum_data *ss_data = NULL;
716
717 ss_data = get_ss_data_entry(
718 clk_src,
719 signal,
720 pll_settings->calculated_pix_clk_100hz / 10);
721
722/* Pixel clock PLL has been programmed to generate desired pixel clock,
723 * now enable SS on pixel clock */
724/* TODO is it OK to return true not doing anything ??*/
725 if (ss_data != NULL && pll_settings->ss_percentage != 0) {
726 if (calculate_ss(pll_settings, ss_data, &d_s_data)) {
727 bp_params.ds.feedback_amount =
728 d_s_data.feedback_amount;
729 bp_params.ds.nfrac_amount =
730 d_s_data.nfrac_amount;
731 bp_params.ds.ds_frac_size = d_s_data.ds_frac_size;
732 bp_params.ds_frac_amount =
733 d_s_data.ds_frac_amount;
734 bp_params.flags.DS_TYPE = 1;
735 bp_params.pll_id = clk_src->base.id;
736 bp_params.percentage = ss_data->percentage;
737 if (ss_data->flags.CENTER_SPREAD)
738 bp_params.flags.CENTER_SPREAD = 1;
739 if (ss_data->flags.EXTERNAL_SS)
740 bp_params.flags.EXTERNAL_SS = 1;
741
742 if (BP_RESULT_OK !=
743 clk_src->bios->funcs->
744 enable_spread_spectrum_on_ppll(
745 clk_src->bios,
746 &bp_params,
747 true))
748 return false;
749 } else
750 return false;
751 }
752 return true;
753}
754
755static void dce110_program_pixel_clk_resync(
756 struct dce110_clk_src *clk_src,
757 enum signal_type signal_type,
758 enum dc_color_depth colordepth)
759{
760 REG_UPDATE(RESYNC_CNTL,
761 DCCG_DEEP_COLOR_CNTL1, 0);
762 /*
763 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
764 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
765 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
766 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
767 */
768 if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
769 return;
770
771 switch (colordepth) {
772 case COLOR_DEPTH_888:
773 REG_UPDATE(RESYNC_CNTL,
774 DCCG_DEEP_COLOR_CNTL1, 0);
775 break;
776 case COLOR_DEPTH_101010:
777 REG_UPDATE(RESYNC_CNTL,
778 DCCG_DEEP_COLOR_CNTL1, 1);
779 break;
780 case COLOR_DEPTH_121212:
781 REG_UPDATE(RESYNC_CNTL,
782 DCCG_DEEP_COLOR_CNTL1, 2);
783 break;
784 case COLOR_DEPTH_161616:
785 REG_UPDATE(RESYNC_CNTL,
786 DCCG_DEEP_COLOR_CNTL1, 3);
787 break;
788 default:
789 break;
790 }
791}
792
793static void dce112_program_pixel_clk_resync(
794 struct dce110_clk_src *clk_src,
795 enum signal_type signal_type,
796 enum dc_color_depth colordepth,
797 bool enable_ycbcr420)
798{
799 uint32_t deep_color_cntl = 0;
800 uint32_t double_rate_enable = 0;
801
802 /*
803 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
804 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
805 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
806 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
807 */
808 if (signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
809 double_rate_enable = enable_ycbcr420 ? 1 : 0;
810
811 switch (colordepth) {
812 case COLOR_DEPTH_888:
813 deep_color_cntl = 0;
814 break;
815 case COLOR_DEPTH_101010:
816 deep_color_cntl = 1;
817 break;
818 case COLOR_DEPTH_121212:
819 deep_color_cntl = 2;
820 break;
821 case COLOR_DEPTH_161616:
822 deep_color_cntl = 3;
823 break;
824 default:
825 break;
826 }
827 }
828
829 if (clk_src->cs_mask->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE)
830 REG_UPDATE_2(PIXCLK_RESYNC_CNTL,
831 PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl,
832 PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, double_rate_enable);
833 else
834 REG_UPDATE(PIXCLK_RESYNC_CNTL,
835 PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl);
836
837}
838
839static bool dce110_program_pix_clk(
840 struct clock_source *clock_source,
841 struct pixel_clk_params *pix_clk_params,
842 enum dp_link_encoding encoding,
843 struct pll_settings *pll_settings)
844{
845 (void)encoding;
846 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
847 struct bp_pixel_clock_parameters bp_pc_params = {0};
848
849 /* First disable SS
850 * ATOMBIOS will enable by default SS on PLL for DP,
851 * do not disable it here
852 */
853 if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL &&
854 !dc_is_dp_signal(pix_clk_params->signal_type) &&
855 clock_source->ctx->dce_version <= DCE_VERSION_11_0)
856 disable_spread_spectrum(clk_src);
857
858 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
859 bp_pc_params.controller_id = pix_clk_params->controller_id;
860 bp_pc_params.pll_id = clock_source->id;
861 bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
862 bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
863 bp_pc_params.signal_type = pix_clk_params->signal_type;
864
865 bp_pc_params.reference_divider = pll_settings->reference_divider;
866 bp_pc_params.feedback_divider = pll_settings->feedback_divider;
867 bp_pc_params.fractional_feedback_divider =
868 pll_settings->fract_feedback_divider;
869 bp_pc_params.pixel_clock_post_divider =
870 pll_settings->pix_clk_post_divider;
871 bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
872 pll_settings->use_external_clk;
873
874 switch (pix_clk_params->color_depth) {
875 case COLOR_DEPTH_101010:
876 bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_30;
877 break;
878 case COLOR_DEPTH_121212:
879 bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_36;
880 break;
881 case COLOR_DEPTH_161616:
882 bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_48;
883 break;
884 default:
885 break;
886 }
887
888 if (clk_src->bios->funcs->set_pixel_clock(
889 clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
890 return false;
891 /* Enable SS
892 * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
893 * based on HW display PLL team, SS control settings should be programmed
894 * during PLL Reset, but they do not have effect
895 * until SS_EN is asserted.*/
896 if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL
897 && !dc_is_dp_signal(pix_clk_params->signal_type)) {
898
899 if (pix_clk_params->flags.ENABLE_SS)
900 if (!enable_spread_spectrum(clk_src,
901 pix_clk_params->signal_type,
902 pll_settings))
903 return false;
904
905 /* Resync deep color DTO */
906 dce110_program_pixel_clk_resync(clk_src,
907 pix_clk_params->signal_type,
908 pix_clk_params->color_depth);
909 }
910
911 return true;
912}
913
914static bool dce112_program_pix_clk(
915 struct clock_source *clock_source,
916 struct pixel_clk_params *pix_clk_params,
917 enum dp_link_encoding encoding,
918 struct pll_settings *pll_settings)
919{
920 (void)encoding;
921 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
922 struct bp_pixel_clock_parameters bp_pc_params = {0};
923
924 /* First disable SS
925 * ATOMBIOS will enable by default SS on PLL for DP,
926 * do not disable it here
927 */
928 if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL &&
929 !dc_is_dp_signal(pix_clk_params->signal_type) &&
930 clock_source->ctx->dce_version <= DCE_VERSION_11_0)
931 disable_spread_spectrum(clk_src);
932
933 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
934 bp_pc_params.controller_id = pix_clk_params->controller_id;
935 bp_pc_params.pll_id = clock_source->id;
936 bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
937 bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
938 bp_pc_params.signal_type = pix_clk_params->signal_type;
939
940 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
941 bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
942 pll_settings->use_external_clk;
943 bp_pc_params.flags.SET_XTALIN_REF_SRC =
944 !pll_settings->use_external_clk;
945 if (pix_clk_params->flags.SUPPORT_YCBCR420) {
946 bp_pc_params.flags.SUPPORT_YUV_420 = 1;
947 }
948 }
949 if (clk_src->bios->funcs->set_pixel_clock(
950 clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
951 return false;
952 /* Resync deep color DTO */
953 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
954 dce112_program_pixel_clk_resync(clk_src,
955 pix_clk_params->signal_type,
956 pix_clk_params->color_depth,
957 pix_clk_params->flags.SUPPORT_YCBCR420 != 0);
958
959 return true;
960}
961
962static bool dcn31_program_pix_clk(
963 struct clock_source *clock_source,
964 struct pixel_clk_params *pix_clk_params,
965 enum dp_link_encoding encoding,
966 struct pll_settings *pll_settings)
967{
968 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
969 unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
970 unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
971 const struct pixel_rate_range_table_entry *e =
972 look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10);
973 struct bp_pixel_clock_parameters bp_pc_params = {0};
974 enum transmitter_color_depth bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
975
976 // Apply ssed(spread spectrum) dpref clock for edp and dp
977 if (clock_source->ctx->dc->clk_mgr->dp_dto_source_clock_in_khz != 0 &&
978 dc_is_dp_signal(pix_clk_params->signal_type) &&
979 encoding == DP_8b_10b_ENCODING)
980 dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dp_dto_source_clock_in_khz;
981
982 // For these signal types Driver to program DP_DTO without calling VBIOS Command table
983 if (dc_is_hdmi_frl_signal(pix_clk_params->signal_type) ||
984 dc_is_virtual_signal(pix_clk_params->signal_type) ||
985 dc_is_dp_signal(pix_clk_params->signal_type)) {
986 if (e) {
987 /* Set DTO values: phase = target clock, modulo = reference clock*/
988 REG_WRITE(PHASE[inst], e->target_pixel_rate_khz * e->mult_factor);
989 REG_WRITE(MODULO[inst], dp_dto_ref_khz * e->div_factor);
990 } else {
991 /* Set DTO values: phase = target clock, modulo = reference clock*/
992 REG_WRITE(PHASE[inst], pll_settings->actual_pix_clk_100hz * 100);
993 REG_WRITE(MODULO[inst], dp_dto_ref_khz * 1000);
994 }
995 /* Enable DTO */
996 if (clk_src->cs_mask->PIPE0_DTO_SRC_SEL)
997 if (encoding == DP_128b_132b_ENCODING)
998 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
999 DP_DTO0_ENABLE, 1,
1000 PIPE0_DTO_SRC_SEL, 2);
1001 else if (dc_is_hdmi_frl_signal(pix_clk_params->signal_type) || encoding == DP_128b_132b_ENCODING)
1002 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
1003 DP_DTO0_ENABLE, 0,
1004 PIPE0_DTO_SRC_SEL, 2);
1005 else
1006 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
1007 DP_DTO0_ENABLE, 1,
1008 PIPE0_DTO_SRC_SEL, 1);
1009 else
1010 REG_UPDATE(PIXEL_RATE_CNTL[inst],
1011 DP_DTO0_ENABLE, 1);
1012 } else {
1013
1014 if (clk_src->cs_mask->PIPE0_DTO_SRC_SEL)
1015 REG_UPDATE(PIXEL_RATE_CNTL[inst],
1016 PIPE0_DTO_SRC_SEL, 0);
1017
1018 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
1019 bp_pc_params.controller_id = pix_clk_params->controller_id;
1020 bp_pc_params.pll_id = clock_source->id;
1021 bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
1022 bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
1023 bp_pc_params.signal_type = pix_clk_params->signal_type;
1024
1025 // Make sure we send the correct color depth to DMUB for HDMI
1026 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
1027 switch (pix_clk_params->color_depth) {
1028 case COLOR_DEPTH_888:
1029 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1030 break;
1031 case COLOR_DEPTH_101010:
1032 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_30;
1033 break;
1034 case COLOR_DEPTH_121212:
1035 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_36;
1036 break;
1037 case COLOR_DEPTH_161616:
1038 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_48;
1039 break;
1040 default:
1041 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1042 break;
1043 }
1044 bp_pc_params.color_depth = bp_pc_colour_depth;
1045 }
1046
1047 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
1048 bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
1049 pll_settings->use_external_clk;
1050 bp_pc_params.flags.SET_XTALIN_REF_SRC =
1051 !pll_settings->use_external_clk;
1052 if (pix_clk_params->flags.SUPPORT_YCBCR420) {
1053 bp_pc_params.flags.SUPPORT_YUV_420 = 1;
1054 }
1055 }
1056 if (clk_src->bios->funcs->set_pixel_clock(
1057 clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
1058 return false;
1059 /* Resync deep color DTO */
1060 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
1061 dce112_program_pixel_clk_resync(clk_src,
1062 pix_clk_params->signal_type,
1063 pix_clk_params->color_depth,
1064 pix_clk_params->flags.SUPPORT_YCBCR420 != 0);
1065 }
1066
1067 return true;
1068}
1069
1070static bool dcn401_program_pix_clk(
1071 struct clock_source *clock_source,
1072 struct pixel_clk_params *pix_clk_params,
1073 enum dp_link_encoding encoding,
1074 struct pll_settings *pll_settings)
1075{
1076 (void)encoding;
1077 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1078 unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
1079 const struct pixel_rate_range_table_entry *e =
1080 look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10);
1081 struct bp_pixel_clock_parameters bp_pc_params = {0};
1082 enum transmitter_color_depth bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1083 struct dp_dto_params dto_params = { 0 };
1084
1085 dto_params.otg_inst = inst;
1086 dto_params.signal = pix_clk_params->signal_type;
1087
1088 // all but TMDS gets Driver to program DP_DTO without calling VBIOS Command table
1089 if (!dc_is_tmds_signal(pix_clk_params->signal_type)) {
1090 long long dtbclk_p_src_clk_khz;
1091
1092 /* if signal is HDMI FRL dtbclk_p_src is DTBCLK else DPREFCLK */
1093 if (dc_is_hdmi_frl_signal(pix_clk_params->signal_type)) {
1094 dtbclk_p_src_clk_khz = clock_source->ctx->dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(clock_source->ctx->dc->clk_mgr);
1095 dto_params.clk_src = DTBCLK0;
1096 } else {
1097 dtbclk_p_src_clk_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
1098 dto_params.clk_src = DPREFCLK;
1099 }
1100
1101 if (e) {
1102 dto_params.pixclk_hz = e->target_pixel_rate_khz;
1103 dto_params.pixclk_hz *= e->mult_factor;
1104 dto_params.refclk_hz = dtbclk_p_src_clk_khz;
1105 dto_params.refclk_hz *= e->div_factor;
1106 } else {
1107 dto_params.pixclk_hz = pix_clk_params->requested_pix_clk_100hz;
1108 dto_params.pixclk_hz *= 100;
1109 dto_params.refclk_hz = dtbclk_p_src_clk_khz;
1110 dto_params.refclk_hz *= 1000;
1111 }
1112
1113 /* enable DP DTO */
1114 clock_source->ctx->dc->res_pool->dccg->funcs->set_dp_dto(
1115 clock_source->ctx->dc->res_pool->dccg,
1116 &dto_params);
1117 if (clock_source->ctx->dc->caps.is_apu &&
1118 pix_clk_params->requested_pix_clk_100hz &&
1119 dc_is_hdmi_frl_signal(pix_clk_params->signal_type)) {
1120 //make sure dtbclk is enabled
1121 if (clock_source->ctx->dc->clk_mgr->funcs->request_dtbclk)
1122 clock_source->ctx->dc->clk_mgr->funcs->request_dtbclk(
1123 clock_source->ctx->dc->clk_mgr, true);
1124 /*need hdmistreamclk before vpg block register access*/
1125 clock_source->ctx->dc->res_pool->dccg->funcs->set_hdmistreamclk(
1126 clock_source->ctx->dc->res_pool->dccg,
1127 DTBCLK0,
1128 pix_clk_params->controller_id - 1);
1129 }
1130 } else {
1131 if (pll_settings->actual_pix_clk_100hz > 6000000UL)
1132 return false;
1133
1134 /* disables DP DTO when provided with TMDS signal type */
1135 clock_source->ctx->dc->res_pool->dccg->funcs->set_dp_dto(
1136 clock_source->ctx->dc->res_pool->dccg,
1137 &dto_params);
1138
1139 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
1140 bp_pc_params.controller_id = pix_clk_params->controller_id;
1141 bp_pc_params.pll_id = clock_source->id;
1142 bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
1143 bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
1144 bp_pc_params.signal_type = pix_clk_params->signal_type;
1145
1146 // Make sure we send the correct color depth to DMUB for HDMI
1147 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
1148 switch (pix_clk_params->color_depth) {
1149 case COLOR_DEPTH_888:
1150 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1151 break;
1152 case COLOR_DEPTH_101010:
1153 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_30;
1154 break;
1155 case COLOR_DEPTH_121212:
1156 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_36;
1157 break;
1158 case COLOR_DEPTH_161616:
1159 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_48;
1160 break;
1161 default:
1162 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1163 break;
1164 }
1165 bp_pc_params.color_depth = bp_pc_colour_depth;
1166 }
1167
1168 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
1169 bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
1170 pll_settings->use_external_clk;
1171 bp_pc_params.flags.SET_XTALIN_REF_SRC =
1172 !pll_settings->use_external_clk;
1173 if (pix_clk_params->flags.SUPPORT_YCBCR420) {
1174 bp_pc_params.flags.SUPPORT_YUV_420 = 1;
1175 }
1176 }
1177 if (clk_src->bios->funcs->set_pixel_clock(
1178 clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
1179 return false;
1180 /* Resync deep color DTO */
1181 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
1182 dce112_program_pixel_clk_resync(clk_src,
1183 pix_clk_params->signal_type,
1184 pix_clk_params->color_depth,
1185 pix_clk_params->flags.SUPPORT_YCBCR420 != 0);
1186 }
1187
1188 return true;
1189}
1190
1191static bool dce110_clock_source_power_down(
1192 struct clock_source *clk_src)
1193{
1194 struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src);
1195 enum bp_result bp_result;
1196 struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
1197
1198 if (clk_src->dp_clk_src)
1199 return true;
1200
1201 /* If Pixel Clock is 0 it means Power Down Pll*/
1202 bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
1203 bp_pixel_clock_params.pll_id = clk_src->id;
1204 bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
1205
1206 /*Call ASICControl to process ATOMBIOS Exec table*/
1207 bp_result = dce110_clk_src->bios->funcs->set_pixel_clock(
1208 dce110_clk_src->bios,
1209 &bp_pixel_clock_params);
1210
1211 return bp_result == BP_RESULT_OK;
1212}
1213
1214static bool get_dp_dto_frequency_100hz(
1215 const struct clock_source *clock_source,
1216 unsigned int inst,
1217 unsigned int *pixel_clk_100hz)
1218{
1219 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1220 unsigned int clock_hz = 0;
1221 unsigned int modulo_hz = 0;
1222 unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
1223 unsigned long long temp = 0;
1224
1225 if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
1226 clock_hz = REG_READ(PHASE[inst]);
1227
1228 if (clock_source->ctx->dc->hwss.enable_vblanks_synchronization &&
1229 clock_source->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0) {
1230 /* NOTE: In case VBLANK syncronization is enabled, MODULO may
1231 * not be programmed equal to DPREFCLK
1232 */
1233 modulo_hz = REG_READ(MODULO[inst]);
1234 if (modulo_hz) {
1235 temp = clock_hz * dp_dto_ref_khz * 10;
1236 ASSERT(temp <= UINT_MAX * modulo_hz * 100ULL);
1237 *pixel_clk_100hz = div_u64(temp, modulo_hz * 100);
1238 } else
1239 *pixel_clk_100hz = 0;
1240 } else {
1241 /* NOTE: There is agreement with VBIOS here that MODULO is
1242 * programmed equal to DPREFCLK, in which case PHASE will be
1243 * equivalent to pixel clock.
1244 */
1245 *pixel_clk_100hz = clock_hz / 100;
1246 }
1247 return true;
1248 }
1249
1250 return false;
1251}
1252
1253static bool dcn401_get_dp_dto_frequency_100hz(const struct clock_source *clock_source, unsigned int inst,
1254 unsigned int *pixel_clk_100hz)
1255{
1256 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1257 unsigned int phase_hz = 0;
1258 unsigned int modulo_hz = 0;
1259 unsigned int dp_dto_integer = 0;
1260 unsigned long long temp = 0;
1261
1262 if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
1263 phase_hz = REG_READ(PHASE[inst]);
1264 modulo_hz = REG_READ(MODULO[inst]);
1265
1266 switch (inst) {
1267 case 0:
1268 REG_GET(OTG_PIXEL_RATE_DIV, DPDTO0_INT, &dp_dto_integer);
1269 break;
1270 case 1:
1271 REG_GET(OTG_PIXEL_RATE_DIV, DPDTO1_INT, &dp_dto_integer);
1272 break;
1273 case 2:
1274 REG_GET(OTG_PIXEL_RATE_DIV, DPDTO2_INT, &dp_dto_integer);
1275 break;
1276 case 3:
1277 REG_GET(OTG_PIXEL_RATE_DIV, DPDTO3_INT, &dp_dto_integer);
1278 break;
1279 default:
1280 BREAK_TO_DEBUGGER();
1281 break;
1282 }
1283
1284 /* On DCN4x, the DCCG DPDTO is directly programmed with the required pixel clock as per the following formula:
1285 * - DPDTO INTEGER = INT(4:4:4 pixel rate / DTBCLK_P rate)
1286 * - DPDTO PHASE = 4:4:4 pixel rate – DPDTO INTEGER * DTBCLK_P rate
1287 * - DPDTO MODULO = DTBCLK_P rate
1288 * - target pix_clk_hz = (DPDTO INTEGER * DPDTO MODULO + DPDTO PHASE)
1289 */
1290 temp = (unsigned long long)dp_dto_integer * modulo_hz + phase_hz;
1291 if (temp > (UINT_MAX * 100ULL)) {
1292 /* pixel rate 100hz should never be this high, if it is, throw an assert and return 0 */
1293 BREAK_TO_DEBUGGER();
1294 *pixel_clk_100hz = 0;
1295 } else {
1296 *pixel_clk_100hz = div_u64(temp, 100);
1297 }
1298
1299 return true;
1300 }
1301
1302 return false;
1303}
1304
1305/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
1306const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] = {
1307 // /1.001 rates
1308 {25170, 25180, 25200, 1000, 1001}, //25.2MHz -> 25.17
1309 {59340, 59350, 59400, 1000, 1001}, //59.4Mhz -> 59.340
1310 {74170, 74180, 74250, 1000, 1001}, //74.25Mhz -> 74.1758
1311 {89910, 90000, 90000, 1000, 1001}, //90Mhz -> 89.91
1312 {125870, 125880, 126000, 1000, 1001}, //126Mhz -> 125.87
1313 {148350, 148360, 148500, 1000, 1001}, //148.5Mhz -> 148.3516
1314 {167830, 167840, 168000, 1000, 1001}, //168Mhz -> 167.83
1315 {222520, 222530, 222750, 1000, 1001}, //222.75Mhz -> 222.527
1316 {257140, 257150, 257400, 1000, 1001}, //257.4Mhz -> 257.1429
1317 {296700, 296710, 297000, 1000, 1001}, //297Mhz -> 296.7033
1318 {342850, 342860, 343200, 1000, 1001}, //343.2Mhz -> 342.857
1319 {395600, 395610, 396000, 1000, 1001}, //396Mhz -> 395.6
1320 {409090, 409100, 409500, 1000, 1001}, //409.5Mhz -> 409.091
1321 {445050, 445060, 445500, 1000, 1001}, //445.5Mhz -> 445.055
1322 {467530, 467540, 468000, 1000, 1001}, //468Mhz -> 467.5325
1323 {519230, 519240, 519750, 1000, 1001}, //519.75Mhz -> 519.231
1324 {525970, 525980, 526500, 1000, 1001}, //526.5Mhz -> 525.974
1325 {545450, 545460, 546000, 1000, 1001}, //546Mhz -> 545.455
1326 {593400, 593410, 594000, 1000, 1001}, //594Mhz -> 593.4066
1327 {623370, 623380, 624000, 1000, 1001}, //624Mhz -> 623.377
1328 {692300, 692310, 693000, 1000, 1001}, //693Mhz -> 692.308
1329 {701290, 701300, 702000, 1000, 1001}, //702Mhz -> 701.2987
1330 {791200, 791210, 792000, 1000, 1001}, //792Mhz -> 791.209
1331 {890100, 890110, 891000, 1000, 1001}, //891Mhz -> 890.1099
1332 {1186810, 1186820, 1188000, 1000, 1001},//1188Mhz -> 1186.8131
1333
1334 // *1.001 rates
1335 {27020, 27030, 27000, 1001, 1000}, //27Mhz
1336 {54050, 54060, 54000, 1001, 1000}, //54Mhz
1337 {108100, 108110, 108000, 1001, 1000},//108Mhz
1338};
1339
1340const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb(
1341 unsigned int pixel_rate_khz)
1342{
1343 int i;
1344
1345 for (i = 0; i < ARRAY_SIZE(video_optimized_pixel_rates); i++) {
1346 const struct pixel_rate_range_table_entry *e = &video_optimized_pixel_rates[i];
1347
1348 if (e->range_min_khz <= pixel_rate_khz && pixel_rate_khz <= e->range_max_khz) {
1349 return e;
1350 }
1351 }
1352
1353 return NULL;
1354}
1355
1356static bool dcn20_program_pix_clk(
1357 struct clock_source *clock_source,
1358 struct pixel_clk_params *pix_clk_params,
1359 enum dp_link_encoding encoding,
1360 struct pll_settings *pll_settings)
1361{
1362 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1363 unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
1364
1365 dce112_program_pix_clk(clock_source, pix_clk_params, encoding, pll_settings);
1366
1367 if (clock_source->ctx->dc->hwss.enable_vblanks_synchronization &&
1368 clock_source->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0) {
1369 /* NOTE: In case VBLANK syncronization is enabled,
1370 * we need to set modulo to default DPREFCLK first
1371 * dce112_program_pix_clk does not set default DPREFCLK
1372 */
1373 REG_WRITE(MODULO[inst],
1374 clock_source->ctx->dc->clk_mgr->dprefclk_khz*1000);
1375 }
1376 return true;
1377}
1378
1379static bool dcn20_override_dp_pix_clk(
1380 struct clock_source *clock_source,
1381 unsigned int inst,
1382 unsigned int pixel_clk,
1383 unsigned int ref_clk)
1384{
1385 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1386
1387 REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 0);
1388 REG_WRITE(PHASE[inst], pixel_clk);
1389 REG_WRITE(MODULO[inst], ref_clk);
1390 REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
1391 return true;
1392}
1393
1394static const struct clock_source_funcs dcn20_clk_src_funcs = {
1395 .cs_power_down = dce110_clock_source_power_down,
1396 .program_pix_clk = dcn20_program_pix_clk,
1397 .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
1398 .get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz,
1399 .override_dp_pix_clk = dcn20_override_dp_pix_clk
1400};
1401
1402static bool dcn3_program_pix_clk(
1403 struct clock_source *clock_source,
1404 struct pixel_clk_params *pix_clk_params,
1405 enum dp_link_encoding encoding,
1406 struct pll_settings *pll_settings)
1407{
1408 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1409 unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
1410 unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
1411 const struct pixel_rate_range_table_entry *e =
1412 look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10);
1413
1414 // For these signal types Driver to program DP_DTO without calling VBIOS Command table
1415 if ((pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_FRL) || dc_is_dp_signal(pix_clk_params->signal_type)) {
1416 if (e) {
1417 /* Set DTO values: phase = target clock, modulo = reference clock*/
1418 REG_WRITE(PHASE[inst], e->target_pixel_rate_khz * e->mult_factor);
1419 REG_WRITE(MODULO[inst], dp_dto_ref_khz * e->div_factor);
1420 } else {
1421 /* Set DTO values: phase = target clock, modulo = reference clock*/
1422 REG_WRITE(PHASE[inst], pll_settings->actual_pix_clk_100hz * 100);
1423 REG_WRITE(MODULO[inst], dp_dto_ref_khz * 1000);
1424 }
1425 /* Enable DTO */
1426 if (clk_src->cs_mask->PIPE0_DTO_SRC_SEL)
1427 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
1428 DP_DTO0_ENABLE, 1,
1429 PIPE0_DTO_SRC_SEL, 1);
1430 else
1431 REG_UPDATE(PIXEL_RATE_CNTL[inst],
1432 DP_DTO0_ENABLE, 1);
1433 } else
1434 // For other signal types(HDMI_TYPE_A, DVI) Driver still to call VBIOS Command table
1435 dce112_program_pix_clk(clock_source, pix_clk_params, encoding, pll_settings);
1436
1437 return true;
1438}
1439
1440static uint32_t dcn3_get_pix_clk_dividers(
1441 struct clock_source *cs,
1442 struct pixel_clk_params *pix_clk_params,
1443 struct pll_settings *pll_settings)
1444{
1445 unsigned long long actual_pix_clk_100Hz = pix_clk_params ? pix_clk_params->requested_pix_clk_100hz : 0;
1446 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
1447
1448 if (pix_clk_params == NULL || pll_settings == NULL
1449 || pix_clk_params->requested_pix_clk_100hz == 0) {
1450 DC_LOG_ERROR(
1451 "%s: Invalid parameters!!\n", __func__);
1452 return UINT_MAX;
1453 }
1454
1455 memset(pll_settings, 0, sizeof(*pll_settings));
1456 /* Adjust for HDMI Type A deep color */
1457 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
1458 switch (pix_clk_params->color_depth) {
1459 case COLOR_DEPTH_101010:
1460 actual_pix_clk_100Hz = (actual_pix_clk_100Hz * 5) >> 2;
1461 break;
1462 case COLOR_DEPTH_121212:
1463 actual_pix_clk_100Hz = (actual_pix_clk_100Hz * 6) >> 2;
1464 break;
1465 case COLOR_DEPTH_161616:
1466 actual_pix_clk_100Hz = actual_pix_clk_100Hz * 2;
1467 break;
1468 default:
1469 break;
1470 }
1471 }
1472 pll_settings->actual_pix_clk_100hz = (unsigned int) actual_pix_clk_100Hz;
1473 pll_settings->adjusted_pix_clk_100hz = (unsigned int) actual_pix_clk_100Hz;
1474 pll_settings->calculated_pix_clk_100hz = (unsigned int) actual_pix_clk_100Hz;
1475
1476 return 0;
1477}
1478
1479static const struct clock_source_funcs dcn3_clk_src_funcs = {
1480 .cs_power_down = dce110_clock_source_power_down,
1481 .program_pix_clk = dcn3_program_pix_clk,
1482 .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
1483 .get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
1484};
1485
1486static const struct clock_source_funcs dcn31_clk_src_funcs = {
1487 .cs_power_down = dce110_clock_source_power_down,
1488 .program_pix_clk = dcn31_program_pix_clk,
1489 .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
1490 .get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
1491};
1492
1493static const struct clock_source_funcs dcn401_clk_src_funcs = {
1494 .cs_power_down = dce110_clock_source_power_down,
1495 .program_pix_clk = dcn401_program_pix_clk,
1496 .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
1497 .get_dp_dto_frequency_100hz = dcn401_get_dp_dto_frequency_100hz
1498};
1499
1500static const struct clock_source_funcs dcn50_clk_src_funcs = {
1501 .cs_power_down = dce110_clock_source_power_down,
1502 .program_pix_clk = dcn401_program_pix_clk,
1503 .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
1504 .get_dp_dto_frequency_100hz = dcn401_get_dp_dto_frequency_100hz
1505};
1506
1507/*****************************************/
1508/* Constructor */
1509/*****************************************/
1510
1511static const struct clock_source_funcs dce112_clk_src_funcs = {
1512 .cs_power_down = dce110_clock_source_power_down,
1513 .program_pix_clk = dce112_program_pix_clk,
1514 .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
1515 .get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
1516};
1517static const struct clock_source_funcs dce110_clk_src_funcs = {
1518 .cs_power_down = dce110_clock_source_power_down,
1519 .program_pix_clk = dce110_program_pix_clk,
1520 .get_pix_clk_dividers = dce110_get_pix_clk_dividers,
1521 .get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
1522};
1523
1524static void get_ss_info_from_atombios(
1525 struct dce110_clk_src *clk_src,
1526 enum as_signal_type as_signal,
1527 struct spread_spectrum_data *spread_spectrum_data[],
1528 uint32_t *ss_entries_num)
1529{
1530 enum bp_result bp_result = BP_RESULT_FAILURE;
1531 struct spread_spectrum_info *ss_info;
1532 struct spread_spectrum_data *ss_data;
1533 struct spread_spectrum_info *ss_info_cur;
1534 struct spread_spectrum_data *ss_data_cur;
1535 uint32_t i;
1536
1537 if (ss_entries_num == NULL) {
1538 DC_LOG_SYNC(
1539 "Invalid entry !!!\n");
1540 return;
1541 }
1542 if (spread_spectrum_data == NULL) {
1543 DC_LOG_SYNC(
1544 "Invalid array pointer!!!\n");
1545 return;
1546 }
1547
1548 spread_spectrum_data[0] = NULL;
1549 *ss_entries_num = 0;
1550
1551 *ss_entries_num = clk_src->bios->funcs->get_ss_entry_number(
1552 clk_src->bios,
1553 as_signal);
1554
1555 if (*ss_entries_num == 0)
1556 return;
1557
1558 ss_info = kzalloc_objs(struct spread_spectrum_info, *ss_entries_num);
1559 ss_info_cur = ss_info;
1560 if (ss_info == NULL)
1561 return;
1562
1563 ss_data = kzalloc_objs(struct spread_spectrum_data, *ss_entries_num);
1564 if (ss_data == NULL)
1565 goto out_free_info;
1566
1567 for (i = 0, ss_info_cur = ss_info;
1568 i < (*ss_entries_num);
1569 ++i, ++ss_info_cur) {
1570
1571 bp_result = clk_src->bios->funcs->get_spread_spectrum_info(
1572 clk_src->bios,
1573 as_signal,
1574 i,
1575 ss_info_cur);
1576
1577 if (bp_result != BP_RESULT_OK)
1578 goto out_free_data;
1579 }
1580
1581 for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data;
1582 i < (*ss_entries_num);
1583 ++i, ++ss_info_cur, ++ss_data_cur) {
1584
1585 if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) {
1586 DC_LOG_SYNC(
1587 "Invalid ATOMBIOS SS Table!!!\n");
1588 goto out_free_data;
1589 }
1590
1591 /* for HDMI check SS percentage,
1592 * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1593 if (as_signal == AS_SIGNAL_TYPE_HDMI
1594 && ss_info_cur->spread_spectrum_percentage > 6){
1595 /* invalid input, do nothing */
1596 DC_LOG_SYNC(
1597 "Invalid SS percentage ");
1598 DC_LOG_SYNC(
1599 "for HDMI in ATOMBIOS info Table!!!\n");
1600 continue;
1601 }
1602 if (ss_info_cur->spread_percentage_divider == 1000) {
1603 /* Keep previous precision from ATOMBIOS for these
1604 * in case new precision set by ATOMBIOS for these
1605 * (otherwise all code in DCE specific classes
1606 * for all previous ASICs would need
1607 * to be updated for SS calculations,
1608 * Audio SS compensation and DP DTO SS compensation
1609 * which assumes fixed SS percentage Divider = 100)*/
1610 ss_info_cur->spread_spectrum_percentage /= 10;
1611 ss_info_cur->spread_percentage_divider = 100;
1612 }
1613
1614 ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range;
1615 ss_data_cur->percentage =
1616 ss_info_cur->spread_spectrum_percentage;
1617 ss_data_cur->percentage_divider =
1618 ss_info_cur->spread_percentage_divider;
1619 ss_data_cur->modulation_freq_hz =
1620 ss_info_cur->spread_spectrum_range;
1621
1622 if (ss_info_cur->type.CENTER_MODE)
1623 ss_data_cur->flags.CENTER_SPREAD = 1;
1624
1625 if (ss_info_cur->type.EXTERNAL)
1626 ss_data_cur->flags.EXTERNAL_SS = 1;
1627
1628 }
1629
1630 *spread_spectrum_data = ss_data;
1631 kfree(ss_info);
1632 return;
1633
1634out_free_data:
1635 kfree(ss_data);
1636 *ss_entries_num = 0;
1637out_free_info:
1638 kfree(ss_info);
1639}
1640
1641static void ss_info_from_atombios_create(
1642 struct dce110_clk_src *clk_src)
1643{
1644 get_ss_info_from_atombios(
1645 clk_src,
1646 AS_SIGNAL_TYPE_DISPLAY_PORT,
1647 &clk_src->dp_ss_params,
1648 &clk_src->dp_ss_params_cnt);
1649 get_ss_info_from_atombios(
1650 clk_src,
1651 AS_SIGNAL_TYPE_HDMI,
1652 &clk_src->hdmi_ss_params,
1653 &clk_src->hdmi_ss_params_cnt);
1654 get_ss_info_from_atombios(
1655 clk_src,
1656 AS_SIGNAL_TYPE_DVI,
1657 &clk_src->dvi_ss_params,
1658 &clk_src->dvi_ss_params_cnt);
1659 get_ss_info_from_atombios(
1660 clk_src,
1661 AS_SIGNAL_TYPE_LVDS,
1662 &clk_src->lvds_ss_params,
1663 &clk_src->lvds_ss_params_cnt);
1664}
1665
1666static bool calc_pll_max_vco_construct(
1667 struct dce110_clk_src *clk_src,
1668 struct calc_pll_clock_source *calc_pll_cs,
1669 struct calc_pll_clock_source_init_data *init_data)
1670{
1671 uint32_t i;
1672 struct dc_firmware_info *fw_info;
1673 if (calc_pll_cs == NULL ||
1674 init_data == NULL ||
1675 init_data->bp == NULL)
1676 return false;
1677
1678 if (!init_data->bp->fw_info_valid)
1679 return false;
1680
1681 fw_info = &init_data->bp->fw_info;
1682 calc_pll_cs->ctx = init_data->ctx;
1683 calc_pll_cs->ref_freq_khz = fw_info->pll_info.crystal_frequency;
1684 calc_pll_cs->min_vco_khz =
1685 fw_info->pll_info.min_output_pxl_clk_pll_frequency;
1686 calc_pll_cs->max_vco_khz =
1687 fw_info->pll_info.max_output_pxl_clk_pll_frequency;
1688
1689 if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0)
1690 calc_pll_cs->max_pll_input_freq_khz =
1691 init_data->max_override_input_pxl_clk_pll_freq_khz;
1692 else
1693 calc_pll_cs->max_pll_input_freq_khz =
1694 fw_info->pll_info.max_input_pxl_clk_pll_frequency;
1695
1696 if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0)
1697 calc_pll_cs->min_pll_input_freq_khz =
1698 init_data->min_override_input_pxl_clk_pll_freq_khz;
1699 else
1700 calc_pll_cs->min_pll_input_freq_khz =
1701 fw_info->pll_info.min_input_pxl_clk_pll_frequency;
1702
1703 calc_pll_cs->min_pix_clock_pll_post_divider =
1704 init_data->min_pix_clk_pll_post_divider;
1705 calc_pll_cs->max_pix_clock_pll_post_divider =
1706 init_data->max_pix_clk_pll_post_divider;
1707 calc_pll_cs->min_pll_ref_divider =
1708 init_data->min_pll_ref_divider;
1709 calc_pll_cs->max_pll_ref_divider =
1710 init_data->max_pll_ref_divider;
1711
1712 if (init_data->num_fract_fb_divider_decimal_point == 0 ||
1713 init_data->num_fract_fb_divider_decimal_point_precision >
1714 init_data->num_fract_fb_divider_decimal_point) {
1715 DC_LOG_ERROR(
1716 "The dec point num or precision is incorrect!");
1717 return false;
1718 }
1719 if (init_data->num_fract_fb_divider_decimal_point_precision == 0) {
1720 DC_LOG_ERROR(
1721 "Incorrect fract feedback divider precision num!");
1722 return false;
1723 }
1724
1725 calc_pll_cs->fract_fb_divider_decimal_points_num =
1726 init_data->num_fract_fb_divider_decimal_point;
1727 calc_pll_cs->fract_fb_divider_precision =
1728 init_data->num_fract_fb_divider_decimal_point_precision;
1729 calc_pll_cs->fract_fb_divider_factor = 1;
1730 for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i)
1731 calc_pll_cs->fract_fb_divider_factor *= 10;
1732
1733 calc_pll_cs->fract_fb_divider_precision_factor = 1;
1734 for (
1735 i = 0;
1736 i < (calc_pll_cs->fract_fb_divider_decimal_points_num -
1737 calc_pll_cs->fract_fb_divider_precision);
1738 ++i)
1739 calc_pll_cs->fract_fb_divider_precision_factor *= 10;
1740
1741 return true;
1742}
1743
1744bool dce110_clk_src_construct(
1745 struct dce110_clk_src *clk_src,
1746 struct dc_context *ctx,
1747 struct dc_bios *bios,
1748 enum clock_source_id id,
1749 const struct dce110_clk_src_regs *regs,
1750 const struct dce110_clk_src_shift *cs_shift,
1751 const struct dce110_clk_src_mask *cs_mask)
1752{
1753 struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi;
1754 struct calc_pll_clock_source_init_data calc_pll_cs_init_data;
1755
1756 clk_src->base.ctx = ctx;
1757 clk_src->bios = bios;
1758 clk_src->base.id = id;
1759 clk_src->base.funcs = &dce110_clk_src_funcs;
1760
1761 clk_src->regs = regs;
1762 clk_src->cs_shift = cs_shift;
1763 clk_src->cs_mask = cs_mask;
1764
1765 if (!clk_src->bios->fw_info_valid) {
1766 ASSERT_CRITICAL(false);
1767 goto unexpected_failure;
1768 }
1769
1770 clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp;
1771
1772 /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1773 calc_pll_cs_init_data.bp = bios;
1774 calc_pll_cs_init_data.min_pix_clk_pll_post_divider = 1;
1775 calc_pll_cs_init_data.max_pix_clk_pll_post_divider =
1776 clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1777 calc_pll_cs_init_data.min_pll_ref_divider = 1;
1778 calc_pll_cs_init_data.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV;
1779 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1780 calc_pll_cs_init_data.min_override_input_pxl_clk_pll_freq_khz = 0;
1781 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1782 calc_pll_cs_init_data.max_override_input_pxl_clk_pll_freq_khz = 0;
1783 /*numberOfFractFBDividerDecimalPoints*/
1784 calc_pll_cs_init_data.num_fract_fb_divider_decimal_point =
1785 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1786 /*number of decimal point to round off for fractional feedback divider value*/
1787 calc_pll_cs_init_data.num_fract_fb_divider_decimal_point_precision =
1788 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1789 calc_pll_cs_init_data.ctx = ctx;
1790
1791 /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1792 calc_pll_cs_init_data_hdmi.bp = bios;
1793 calc_pll_cs_init_data_hdmi.min_pix_clk_pll_post_divider = 1;
1794 calc_pll_cs_init_data_hdmi.max_pix_clk_pll_post_divider =
1795 clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1796 calc_pll_cs_init_data_hdmi.min_pll_ref_divider = 1;
1797 calc_pll_cs_init_data_hdmi.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV;
1798 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1799 calc_pll_cs_init_data_hdmi.min_override_input_pxl_clk_pll_freq_khz = 13500;
1800 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1801 calc_pll_cs_init_data_hdmi.max_override_input_pxl_clk_pll_freq_khz = 27000;
1802 /*numberOfFractFBDividerDecimalPoints*/
1803 calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point =
1804 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1805 /*number of decimal point to round off for fractional feedback divider value*/
1806 calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point_precision =
1807 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1808 calc_pll_cs_init_data_hdmi.ctx = ctx;
1809
1810 clk_src->ref_freq_khz = clk_src->bios->fw_info.pll_info.crystal_frequency;
1811
1812 if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL)
1813 return true;
1814
1815 /* PLL only from here on */
1816 ss_info_from_atombios_create(clk_src);
1817
1818 if (!calc_pll_max_vco_construct(
1819 clk_src,
1820 &clk_src->calc_pll,
1821 &calc_pll_cs_init_data)) {
1822 ASSERT_CRITICAL(false);
1823 goto unexpected_failure;
1824 }
1825
1826
1827 calc_pll_cs_init_data_hdmi.
1828 min_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz/2;
1829 calc_pll_cs_init_data_hdmi.
1830 max_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz;
1831
1832
1833 if (!calc_pll_max_vco_construct(
1834 clk_src, &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
1835 ASSERT_CRITICAL(false);
1836 goto unexpected_failure;
1837 }
1838
1839 return true;
1840
1841unexpected_failure:
1842 return false;
1843}
1844
1845bool dce112_clk_src_construct(
1846 struct dce110_clk_src *clk_src,
1847 struct dc_context *ctx,
1848 struct dc_bios *bios,
1849 enum clock_source_id id,
1850 const struct dce110_clk_src_regs *regs,
1851 const struct dce110_clk_src_shift *cs_shift,
1852 const struct dce110_clk_src_mask *cs_mask)
1853{
1854 clk_src->base.ctx = ctx;
1855 clk_src->bios = bios;
1856 clk_src->base.id = id;
1857 clk_src->base.funcs = &dce112_clk_src_funcs;
1858
1859 clk_src->regs = regs;
1860 clk_src->cs_shift = cs_shift;
1861 clk_src->cs_mask = cs_mask;
1862
1863 if (!clk_src->bios->fw_info_valid) {
1864 ASSERT_CRITICAL(false);
1865 return false;
1866 }
1867
1868 clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp;
1869
1870 return true;
1871}
1872
1873bool dcn20_clk_src_construct(
1874 struct dce110_clk_src *clk_src,
1875 struct dc_context *ctx,
1876 struct dc_bios *bios,
1877 enum clock_source_id id,
1878 const struct dce110_clk_src_regs *regs,
1879 const struct dce110_clk_src_shift *cs_shift,
1880 const struct dce110_clk_src_mask *cs_mask)
1881{
1882 bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1883
1884 clk_src->base.funcs = &dcn20_clk_src_funcs;
1885
1886 return ret;
1887}
1888
1889bool dcn3_clk_src_construct(
1890 struct dce110_clk_src *clk_src,
1891 struct dc_context *ctx,
1892 struct dc_bios *bios,
1893 enum clock_source_id id,
1894 const struct dce110_clk_src_regs *regs,
1895 const struct dce110_clk_src_shift *cs_shift,
1896 const struct dce110_clk_src_mask *cs_mask)
1897{
1898 bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1899
1900 clk_src->base.funcs = &dcn3_clk_src_funcs;
1901
1902 return ret;
1903}
1904
1905bool dcn31_clk_src_construct(
1906 struct dce110_clk_src *clk_src,
1907 struct dc_context *ctx,
1908 struct dc_bios *bios,
1909 enum clock_source_id id,
1910 const struct dce110_clk_src_regs *regs,
1911 const struct dce110_clk_src_shift *cs_shift,
1912 const struct dce110_clk_src_mask *cs_mask)
1913{
1914 bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1915
1916 clk_src->base.funcs = &dcn31_clk_src_funcs;
1917
1918 return ret;
1919}
1920
1921bool dcn401_clk_src_construct(
1922 struct dce110_clk_src *clk_src,
1923 struct dc_context *ctx,
1924 struct dc_bios *bios,
1925 enum clock_source_id id,
1926 const struct dce110_clk_src_regs *regs,
1927 const struct dce110_clk_src_shift *cs_shift,
1928 const struct dce110_clk_src_mask *cs_mask)
1929{
1930 bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1931
1932 clk_src->base.funcs = &dcn401_clk_src_funcs;
1933
1934 return ret;
1935}
1936
1937bool dcn50_clk_src_construct(
1938 struct dce110_clk_src *clk_src,
1939 struct dc_context *ctx,
1940 struct dc_bios *bios,
1941 enum clock_source_id id,
1942 const struct dce110_clk_src_regs *regs,
1943 const struct dce110_clk_src_shift *cs_shift,
1944 const struct dce110_clk_src_mask *cs_mask)
1945{
1946 bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1947
1948 clk_src->base.funcs = &dcn50_clk_src_funcs;
1949
1950 return ret;
1951}
1952
1953bool dcn301_clk_src_construct(
1954 struct dce110_clk_src *clk_src,
1955 struct dc_context *ctx,
1956 struct dc_bios *bios,
1957 enum clock_source_id id,
1958 const struct dce110_clk_src_regs *regs,
1959 const struct dce110_clk_src_shift *cs_shift,
1960 const struct dce110_clk_src_mask *cs_mask)
1961{
1962 bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1963
1964 clk_src->base.funcs = &dcn3_clk_src_funcs;
1965
1966 return ret;
1967}