2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dm_services.h"
30 #include "core_types.h"
32 #include "include/grph_object_id.h"
33 #include "include/logger_interface.h"
35 #include "dce_clock_source.h"
39 #include "reg_helper.h"
48 calc_pll_cs->ctx->logger
49 #define DC_LOGGER_INIT() \
50 struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll
53 #define FN(reg_name, field_name) \
54 clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
56 #define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
57 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
58 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF
60 #define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
62 static const struct spread_spectrum_data
*get_ss_data_entry(
63 struct dce110_clk_src
*clk_src
,
64 enum signal_type signal
,
70 struct spread_spectrum_data
*ss_parm
= NULL
;
71 struct spread_spectrum_data
*ret
= NULL
;
74 case SIGNAL_TYPE_DVI_SINGLE_LINK
:
75 case SIGNAL_TYPE_DVI_DUAL_LINK
:
76 ss_parm
= clk_src
->dvi_ss_params
;
77 entrys_num
= clk_src
->dvi_ss_params_cnt
;
80 case SIGNAL_TYPE_HDMI_TYPE_A
:
81 ss_parm
= clk_src
->hdmi_ss_params
;
82 entrys_num
= clk_src
->hdmi_ss_params_cnt
;
85 case SIGNAL_TYPE_LVDS
:
86 ss_parm
= clk_src
->lvds_ss_params
;
87 entrys_num
= clk_src
->lvds_ss_params_cnt
;
90 case SIGNAL_TYPE_DISPLAY_PORT
:
91 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
93 case SIGNAL_TYPE_VIRTUAL
:
94 ss_parm
= clk_src
->dp_ss_params
;
95 entrys_num
= clk_src
->dp_ss_params_cnt
;
107 for (i
= 0; i
< entrys_num
; ++i
, ++ss_parm
) {
108 if (ss_parm
->freq_range_khz
>= pix_clk_khz
) {
118 * calculate_fb_and_fractional_fb_divider - Calculates feedback and fractional
119 * feedback dividers values
121 * @calc_pll_cs: Pointer to clock source information
122 * @target_pix_clk_100hz: Desired frequency in 100 Hz
123 * @ref_divider: Reference divider (already known)
124 * @post_divider: Post Divider (already known)
125 * @feedback_divider_param: Pointer where to store
126 * calculated feedback divider value
127 * @fract_feedback_divider_param: Pointer where to store
128 * calculated fract feedback divider value
131 * It fills the locations pointed by feedback_divider_param
132 * and fract_feedback_divider_param
133 * It returns - true if feedback divider not 0
134 * - false should never happen)
136 static bool calculate_fb_and_fractional_fb_divider(
137 struct calc_pll_clock_source
*calc_pll_cs
,
138 uint32_t target_pix_clk_100hz
,
139 uint32_t ref_divider
,
140 uint32_t post_divider
,
141 uint32_t *feedback_divider_param
,
142 uint32_t *fract_feedback_divider_param
)
144 uint64_t feedback_divider
;
147 (uint64_t)target_pix_clk_100hz
* ref_divider
* post_divider
;
148 feedback_divider
*= 10;
149 /* additional factor, since we divide by 10 afterwards */
150 feedback_divider
*= (uint64_t)(calc_pll_cs
->fract_fb_divider_factor
);
151 feedback_divider
= div_u64(feedback_divider
, calc_pll_cs
->ref_freq_khz
* 10ull);
153 /*Round to the number of precision
154 * The following code replace the old code (ullfeedbackDivider + 5)/10
155 * for example if the difference between the number
156 * of fractional feedback decimal point and the fractional FB Divider precision
157 * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
159 feedback_divider
+= 5ULL *
160 calc_pll_cs
->fract_fb_divider_precision_factor
;
162 div_u64(feedback_divider
,
163 calc_pll_cs
->fract_fb_divider_precision_factor
* 10);
164 feedback_divider
*= (uint64_t)
165 (calc_pll_cs
->fract_fb_divider_precision_factor
);
167 *feedback_divider_param
=
170 calc_pll_cs
->fract_fb_divider_factor
,
171 fract_feedback_divider_param
);
173 if (*feedback_divider_param
!= 0)
179 * calc_fb_divider_checking_tolerance - Calculates Feedback and
180 * Fractional Feedback divider values
181 * for passed Reference and Post divider,
182 * checking for tolerance.
183 * @calc_pll_cs: Pointer to clock source information
184 * @pll_settings: Pointer to PLL settings
185 * @ref_divider: Reference divider (already known)
186 * @post_divider: Post Divider (already known)
187 * @tolerance: Tolerance for Calculated Pixel Clock to be within
190 * It fills the PLLSettings structure with PLL Dividers values
191 * if calculated values are within required tolerance
192 * It returns - true if error is within tolerance
193 * - false if error is not within tolerance
195 static bool calc_fb_divider_checking_tolerance(
196 struct calc_pll_clock_source
*calc_pll_cs
,
197 struct pll_settings
*pll_settings
,
198 uint32_t ref_divider
,
199 uint32_t post_divider
,
202 uint32_t feedback_divider
;
203 uint32_t fract_feedback_divider
;
204 uint32_t actual_calculated_clock_100hz
;
206 uint64_t actual_calc_clk_100hz
;
208 calculate_fb_and_fractional_fb_divider(
210 pll_settings
->adjusted_pix_clk_100hz
,
214 &fract_feedback_divider
);
216 /*Actual calculated value*/
217 actual_calc_clk_100hz
= (uint64_t)feedback_divider
*
218 calc_pll_cs
->fract_fb_divider_factor
+
219 fract_feedback_divider
;
220 actual_calc_clk_100hz
*= calc_pll_cs
->ref_freq_khz
* 10;
221 actual_calc_clk_100hz
=
222 div_u64(actual_calc_clk_100hz
,
223 ref_divider
* post_divider
*
224 calc_pll_cs
->fract_fb_divider_factor
);
226 actual_calculated_clock_100hz
= (uint32_t)(actual_calc_clk_100hz
);
228 abs_err
= (actual_calculated_clock_100hz
>
229 pll_settings
->adjusted_pix_clk_100hz
)
230 ? actual_calculated_clock_100hz
-
231 pll_settings
->adjusted_pix_clk_100hz
232 : pll_settings
->adjusted_pix_clk_100hz
-
233 actual_calculated_clock_100hz
;
235 if (abs_err
<= tolerance
) {
236 /*found good values*/
237 pll_settings
->reference_freq
= calc_pll_cs
->ref_freq_khz
;
238 pll_settings
->reference_divider
= ref_divider
;
239 pll_settings
->feedback_divider
= feedback_divider
;
240 pll_settings
->fract_feedback_divider
= fract_feedback_divider
;
241 pll_settings
->pix_clk_post_divider
= post_divider
;
242 pll_settings
->calculated_pix_clk_100hz
=
243 actual_calculated_clock_100hz
;
244 pll_settings
->vco_freq
=
245 div_u64((u64
)actual_calculated_clock_100hz
* post_divider
, 10);
251 static bool calc_pll_dividers_in_range(
252 struct calc_pll_clock_source
*calc_pll_cs
,
253 struct pll_settings
*pll_settings
,
254 uint32_t min_ref_divider
,
255 uint32_t max_ref_divider
,
256 uint32_t min_post_divider
,
257 uint32_t max_post_divider
,
258 uint32_t err_tolerance
)
260 uint32_t ref_divider
;
261 uint32_t post_divider
;
264 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
265 * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
266 tolerance
= (pll_settings
->adjusted_pix_clk_100hz
* err_tolerance
) /
268 if (tolerance
< CALC_PLL_CLK_SRC_ERR_TOLERANCE
)
269 tolerance
= CALC_PLL_CLK_SRC_ERR_TOLERANCE
;
272 post_divider
= max_post_divider
;
273 post_divider
>= min_post_divider
;
276 ref_divider
= min_ref_divider
;
277 ref_divider
<= max_ref_divider
;
279 if (calc_fb_divider_checking_tolerance(
293 static uint32_t calculate_pixel_clock_pll_dividers(
294 struct calc_pll_clock_source
*calc_pll_cs
,
295 struct pll_settings
*pll_settings
)
297 uint32_t err_tolerance
;
298 uint32_t min_post_divider
;
299 uint32_t max_post_divider
;
300 uint32_t min_ref_divider
;
301 uint32_t max_ref_divider
;
303 if (pll_settings
->adjusted_pix_clk_100hz
== 0) {
305 "%s Bad requested pixel clock", __func__
);
306 return MAX_PLL_CALC_ERROR
;
309 /* 1) Find Post divider ranges */
310 if (pll_settings
->pix_clk_post_divider
) {
311 min_post_divider
= pll_settings
->pix_clk_post_divider
;
312 max_post_divider
= pll_settings
->pix_clk_post_divider
;
314 min_post_divider
= calc_pll_cs
->min_pix_clock_pll_post_divider
;
315 if (min_post_divider
* pll_settings
->adjusted_pix_clk_100hz
<
316 calc_pll_cs
->min_vco_khz
* 10) {
317 min_post_divider
= calc_pll_cs
->min_vco_khz
* 10 /
318 pll_settings
->adjusted_pix_clk_100hz
;
319 if ((min_post_divider
*
320 pll_settings
->adjusted_pix_clk_100hz
) <
321 calc_pll_cs
->min_vco_khz
* 10)
325 max_post_divider
= calc_pll_cs
->max_pix_clock_pll_post_divider
;
326 if (max_post_divider
* pll_settings
->adjusted_pix_clk_100hz
327 > calc_pll_cs
->max_vco_khz
* 10)
328 max_post_divider
= calc_pll_cs
->max_vco_khz
* 10 /
329 pll_settings
->adjusted_pix_clk_100hz
;
332 /* 2) Find Reference divider ranges
333 * When SS is enabled, or for Display Port even without SS,
334 * pll_settings->referenceDivider is not zero.
335 * So calculate PPLL FB and fractional FB divider
336 * using the passed reference divider*/
338 if (pll_settings
->reference_divider
) {
339 min_ref_divider
= pll_settings
->reference_divider
;
340 max_ref_divider
= pll_settings
->reference_divider
;
342 min_ref_divider
= ((calc_pll_cs
->ref_freq_khz
343 / calc_pll_cs
->max_pll_input_freq_khz
)
344 > calc_pll_cs
->min_pll_ref_divider
)
345 ? calc_pll_cs
->ref_freq_khz
346 / calc_pll_cs
->max_pll_input_freq_khz
347 : calc_pll_cs
->min_pll_ref_divider
;
349 max_ref_divider
= ((calc_pll_cs
->ref_freq_khz
350 / calc_pll_cs
->min_pll_input_freq_khz
)
351 < calc_pll_cs
->max_pll_ref_divider
)
352 ? calc_pll_cs
->ref_freq_khz
/
353 calc_pll_cs
->min_pll_input_freq_khz
354 : calc_pll_cs
->max_pll_ref_divider
;
357 /* If some parameters are invalid we could have scenario when "min">"max"
358 * which produced endless loop later.
359 * We should investigate why we get the wrong parameters.
360 * But to follow the similar logic when "adjustedPixelClock" is set to be 0
361 * it is better to return here than cause system hang/watchdog timeout later.
362 * ## SVS Wed 15 Jul 2009 */
364 if (min_post_divider
> max_post_divider
) {
366 "%s Post divider range is invalid", __func__
);
367 return MAX_PLL_CALC_ERROR
;
370 if (min_ref_divider
> max_ref_divider
) {
372 "%s Reference divider range is invalid", __func__
);
373 return MAX_PLL_CALC_ERROR
;
376 /* 3) Try to find PLL dividers given ranges
377 * starting with minimal error tolerance.
378 * Increase error tolerance until PLL dividers found*/
379 err_tolerance
= MAX_PLL_CALC_ERROR
;
381 while (!calc_pll_dividers_in_range(
389 err_tolerance
+= (err_tolerance
> 10)
390 ? (err_tolerance
/ 10)
393 return err_tolerance
;
396 static bool pll_adjust_pix_clk(
397 struct dce110_clk_src
*clk_src
,
398 struct pixel_clk_params
*pix_clk_params
,
399 struct pll_settings
*pll_settings
)
401 uint32_t actual_pix_clk_100hz
= 0;
402 uint32_t requested_clk_100hz
= 0;
403 struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params
= {
405 enum bp_result bp_result
;
406 switch (pix_clk_params
->signal_type
) {
407 case SIGNAL_TYPE_HDMI_TYPE_A
: {
408 requested_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
409 if (pix_clk_params
->pixel_encoding
!= PIXEL_ENCODING_YCBCR422
) {
410 switch (pix_clk_params
->color_depth
) {
411 case COLOR_DEPTH_101010
:
412 requested_clk_100hz
= (requested_clk_100hz
* 5) >> 2;
414 case COLOR_DEPTH_121212
:
415 requested_clk_100hz
= (requested_clk_100hz
* 6) >> 2;
417 case COLOR_DEPTH_161616
:
418 requested_clk_100hz
= requested_clk_100hz
* 2;
424 actual_pix_clk_100hz
= requested_clk_100hz
;
428 case SIGNAL_TYPE_DISPLAY_PORT
:
429 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
430 case SIGNAL_TYPE_EDP
:
431 requested_clk_100hz
= pix_clk_params
->requested_sym_clk
* 10;
432 actual_pix_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
436 requested_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
437 actual_pix_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
441 bp_adjust_pixel_clock_params
.pixel_clock
= requested_clk_100hz
/ 10;
442 bp_adjust_pixel_clock_params
.
443 encoder_object_id
= pix_clk_params
->encoder_object_id
;
444 bp_adjust_pixel_clock_params
.signal_type
= pix_clk_params
->signal_type
;
445 bp_adjust_pixel_clock_params
.
446 ss_enable
= pix_clk_params
->flags
.ENABLE_SS
;
447 bp_result
= clk_src
->bios
->funcs
->adjust_pixel_clock(
448 clk_src
->bios
, &bp_adjust_pixel_clock_params
);
449 if (bp_result
== BP_RESULT_OK
) {
450 pll_settings
->actual_pix_clk_100hz
= actual_pix_clk_100hz
;
451 pll_settings
->adjusted_pix_clk_100hz
=
452 bp_adjust_pixel_clock_params
.adjusted_pixel_clock
* 10;
453 pll_settings
->reference_divider
=
454 bp_adjust_pixel_clock_params
.reference_divider
;
455 pll_settings
->pix_clk_post_divider
=
456 bp_adjust_pixel_clock_params
.pixel_clock_post_divider
;
465 * Calculate PLL Dividers for given Clock Value.
466 * First will call VBIOS Adjust Exec table to check if requested Pixel clock
467 * will be Adjusted based on usage.
468 * Then it will calculate PLL Dividers for this Adjusted clock using preferred
469 * method (Maximum VCO frequency).
472 * Calculation error in units of 0.01%
475 static uint32_t dce110_get_pix_clk_dividers_helper (
476 struct dce110_clk_src
*clk_src
,
477 struct pll_settings
*pll_settings
,
478 struct pixel_clk_params
*pix_clk_params
)
481 uint32_t pll_calc_error
= MAX_PLL_CALC_ERROR
;
483 /* Check if reference clock is external (not pcie/xtalin)
485 * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB
486 * 04 - HSYNCA, 05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
487 REG_GET(PLL_CNTL
, PLL_REF_DIV_SRC
, &field
);
488 pll_settings
->use_external_clk
= (field
> 1);
490 /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
491 * (we do not care any more from SI for some older DP Sink which
492 * does not report SS support, no known issues) */
493 if ((pix_clk_params
->flags
.ENABLE_SS
) ||
494 (dc_is_dp_signal(pix_clk_params
->signal_type
))) {
496 const struct spread_spectrum_data
*ss_data
= get_ss_data_entry(
498 pix_clk_params
->signal_type
,
499 pll_settings
->adjusted_pix_clk_100hz
/ 10);
502 pll_settings
->ss_percentage
= ss_data
->percentage
;
505 /* Check VBIOS AdjustPixelClock Exec table */
506 if (!pll_adjust_pix_clk(clk_src
, pix_clk_params
, pll_settings
)) {
507 /* Should never happen, ASSERT and fill up values to be able
510 "%s: Failed to adjust pixel clock!!", __func__
);
511 pll_settings
->actual_pix_clk_100hz
=
512 pix_clk_params
->requested_pix_clk_100hz
;
513 pll_settings
->adjusted_pix_clk_100hz
=
514 pix_clk_params
->requested_pix_clk_100hz
;
516 if (dc_is_dp_signal(pix_clk_params
->signal_type
))
517 pll_settings
->adjusted_pix_clk_100hz
= 1000000;
520 /* Calculate Dividers */
521 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
)
522 /*Calculate Dividers by HDMI object, no SS case or SS case */
524 calculate_pixel_clock_pll_dividers(
525 &clk_src
->calc_pll_hdmi
,
528 /*Calculate Dividers by default object, no SS case or SS case */
530 calculate_pixel_clock_pll_dividers(
534 return pll_calc_error
;
537 static void dce112_get_pix_clk_dividers_helper (
538 struct dce110_clk_src
*clk_src
,
539 struct pll_settings
*pll_settings
,
540 struct pixel_clk_params
*pix_clk_params
)
542 uint32_t actual_pixel_clock_100hz
;
544 actual_pixel_clock_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
545 /* Calculate Dividers */
546 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
547 switch (pix_clk_params
->color_depth
) {
548 case COLOR_DEPTH_101010
:
549 actual_pixel_clock_100hz
= (actual_pixel_clock_100hz
* 5) >> 2;
550 actual_pixel_clock_100hz
-= actual_pixel_clock_100hz
% 10;
552 case COLOR_DEPTH_121212
:
553 actual_pixel_clock_100hz
= (actual_pixel_clock_100hz
* 6) >> 2;
554 actual_pixel_clock_100hz
-= actual_pixel_clock_100hz
% 10;
556 case COLOR_DEPTH_161616
:
557 actual_pixel_clock_100hz
= actual_pixel_clock_100hz
* 2;
563 pll_settings
->actual_pix_clk_100hz
= actual_pixel_clock_100hz
;
564 pll_settings
->adjusted_pix_clk_100hz
= actual_pixel_clock_100hz
;
565 pll_settings
->calculated_pix_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
568 static uint32_t dce110_get_pix_clk_dividers(
569 struct clock_source
*cs
,
570 struct pixel_clk_params
*pix_clk_params
,
571 struct pll_settings
*pll_settings
)
573 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
574 uint32_t pll_calc_error
= MAX_PLL_CALC_ERROR
;
577 if (pix_clk_params
== NULL
|| pll_settings
== NULL
578 || pix_clk_params
->requested_pix_clk_100hz
== 0) {
580 "%s: Invalid parameters!!\n", __func__
);
581 return pll_calc_error
;
584 memset(pll_settings
, 0, sizeof(*pll_settings
));
586 if (cs
->id
== CLOCK_SOURCE_ID_DP_DTO
||
587 cs
->id
== CLOCK_SOURCE_ID_EXTERNAL
) {
588 pll_settings
->adjusted_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
589 pll_settings
->calculated_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
590 pll_settings
->actual_pix_clk_100hz
=
591 pix_clk_params
->requested_pix_clk_100hz
;
595 pll_calc_error
= dce110_get_pix_clk_dividers_helper(clk_src
,
596 pll_settings
, pix_clk_params
);
598 return pll_calc_error
;
601 static uint32_t dce112_get_pix_clk_dividers(
602 struct clock_source
*cs
,
603 struct pixel_clk_params
*pix_clk_params
,
604 struct pll_settings
*pll_settings
)
606 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
609 if (pix_clk_params
== NULL
|| pll_settings
== NULL
610 || pix_clk_params
->requested_pix_clk_100hz
== 0) {
612 "%s: Invalid parameters!!\n", __func__
);
616 memset(pll_settings
, 0, sizeof(*pll_settings
));
618 if (cs
->id
== CLOCK_SOURCE_ID_DP_DTO
||
619 cs
->id
== CLOCK_SOURCE_ID_EXTERNAL
) {
620 pll_settings
->adjusted_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
621 pll_settings
->calculated_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
622 pll_settings
->actual_pix_clk_100hz
=
623 pix_clk_params
->requested_pix_clk_100hz
;
627 dce112_get_pix_clk_dividers_helper(clk_src
,
628 pll_settings
, pix_clk_params
);
633 static bool disable_spread_spectrum(struct dce110_clk_src
*clk_src
)
635 enum bp_result result
;
636 struct bp_spread_spectrum_parameters bp_ss_params
= {0};
638 bp_ss_params
.pll_id
= clk_src
->base
.id
;
640 /*Call ASICControl to process ATOMBIOS Exec table*/
641 result
= clk_src
->bios
->funcs
->enable_spread_spectrum_on_ppll(
646 return result
== BP_RESULT_OK
;
649 static bool calculate_ss(
650 const struct pll_settings
*pll_settings
,
651 const struct spread_spectrum_data
*ss_data
,
652 struct delta_sigma_data
*ds_data
)
654 struct fixed31_32 fb_div
;
655 struct fixed31_32 ss_amount
;
656 struct fixed31_32 ss_nslip_amount
;
657 struct fixed31_32 ss_ds_frac_amount
;
658 struct fixed31_32 ss_step_size
;
659 struct fixed31_32 modulation_time
;
665 if (ss_data
->percentage
== 0)
667 if (pll_settings
== NULL
)
670 memset(ds_data
, 0, sizeof(struct delta_sigma_data
));
672 /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
673 /* 6 decimal point support in fractional feedback divider */
674 fb_div
= dc_fixpt_from_fraction(
675 pll_settings
->fract_feedback_divider
, 1000000);
676 fb_div
= dc_fixpt_add_int(fb_div
, pll_settings
->feedback_divider
);
678 ds_data
->ds_frac_amount
= 0;
679 /*spreadSpectrumPercentage is in the unit of .01%,
680 * so have to divided by 100 * 100*/
681 ss_amount
= dc_fixpt_mul(
682 fb_div
, dc_fixpt_from_fraction(ss_data
->percentage
,
683 100 * ss_data
->percentage_divider
));
684 ds_data
->feedback_amount
= dc_fixpt_floor(ss_amount
);
686 ss_nslip_amount
= dc_fixpt_sub(ss_amount
,
687 dc_fixpt_from_int(ds_data
->feedback_amount
));
688 ss_nslip_amount
= dc_fixpt_mul_int(ss_nslip_amount
, 10);
689 ds_data
->nfrac_amount
= dc_fixpt_floor(ss_nslip_amount
);
691 ss_ds_frac_amount
= dc_fixpt_sub(ss_nslip_amount
,
692 dc_fixpt_from_int(ds_data
->nfrac_amount
));
693 ss_ds_frac_amount
= dc_fixpt_mul_int(ss_ds_frac_amount
, 65536);
694 ds_data
->ds_frac_amount
= dc_fixpt_floor(ss_ds_frac_amount
);
696 /* compute SS_STEP_SIZE_DSFRAC */
697 modulation_time
= dc_fixpt_from_fraction(
698 pll_settings
->reference_freq
* 1000,
699 pll_settings
->reference_divider
* ss_data
->modulation_freq_hz
);
701 if (ss_data
->flags
.CENTER_SPREAD
)
702 modulation_time
= dc_fixpt_div_int(modulation_time
, 4);
704 modulation_time
= dc_fixpt_div_int(modulation_time
, 2);
706 ss_step_size
= dc_fixpt_div(ss_amount
, modulation_time
);
707 /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
708 ss_step_size
= dc_fixpt_mul_int(ss_step_size
, 65536 * 10);
709 ds_data
->ds_frac_size
= dc_fixpt_floor(ss_step_size
);
714 static bool enable_spread_spectrum(
715 struct dce110_clk_src
*clk_src
,
716 enum signal_type signal
, struct pll_settings
*pll_settings
)
718 struct bp_spread_spectrum_parameters bp_params
= {0};
719 struct delta_sigma_data d_s_data
;
720 const struct spread_spectrum_data
*ss_data
= NULL
;
722 ss_data
= get_ss_data_entry(
725 pll_settings
->calculated_pix_clk_100hz
/ 10);
727 /* Pixel clock PLL has been programmed to generate desired pixel clock,
728 * now enable SS on pixel clock */
729 /* TODO is it OK to return true not doing anything ??*/
730 if (ss_data
!= NULL
&& pll_settings
->ss_percentage
!= 0) {
731 if (calculate_ss(pll_settings
, ss_data
, &d_s_data
)) {
732 bp_params
.ds
.feedback_amount
=
733 d_s_data
.feedback_amount
;
734 bp_params
.ds
.nfrac_amount
=
735 d_s_data
.nfrac_amount
;
736 bp_params
.ds
.ds_frac_size
= d_s_data
.ds_frac_size
;
737 bp_params
.ds_frac_amount
=
738 d_s_data
.ds_frac_amount
;
739 bp_params
.flags
.DS_TYPE
= 1;
740 bp_params
.pll_id
= clk_src
->base
.id
;
741 bp_params
.percentage
= ss_data
->percentage
;
742 if (ss_data
->flags
.CENTER_SPREAD
)
743 bp_params
.flags
.CENTER_SPREAD
= 1;
744 if (ss_data
->flags
.EXTERNAL_SS
)
745 bp_params
.flags
.EXTERNAL_SS
= 1;
748 clk_src
->bios
->funcs
->
749 enable_spread_spectrum_on_ppll(
760 static void dce110_program_pixel_clk_resync(
761 struct dce110_clk_src
*clk_src
,
762 enum signal_type signal_type
,
763 enum dc_color_depth colordepth
)
765 REG_UPDATE(RESYNC_CNTL
,
766 DCCG_DEEP_COLOR_CNTL1
, 0);
768 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
769 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
770 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
771 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
773 if (signal_type
!= SIGNAL_TYPE_HDMI_TYPE_A
)
776 switch (colordepth
) {
777 case COLOR_DEPTH_888
:
778 REG_UPDATE(RESYNC_CNTL
,
779 DCCG_DEEP_COLOR_CNTL1
, 0);
781 case COLOR_DEPTH_101010
:
782 REG_UPDATE(RESYNC_CNTL
,
783 DCCG_DEEP_COLOR_CNTL1
, 1);
785 case COLOR_DEPTH_121212
:
786 REG_UPDATE(RESYNC_CNTL
,
787 DCCG_DEEP_COLOR_CNTL1
, 2);
789 case COLOR_DEPTH_161616
:
790 REG_UPDATE(RESYNC_CNTL
,
791 DCCG_DEEP_COLOR_CNTL1
, 3);
798 static void dce112_program_pixel_clk_resync(
799 struct dce110_clk_src
*clk_src
,
800 enum signal_type signal_type
,
801 enum dc_color_depth colordepth
,
802 bool enable_ycbcr420
)
804 uint32_t deep_color_cntl
= 0;
805 uint32_t double_rate_enable
= 0;
808 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
809 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
810 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
811 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
813 if (signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
814 double_rate_enable
= enable_ycbcr420
? 1 : 0;
816 switch (colordepth
) {
817 case COLOR_DEPTH_888
:
820 case COLOR_DEPTH_101010
:
823 case COLOR_DEPTH_121212
:
826 case COLOR_DEPTH_161616
:
834 if (clk_src
->cs_mask
->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE
)
835 REG_UPDATE_2(PIXCLK_RESYNC_CNTL
,
836 PHYPLLA_DCCG_DEEP_COLOR_CNTL
, deep_color_cntl
,
837 PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE
, double_rate_enable
);
839 REG_UPDATE(PIXCLK_RESYNC_CNTL
,
840 PHYPLLA_DCCG_DEEP_COLOR_CNTL
, deep_color_cntl
);
844 static bool dce110_program_pix_clk(
845 struct clock_source
*clock_source
,
846 struct pixel_clk_params
*pix_clk_params
,
847 enum dp_link_encoding encoding
,
848 struct pll_settings
*pll_settings
)
850 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
851 struct bp_pixel_clock_parameters bp_pc_params
= {0};
854 * ATOMBIOS will enable by default SS on PLL for DP,
855 * do not disable it here
857 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
&&
858 !dc_is_dp_signal(pix_clk_params
->signal_type
) &&
859 clock_source
->ctx
->dce_version
<= DCE_VERSION_11_0
)
860 disable_spread_spectrum(clk_src
);
862 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
863 bp_pc_params
.controller_id
= pix_clk_params
->controller_id
;
864 bp_pc_params
.pll_id
= clock_source
->id
;
865 bp_pc_params
.target_pixel_clock_100hz
= pll_settings
->actual_pix_clk_100hz
;
866 bp_pc_params
.encoder_object_id
= pix_clk_params
->encoder_object_id
;
867 bp_pc_params
.signal_type
= pix_clk_params
->signal_type
;
869 bp_pc_params
.reference_divider
= pll_settings
->reference_divider
;
870 bp_pc_params
.feedback_divider
= pll_settings
->feedback_divider
;
871 bp_pc_params
.fractional_feedback_divider
=
872 pll_settings
->fract_feedback_divider
;
873 bp_pc_params
.pixel_clock_post_divider
=
874 pll_settings
->pix_clk_post_divider
;
875 bp_pc_params
.flags
.SET_EXTERNAL_REF_DIV_SRC
=
876 pll_settings
->use_external_clk
;
878 switch (pix_clk_params
->color_depth
) {
879 case COLOR_DEPTH_101010
:
880 bp_pc_params
.color_depth
= TRANSMITTER_COLOR_DEPTH_30
;
882 case COLOR_DEPTH_121212
:
883 bp_pc_params
.color_depth
= TRANSMITTER_COLOR_DEPTH_36
;
885 case COLOR_DEPTH_161616
:
886 bp_pc_params
.color_depth
= TRANSMITTER_COLOR_DEPTH_48
;
892 if (clk_src
->bios
->funcs
->set_pixel_clock(
893 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
896 * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
897 * based on HW display PLL team, SS control settings should be programmed
898 * during PLL Reset, but they do not have effect
899 * until SS_EN is asserted.*/
900 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
901 && !dc_is_dp_signal(pix_clk_params
->signal_type
)) {
903 if (pix_clk_params
->flags
.ENABLE_SS
)
904 if (!enable_spread_spectrum(clk_src
,
905 pix_clk_params
->signal_type
,
909 /* Resync deep color DTO */
910 dce110_program_pixel_clk_resync(clk_src
,
911 pix_clk_params
->signal_type
,
912 pix_clk_params
->color_depth
);
918 static bool dce112_program_pix_clk(
919 struct clock_source
*clock_source
,
920 struct pixel_clk_params
*pix_clk_params
,
921 enum dp_link_encoding encoding
,
922 struct pll_settings
*pll_settings
)
924 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
925 struct bp_pixel_clock_parameters bp_pc_params
= {0};
928 * ATOMBIOS will enable by default SS on PLL for DP,
929 * do not disable it here
931 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
&&
932 !dc_is_dp_signal(pix_clk_params
->signal_type
) &&
933 clock_source
->ctx
->dce_version
<= DCE_VERSION_11_0
)
934 disable_spread_spectrum(clk_src
);
936 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
937 bp_pc_params
.controller_id
= pix_clk_params
->controller_id
;
938 bp_pc_params
.pll_id
= clock_source
->id
;
939 bp_pc_params
.target_pixel_clock_100hz
= pll_settings
->actual_pix_clk_100hz
;
940 bp_pc_params
.encoder_object_id
= pix_clk_params
->encoder_object_id
;
941 bp_pc_params
.signal_type
= pix_clk_params
->signal_type
;
943 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
) {
944 bp_pc_params
.flags
.SET_GENLOCK_REF_DIV_SRC
=
945 pll_settings
->use_external_clk
;
946 bp_pc_params
.flags
.SET_XTALIN_REF_SRC
=
947 !pll_settings
->use_external_clk
;
948 if (pix_clk_params
->flags
.SUPPORT_YCBCR420
) {
949 bp_pc_params
.flags
.SUPPORT_YUV_420
= 1;
952 if (clk_src
->bios
->funcs
->set_pixel_clock(
953 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
955 /* Resync deep color DTO */
956 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
)
957 dce112_program_pixel_clk_resync(clk_src
,
958 pix_clk_params
->signal_type
,
959 pix_clk_params
->color_depth
,
960 pix_clk_params
->flags
.SUPPORT_YCBCR420
);
965 static bool dcn31_program_pix_clk(
966 struct clock_source
*clock_source
,
967 struct pixel_clk_params
*pix_clk_params
,
968 enum dp_link_encoding encoding
,
969 struct pll_settings
*pll_settings
)
971 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
972 unsigned int inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
973 unsigned int dp_dto_ref_khz
= clock_source
->ctx
->dc
->clk_mgr
->dprefclk_khz
;
974 const struct pixel_rate_range_table_entry
*e
=
975 look_up_in_video_optimized_rate_tlb(pix_clk_params
->requested_pix_clk_100hz
/ 10);
976 struct bp_pixel_clock_parameters bp_pc_params
= {0};
977 enum transmitter_color_depth bp_pc_colour_depth
= TRANSMITTER_COLOR_DEPTH_24
;
979 if (clock_source
->ctx
->dc
->clk_mgr
->dp_dto_source_clock_in_khz
!= 0)
980 dp_dto_ref_khz
= clock_source
->ctx
->dc
->clk_mgr
->dp_dto_source_clock_in_khz
;
981 // For these signal types Driver to program DP_DTO without calling VBIOS Command table
982 if (dc_is_dp_signal(pix_clk_params
->signal_type
) || dc_is_virtual_signal(pix_clk_params
->signal_type
)) {
984 /* Set DTO values: phase = target clock, modulo = reference clock*/
985 REG_WRITE(PHASE
[inst
], e
->target_pixel_rate_khz
* e
->mult_factor
);
986 REG_WRITE(MODULO
[inst
], dp_dto_ref_khz
* e
->div_factor
);
988 /* Set DTO values: phase = target clock, modulo = reference clock*/
989 REG_WRITE(PHASE
[inst
], pll_settings
->actual_pix_clk_100hz
* 100);
990 REG_WRITE(MODULO
[inst
], dp_dto_ref_khz
* 1000);
993 if (clk_src
->cs_mask
->PIPE0_DTO_SRC_SEL
)
994 if (encoding
== DP_128b_132b_ENCODING
)
995 REG_UPDATE_2(PIXEL_RATE_CNTL
[inst
],
997 PIPE0_DTO_SRC_SEL
, 2);
999 REG_UPDATE_2(PIXEL_RATE_CNTL
[inst
],
1001 PIPE0_DTO_SRC_SEL
, 1);
1003 REG_UPDATE(PIXEL_RATE_CNTL
[inst
],
1007 if (clk_src
->cs_mask
->PIPE0_DTO_SRC_SEL
)
1008 REG_UPDATE(PIXEL_RATE_CNTL
[inst
],
1009 PIPE0_DTO_SRC_SEL
, 0);
1011 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
1012 bp_pc_params
.controller_id
= pix_clk_params
->controller_id
;
1013 bp_pc_params
.pll_id
= clock_source
->id
;
1014 bp_pc_params
.target_pixel_clock_100hz
= pll_settings
->actual_pix_clk_100hz
;
1015 bp_pc_params
.encoder_object_id
= pix_clk_params
->encoder_object_id
;
1016 bp_pc_params
.signal_type
= pix_clk_params
->signal_type
;
1018 // Make sure we send the correct color depth to DMUB for HDMI
1019 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
1020 switch (pix_clk_params
->color_depth
) {
1021 case COLOR_DEPTH_888
:
1022 bp_pc_colour_depth
= TRANSMITTER_COLOR_DEPTH_24
;
1024 case COLOR_DEPTH_101010
:
1025 bp_pc_colour_depth
= TRANSMITTER_COLOR_DEPTH_30
;
1027 case COLOR_DEPTH_121212
:
1028 bp_pc_colour_depth
= TRANSMITTER_COLOR_DEPTH_36
;
1030 case COLOR_DEPTH_161616
:
1031 bp_pc_colour_depth
= TRANSMITTER_COLOR_DEPTH_48
;
1034 bp_pc_colour_depth
= TRANSMITTER_COLOR_DEPTH_24
;
1037 bp_pc_params
.color_depth
= bp_pc_colour_depth
;
1040 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
) {
1041 bp_pc_params
.flags
.SET_GENLOCK_REF_DIV_SRC
=
1042 pll_settings
->use_external_clk
;
1043 bp_pc_params
.flags
.SET_XTALIN_REF_SRC
=
1044 !pll_settings
->use_external_clk
;
1045 if (pix_clk_params
->flags
.SUPPORT_YCBCR420
) {
1046 bp_pc_params
.flags
.SUPPORT_YUV_420
= 1;
1049 if (clk_src
->bios
->funcs
->set_pixel_clock(
1050 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
1052 /* Resync deep color DTO */
1053 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
)
1054 dce112_program_pixel_clk_resync(clk_src
,
1055 pix_clk_params
->signal_type
,
1056 pix_clk_params
->color_depth
,
1057 pix_clk_params
->flags
.SUPPORT_YCBCR420
);
1063 static bool dce110_clock_source_power_down(
1064 struct clock_source
*clk_src
)
1066 struct dce110_clk_src
*dce110_clk_src
= TO_DCE110_CLK_SRC(clk_src
);
1067 enum bp_result bp_result
;
1068 struct bp_pixel_clock_parameters bp_pixel_clock_params
= {0};
1070 if (clk_src
->dp_clk_src
)
1073 /* If Pixel Clock is 0 it means Power Down Pll*/
1074 bp_pixel_clock_params
.controller_id
= CONTROLLER_ID_UNDEFINED
;
1075 bp_pixel_clock_params
.pll_id
= clk_src
->id
;
1076 bp_pixel_clock_params
.flags
.FORCE_PROGRAMMING_OF_PLL
= 1;
1078 /*Call ASICControl to process ATOMBIOS Exec table*/
1079 bp_result
= dce110_clk_src
->bios
->funcs
->set_pixel_clock(
1080 dce110_clk_src
->bios
,
1081 &bp_pixel_clock_params
);
1083 return bp_result
== BP_RESULT_OK
;
1086 static bool get_pixel_clk_frequency_100hz(
1087 const struct clock_source
*clock_source
,
1089 unsigned int *pixel_clk_khz
)
1091 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
1092 unsigned int clock_hz
= 0;
1093 unsigned int modulo_hz
= 0;
1094 unsigned int dp_dto_ref_khz
= clock_source
->ctx
->dc
->clk_mgr
->dprefclk_khz
;
1096 if (clock_source
->ctx
->dc
->clk_mgr
->dp_dto_source_clock_in_khz
!= 0)
1097 dp_dto_ref_khz
= clock_source
->ctx
->dc
->clk_mgr
->dp_dto_source_clock_in_khz
;
1099 if (clock_source
->id
== CLOCK_SOURCE_ID_DP_DTO
) {
1100 clock_hz
= REG_READ(PHASE
[inst
]);
1102 if (clock_source
->ctx
->dc
->hwss
.enable_vblanks_synchronization
&&
1103 clock_source
->ctx
->dc
->config
.vblank_alignment_max_frame_time_diff
> 0) {
1104 /* NOTE: In case VBLANK syncronization is enabled, MODULO may
1105 * not be programmed equal to DPREFCLK
1107 modulo_hz
= REG_READ(MODULO
[inst
]);
1109 *pixel_clk_khz
= div_u64((uint64_t)clock_hz
*
1115 /* NOTE: There is agreement with VBIOS here that MODULO is
1116 * programmed equal to DPREFCLK, in which case PHASE will be
1117 * equivalent to pixel clock.
1119 *pixel_clk_khz
= clock_hz
/ 100;
1127 /* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
1128 const struct pixel_rate_range_table_entry video_optimized_pixel_rates
[] = {
1130 {25170, 25180, 25200, 1000, 1001}, //25.2MHz -> 25.17
1131 {59340, 59350, 59400, 1000, 1001}, //59.4Mhz -> 59.340
1132 {74170, 74180, 74250, 1000, 1001}, //74.25Mhz -> 74.1758
1133 {89910, 90000, 90000, 1000, 1001}, //90Mhz -> 89.91
1134 {125870, 125880, 126000, 1000, 1001}, //126Mhz -> 125.87
1135 {148350, 148360, 148500, 1000, 1001}, //148.5Mhz -> 148.3516
1136 {167830, 167840, 168000, 1000, 1001}, //168Mhz -> 167.83
1137 {222520, 222530, 222750, 1000, 1001}, //222.75Mhz -> 222.527
1138 {257140, 257150, 257400, 1000, 1001}, //257.4Mhz -> 257.1429
1139 {296700, 296710, 297000, 1000, 1001}, //297Mhz -> 296.7033
1140 {342850, 342860, 343200, 1000, 1001}, //343.2Mhz -> 342.857
1141 {395600, 395610, 396000, 1000, 1001}, //396Mhz -> 395.6
1142 {409090, 409100, 409500, 1000, 1001}, //409.5Mhz -> 409.091
1143 {445050, 445060, 445500, 1000, 1001}, //445.5Mhz -> 445.055
1144 {467530, 467540, 468000, 1000, 1001}, //468Mhz -> 467.5325
1145 {519230, 519240, 519750, 1000, 1001}, //519.75Mhz -> 519.231
1146 {525970, 525980, 526500, 1000, 1001}, //526.5Mhz -> 525.974
1147 {545450, 545460, 546000, 1000, 1001}, //546Mhz -> 545.455
1148 {593400, 593410, 594000, 1000, 1001}, //594Mhz -> 593.4066
1149 {623370, 623380, 624000, 1000, 1001}, //624Mhz -> 623.377
1150 {692300, 692310, 693000, 1000, 1001}, //693Mhz -> 692.308
1151 {701290, 701300, 702000, 1000, 1001}, //702Mhz -> 701.2987
1152 {791200, 791210, 792000, 1000, 1001}, //792Mhz -> 791.209
1153 {890100, 890110, 891000, 1000, 1001}, //891Mhz -> 890.1099
1154 {1186810, 1186820, 1188000, 1000, 1001},//1188Mhz -> 1186.8131
1157 {27020, 27030, 27000, 1001, 1000}, //27Mhz
1158 {54050, 54060, 54000, 1001, 1000}, //54Mhz
1159 {108100, 108110, 108000, 1001, 1000},//108Mhz
1162 const struct pixel_rate_range_table_entry
*look_up_in_video_optimized_rate_tlb(
1163 unsigned int pixel_rate_khz
)
1167 for (i
= 0; i
< NUM_ELEMENTS(video_optimized_pixel_rates
); i
++) {
1168 const struct pixel_rate_range_table_entry
*e
= &video_optimized_pixel_rates
[i
];
1170 if (e
->range_min_khz
<= pixel_rate_khz
&& pixel_rate_khz
<= e
->range_max_khz
) {
1178 static bool dcn20_program_pix_clk(
1179 struct clock_source
*clock_source
,
1180 struct pixel_clk_params
*pix_clk_params
,
1181 enum dp_link_encoding encoding
,
1182 struct pll_settings
*pll_settings
)
1184 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
1185 unsigned int inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
1187 dce112_program_pix_clk(clock_source
, pix_clk_params
, encoding
, pll_settings
);
1189 if (clock_source
->ctx
->dc
->hwss
.enable_vblanks_synchronization
&&
1190 clock_source
->ctx
->dc
->config
.vblank_alignment_max_frame_time_diff
> 0) {
1191 /* NOTE: In case VBLANK syncronization is enabled,
1192 * we need to set modulo to default DPREFCLK first
1193 * dce112_program_pix_clk does not set default DPREFCLK
1195 REG_WRITE(MODULO
[inst
],
1196 clock_source
->ctx
->dc
->clk_mgr
->dprefclk_khz
*1000);
1201 static bool dcn20_override_dp_pix_clk(
1202 struct clock_source
*clock_source
,
1204 unsigned int pixel_clk
,
1205 unsigned int ref_clk
)
1207 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
1209 REG_UPDATE(PIXEL_RATE_CNTL
[inst
], DP_DTO0_ENABLE
, 0);
1210 REG_WRITE(PHASE
[inst
], pixel_clk
);
1211 REG_WRITE(MODULO
[inst
], ref_clk
);
1212 REG_UPDATE(PIXEL_RATE_CNTL
[inst
], DP_DTO0_ENABLE
, 1);
1216 static const struct clock_source_funcs dcn20_clk_src_funcs
= {
1217 .cs_power_down
= dce110_clock_source_power_down
,
1218 .program_pix_clk
= dcn20_program_pix_clk
,
1219 .get_pix_clk_dividers
= dce112_get_pix_clk_dividers
,
1220 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
,
1221 .override_dp_pix_clk
= dcn20_override_dp_pix_clk
1224 static bool dcn3_program_pix_clk(
1225 struct clock_source
*clock_source
,
1226 struct pixel_clk_params
*pix_clk_params
,
1227 enum dp_link_encoding encoding
,
1228 struct pll_settings
*pll_settings
)
1230 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
1231 unsigned int inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
1232 unsigned int dp_dto_ref_khz
= clock_source
->ctx
->dc
->clk_mgr
->dprefclk_khz
;
1233 const struct pixel_rate_range_table_entry
*e
=
1234 look_up_in_video_optimized_rate_tlb(pix_clk_params
->requested_pix_clk_100hz
/ 10);
1236 // For these signal types Driver to program DP_DTO without calling VBIOS Command table
1237 if (dc_is_dp_signal(pix_clk_params
->signal_type
)) {
1239 /* Set DTO values: phase = target clock, modulo = reference clock*/
1240 REG_WRITE(PHASE
[inst
], e
->target_pixel_rate_khz
* e
->mult_factor
);
1241 REG_WRITE(MODULO
[inst
], dp_dto_ref_khz
* e
->div_factor
);
1243 /* Set DTO values: phase = target clock, modulo = reference clock*/
1244 REG_WRITE(PHASE
[inst
], pll_settings
->actual_pix_clk_100hz
* 100);
1245 REG_WRITE(MODULO
[inst
], dp_dto_ref_khz
* 1000);
1248 if (clk_src
->cs_mask
->PIPE0_DTO_SRC_SEL
)
1249 REG_UPDATE_2(PIXEL_RATE_CNTL
[inst
],
1251 PIPE0_DTO_SRC_SEL
, 1);
1253 REG_UPDATE(PIXEL_RATE_CNTL
[inst
],
1256 // For other signal types(HDMI_TYPE_A, DVI) Driver still to call VBIOS Command table
1257 dce112_program_pix_clk(clock_source
, pix_clk_params
, encoding
, pll_settings
);
1262 static uint32_t dcn3_get_pix_clk_dividers(
1263 struct clock_source
*cs
,
1264 struct pixel_clk_params
*pix_clk_params
,
1265 struct pll_settings
*pll_settings
)
1267 unsigned long long actual_pix_clk_100Hz
= pix_clk_params
? pix_clk_params
->requested_pix_clk_100hz
: 0;
1268 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
1272 if (pix_clk_params
== NULL
|| pll_settings
== NULL
1273 || pix_clk_params
->requested_pix_clk_100hz
== 0) {
1275 "%s: Invalid parameters!!\n", __func__
);
1279 memset(pll_settings
, 0, sizeof(*pll_settings
));
1280 /* Adjust for HDMI Type A deep color */
1281 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
1282 switch (pix_clk_params
->color_depth
) {
1283 case COLOR_DEPTH_101010
:
1284 actual_pix_clk_100Hz
= (actual_pix_clk_100Hz
* 5) >> 2;
1286 case COLOR_DEPTH_121212
:
1287 actual_pix_clk_100Hz
= (actual_pix_clk_100Hz
* 6) >> 2;
1289 case COLOR_DEPTH_161616
:
1290 actual_pix_clk_100Hz
= actual_pix_clk_100Hz
* 2;
1296 pll_settings
->actual_pix_clk_100hz
= (unsigned int) actual_pix_clk_100Hz
;
1297 pll_settings
->adjusted_pix_clk_100hz
= (unsigned int) actual_pix_clk_100Hz
;
1298 pll_settings
->calculated_pix_clk_100hz
= (unsigned int) actual_pix_clk_100Hz
;
1303 static const struct clock_source_funcs dcn3_clk_src_funcs
= {
1304 .cs_power_down
= dce110_clock_source_power_down
,
1305 .program_pix_clk
= dcn3_program_pix_clk
,
1306 .get_pix_clk_dividers
= dcn3_get_pix_clk_dividers
,
1307 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1310 static const struct clock_source_funcs dcn31_clk_src_funcs
= {
1311 .cs_power_down
= dce110_clock_source_power_down
,
1312 .program_pix_clk
= dcn31_program_pix_clk
,
1313 .get_pix_clk_dividers
= dcn3_get_pix_clk_dividers
,
1314 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1317 /*****************************************/
1319 /*****************************************/
1321 static const struct clock_source_funcs dce112_clk_src_funcs
= {
1322 .cs_power_down
= dce110_clock_source_power_down
,
1323 .program_pix_clk
= dce112_program_pix_clk
,
1324 .get_pix_clk_dividers
= dce112_get_pix_clk_dividers
,
1325 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1327 static const struct clock_source_funcs dce110_clk_src_funcs
= {
1328 .cs_power_down
= dce110_clock_source_power_down
,
1329 .program_pix_clk
= dce110_program_pix_clk
,
1330 .get_pix_clk_dividers
= dce110_get_pix_clk_dividers
,
1331 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1335 static void get_ss_info_from_atombios(
1336 struct dce110_clk_src
*clk_src
,
1337 enum as_signal_type as_signal
,
1338 struct spread_spectrum_data
*spread_spectrum_data
[],
1339 uint32_t *ss_entries_num
)
1341 enum bp_result bp_result
= BP_RESULT_FAILURE
;
1342 struct spread_spectrum_info
*ss_info
;
1343 struct spread_spectrum_data
*ss_data
;
1344 struct spread_spectrum_info
*ss_info_cur
;
1345 struct spread_spectrum_data
*ss_data_cur
;
1348 if (ss_entries_num
== NULL
) {
1350 "Invalid entry !!!\n");
1353 if (spread_spectrum_data
== NULL
) {
1355 "Invalid array pointer!!!\n");
1359 spread_spectrum_data
[0] = NULL
;
1360 *ss_entries_num
= 0;
1362 *ss_entries_num
= clk_src
->bios
->funcs
->get_ss_entry_number(
1366 if (*ss_entries_num
== 0)
1369 ss_info
= kcalloc(*ss_entries_num
,
1370 sizeof(struct spread_spectrum_info
),
1372 ss_info_cur
= ss_info
;
1373 if (ss_info
== NULL
)
1376 ss_data
= kcalloc(*ss_entries_num
,
1377 sizeof(struct spread_spectrum_data
),
1379 if (ss_data
== NULL
)
1382 for (i
= 0, ss_info_cur
= ss_info
;
1383 i
< (*ss_entries_num
);
1384 ++i
, ++ss_info_cur
) {
1386 bp_result
= clk_src
->bios
->funcs
->get_spread_spectrum_info(
1392 if (bp_result
!= BP_RESULT_OK
)
1396 for (i
= 0, ss_info_cur
= ss_info
, ss_data_cur
= ss_data
;
1397 i
< (*ss_entries_num
);
1398 ++i
, ++ss_info_cur
, ++ss_data_cur
) {
1400 if (ss_info_cur
->type
.STEP_AND_DELAY_INFO
!= false) {
1402 "Invalid ATOMBIOS SS Table!!!\n");
1406 /* for HDMI check SS percentage,
1407 * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1408 if (as_signal
== AS_SIGNAL_TYPE_HDMI
1409 && ss_info_cur
->spread_spectrum_percentage
> 6){
1410 /* invalid input, do nothing */
1412 "Invalid SS percentage ");
1414 "for HDMI in ATOMBIOS info Table!!!\n");
1417 if (ss_info_cur
->spread_percentage_divider
== 1000) {
1418 /* Keep previous precision from ATOMBIOS for these
1419 * in case new precision set by ATOMBIOS for these
1420 * (otherwise all code in DCE specific classes
1421 * for all previous ASICs would need
1422 * to be updated for SS calculations,
1423 * Audio SS compensation and DP DTO SS compensation
1424 * which assumes fixed SS percentage Divider = 100)*/
1425 ss_info_cur
->spread_spectrum_percentage
/= 10;
1426 ss_info_cur
->spread_percentage_divider
= 100;
1429 ss_data_cur
->freq_range_khz
= ss_info_cur
->target_clock_range
;
1430 ss_data_cur
->percentage
=
1431 ss_info_cur
->spread_spectrum_percentage
;
1432 ss_data_cur
->percentage_divider
=
1433 ss_info_cur
->spread_percentage_divider
;
1434 ss_data_cur
->modulation_freq_hz
=
1435 ss_info_cur
->spread_spectrum_range
;
1437 if (ss_info_cur
->type
.CENTER_MODE
)
1438 ss_data_cur
->flags
.CENTER_SPREAD
= 1;
1440 if (ss_info_cur
->type
.EXTERNAL
)
1441 ss_data_cur
->flags
.EXTERNAL_SS
= 1;
1445 *spread_spectrum_data
= ss_data
;
1451 *ss_entries_num
= 0;
1456 static void ss_info_from_atombios_create(
1457 struct dce110_clk_src
*clk_src
)
1459 get_ss_info_from_atombios(
1461 AS_SIGNAL_TYPE_DISPLAY_PORT
,
1462 &clk_src
->dp_ss_params
,
1463 &clk_src
->dp_ss_params_cnt
);
1464 get_ss_info_from_atombios(
1466 AS_SIGNAL_TYPE_HDMI
,
1467 &clk_src
->hdmi_ss_params
,
1468 &clk_src
->hdmi_ss_params_cnt
);
1469 get_ss_info_from_atombios(
1472 &clk_src
->dvi_ss_params
,
1473 &clk_src
->dvi_ss_params_cnt
);
1474 get_ss_info_from_atombios(
1476 AS_SIGNAL_TYPE_LVDS
,
1477 &clk_src
->lvds_ss_params
,
1478 &clk_src
->lvds_ss_params_cnt
);
1481 static bool calc_pll_max_vco_construct(
1482 struct calc_pll_clock_source
*calc_pll_cs
,
1483 struct calc_pll_clock_source_init_data
*init_data
)
1486 struct dc_firmware_info
*fw_info
;
1487 if (calc_pll_cs
== NULL
||
1488 init_data
== NULL
||
1489 init_data
->bp
== NULL
)
1492 if (!init_data
->bp
->fw_info_valid
)
1495 fw_info
= &init_data
->bp
->fw_info
;
1496 calc_pll_cs
->ctx
= init_data
->ctx
;
1497 calc_pll_cs
->ref_freq_khz
= fw_info
->pll_info
.crystal_frequency
;
1498 calc_pll_cs
->min_vco_khz
=
1499 fw_info
->pll_info
.min_output_pxl_clk_pll_frequency
;
1500 calc_pll_cs
->max_vco_khz
=
1501 fw_info
->pll_info
.max_output_pxl_clk_pll_frequency
;
1503 if (init_data
->max_override_input_pxl_clk_pll_freq_khz
!= 0)
1504 calc_pll_cs
->max_pll_input_freq_khz
=
1505 init_data
->max_override_input_pxl_clk_pll_freq_khz
;
1507 calc_pll_cs
->max_pll_input_freq_khz
=
1508 fw_info
->pll_info
.max_input_pxl_clk_pll_frequency
;
1510 if (init_data
->min_override_input_pxl_clk_pll_freq_khz
!= 0)
1511 calc_pll_cs
->min_pll_input_freq_khz
=
1512 init_data
->min_override_input_pxl_clk_pll_freq_khz
;
1514 calc_pll_cs
->min_pll_input_freq_khz
=
1515 fw_info
->pll_info
.min_input_pxl_clk_pll_frequency
;
1517 calc_pll_cs
->min_pix_clock_pll_post_divider
=
1518 init_data
->min_pix_clk_pll_post_divider
;
1519 calc_pll_cs
->max_pix_clock_pll_post_divider
=
1520 init_data
->max_pix_clk_pll_post_divider
;
1521 calc_pll_cs
->min_pll_ref_divider
=
1522 init_data
->min_pll_ref_divider
;
1523 calc_pll_cs
->max_pll_ref_divider
=
1524 init_data
->max_pll_ref_divider
;
1526 if (init_data
->num_fract_fb_divider_decimal_point
== 0 ||
1527 init_data
->num_fract_fb_divider_decimal_point_precision
>
1528 init_data
->num_fract_fb_divider_decimal_point
) {
1530 "The dec point num or precision is incorrect!");
1533 if (init_data
->num_fract_fb_divider_decimal_point_precision
== 0) {
1535 "Incorrect fract feedback divider precision num!");
1539 calc_pll_cs
->fract_fb_divider_decimal_points_num
=
1540 init_data
->num_fract_fb_divider_decimal_point
;
1541 calc_pll_cs
->fract_fb_divider_precision
=
1542 init_data
->num_fract_fb_divider_decimal_point_precision
;
1543 calc_pll_cs
->fract_fb_divider_factor
= 1;
1544 for (i
= 0; i
< calc_pll_cs
->fract_fb_divider_decimal_points_num
; ++i
)
1545 calc_pll_cs
->fract_fb_divider_factor
*= 10;
1547 calc_pll_cs
->fract_fb_divider_precision_factor
= 1;
1550 i
< (calc_pll_cs
->fract_fb_divider_decimal_points_num
-
1551 calc_pll_cs
->fract_fb_divider_precision
);
1553 calc_pll_cs
->fract_fb_divider_precision_factor
*= 10;
1558 bool dce110_clk_src_construct(
1559 struct dce110_clk_src
*clk_src
,
1560 struct dc_context
*ctx
,
1561 struct dc_bios
*bios
,
1562 enum clock_source_id id
,
1563 const struct dce110_clk_src_regs
*regs
,
1564 const struct dce110_clk_src_shift
*cs_shift
,
1565 const struct dce110_clk_src_mask
*cs_mask
)
1567 struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi
;
1568 struct calc_pll_clock_source_init_data calc_pll_cs_init_data
;
1570 clk_src
->base
.ctx
= ctx
;
1571 clk_src
->bios
= bios
;
1572 clk_src
->base
.id
= id
;
1573 clk_src
->base
.funcs
= &dce110_clk_src_funcs
;
1575 clk_src
->regs
= regs
;
1576 clk_src
->cs_shift
= cs_shift
;
1577 clk_src
->cs_mask
= cs_mask
;
1579 if (!clk_src
->bios
->fw_info_valid
) {
1580 ASSERT_CRITICAL(false);
1581 goto unexpected_failure
;
1584 clk_src
->ext_clk_khz
= clk_src
->bios
->fw_info
.external_clock_source_frequency_for_dp
;
1586 /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1587 calc_pll_cs_init_data
.bp
= bios
;
1588 calc_pll_cs_init_data
.min_pix_clk_pll_post_divider
= 1;
1589 calc_pll_cs_init_data
.max_pix_clk_pll_post_divider
=
1590 clk_src
->cs_mask
->PLL_POST_DIV_PIXCLK
;
1591 calc_pll_cs_init_data
.min_pll_ref_divider
= 1;
1592 calc_pll_cs_init_data
.max_pll_ref_divider
= clk_src
->cs_mask
->PLL_REF_DIV
;
1593 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1594 calc_pll_cs_init_data
.min_override_input_pxl_clk_pll_freq_khz
= 0;
1595 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1596 calc_pll_cs_init_data
.max_override_input_pxl_clk_pll_freq_khz
= 0;
1597 /*numberOfFractFBDividerDecimalPoints*/
1598 calc_pll_cs_init_data
.num_fract_fb_divider_decimal_point
=
1599 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1600 /*number of decimal point to round off for fractional feedback divider value*/
1601 calc_pll_cs_init_data
.num_fract_fb_divider_decimal_point_precision
=
1602 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1603 calc_pll_cs_init_data
.ctx
= ctx
;
1605 /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1606 calc_pll_cs_init_data_hdmi
.bp
= bios
;
1607 calc_pll_cs_init_data_hdmi
.min_pix_clk_pll_post_divider
= 1;
1608 calc_pll_cs_init_data_hdmi
.max_pix_clk_pll_post_divider
=
1609 clk_src
->cs_mask
->PLL_POST_DIV_PIXCLK
;
1610 calc_pll_cs_init_data_hdmi
.min_pll_ref_divider
= 1;
1611 calc_pll_cs_init_data_hdmi
.max_pll_ref_divider
= clk_src
->cs_mask
->PLL_REF_DIV
;
1612 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1613 calc_pll_cs_init_data_hdmi
.min_override_input_pxl_clk_pll_freq_khz
= 13500;
1614 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1615 calc_pll_cs_init_data_hdmi
.max_override_input_pxl_clk_pll_freq_khz
= 27000;
1616 /*numberOfFractFBDividerDecimalPoints*/
1617 calc_pll_cs_init_data_hdmi
.num_fract_fb_divider_decimal_point
=
1618 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1619 /*number of decimal point to round off for fractional feedback divider value*/
1620 calc_pll_cs_init_data_hdmi
.num_fract_fb_divider_decimal_point_precision
=
1621 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1622 calc_pll_cs_init_data_hdmi
.ctx
= ctx
;
1624 clk_src
->ref_freq_khz
= clk_src
->bios
->fw_info
.pll_info
.crystal_frequency
;
1626 if (clk_src
->base
.id
== CLOCK_SOURCE_ID_EXTERNAL
)
1629 /* PLL only from here on */
1630 ss_info_from_atombios_create(clk_src
);
1632 if (!calc_pll_max_vco_construct(
1634 &calc_pll_cs_init_data
)) {
1635 ASSERT_CRITICAL(false);
1636 goto unexpected_failure
;
1640 calc_pll_cs_init_data_hdmi
.
1641 min_override_input_pxl_clk_pll_freq_khz
= clk_src
->ref_freq_khz
/2;
1642 calc_pll_cs_init_data_hdmi
.
1643 max_override_input_pxl_clk_pll_freq_khz
= clk_src
->ref_freq_khz
;
1646 if (!calc_pll_max_vco_construct(
1647 &clk_src
->calc_pll_hdmi
, &calc_pll_cs_init_data_hdmi
)) {
1648 ASSERT_CRITICAL(false);
1649 goto unexpected_failure
;
1658 bool dce112_clk_src_construct(
1659 struct dce110_clk_src
*clk_src
,
1660 struct dc_context
*ctx
,
1661 struct dc_bios
*bios
,
1662 enum clock_source_id id
,
1663 const struct dce110_clk_src_regs
*regs
,
1664 const struct dce110_clk_src_shift
*cs_shift
,
1665 const struct dce110_clk_src_mask
*cs_mask
)
1667 clk_src
->base
.ctx
= ctx
;
1668 clk_src
->bios
= bios
;
1669 clk_src
->base
.id
= id
;
1670 clk_src
->base
.funcs
= &dce112_clk_src_funcs
;
1672 clk_src
->regs
= regs
;
1673 clk_src
->cs_shift
= cs_shift
;
1674 clk_src
->cs_mask
= cs_mask
;
1676 if (!clk_src
->bios
->fw_info_valid
) {
1677 ASSERT_CRITICAL(false);
1681 clk_src
->ext_clk_khz
= clk_src
->bios
->fw_info
.external_clock_source_frequency_for_dp
;
1686 bool dcn20_clk_src_construct(
1687 struct dce110_clk_src
*clk_src
,
1688 struct dc_context
*ctx
,
1689 struct dc_bios
*bios
,
1690 enum clock_source_id id
,
1691 const struct dce110_clk_src_regs
*regs
,
1692 const struct dce110_clk_src_shift
*cs_shift
,
1693 const struct dce110_clk_src_mask
*cs_mask
)
1695 bool ret
= dce112_clk_src_construct(clk_src
, ctx
, bios
, id
, regs
, cs_shift
, cs_mask
);
1697 clk_src
->base
.funcs
= &dcn20_clk_src_funcs
;
1702 bool dcn3_clk_src_construct(
1703 struct dce110_clk_src
*clk_src
,
1704 struct dc_context
*ctx
,
1705 struct dc_bios
*bios
,
1706 enum clock_source_id id
,
1707 const struct dce110_clk_src_regs
*regs
,
1708 const struct dce110_clk_src_shift
*cs_shift
,
1709 const struct dce110_clk_src_mask
*cs_mask
)
1711 bool ret
= dce112_clk_src_construct(clk_src
, ctx
, bios
, id
, regs
, cs_shift
, cs_mask
);
1713 clk_src
->base
.funcs
= &dcn3_clk_src_funcs
;
1718 bool dcn31_clk_src_construct(
1719 struct dce110_clk_src
*clk_src
,
1720 struct dc_context
*ctx
,
1721 struct dc_bios
*bios
,
1722 enum clock_source_id id
,
1723 const struct dce110_clk_src_regs
*regs
,
1724 const struct dce110_clk_src_shift
*cs_shift
,
1725 const struct dce110_clk_src_mask
*cs_mask
)
1727 bool ret
= dce112_clk_src_construct(clk_src
, ctx
, bios
, id
, regs
, cs_shift
, cs_mask
);
1729 clk_src
->base
.funcs
= &dcn31_clk_src_funcs
;
1734 bool dcn301_clk_src_construct(
1735 struct dce110_clk_src
*clk_src
,
1736 struct dc_context
*ctx
,
1737 struct dc_bios
*bios
,
1738 enum clock_source_id id
,
1739 const struct dce110_clk_src_regs
*regs
,
1740 const struct dce110_clk_src_shift
*cs_shift
,
1741 const struct dce110_clk_src_mask
*cs_mask
)
1743 bool ret
= dce112_clk_src_construct(clk_src
, ctx
, bios
, id
, regs
, cs_shift
, cs_mask
);
1745 clk_src
->base
.funcs
= &dcn3_clk_src_funcs
;