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 <linux/slab.h>
28 #include "dm_services.h"
32 #include "core_types.h"
34 #include "include/grph_object_id.h"
35 #include "include/logger_interface.h"
37 #include "dce_clock_source.h"
40 #include "reg_helper.h"
48 #define DC_LOGGER_INIT()
51 #define FN(reg_name, field_name) \
52 clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
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
58 #define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
60 static const struct spread_spectrum_data
*get_ss_data_entry(
61 struct dce110_clk_src
*clk_src
,
62 enum signal_type signal
,
68 struct spread_spectrum_data
*ss_parm
= NULL
;
69 struct spread_spectrum_data
*ret
= NULL
;
72 case SIGNAL_TYPE_DVI_SINGLE_LINK
:
73 case SIGNAL_TYPE_DVI_DUAL_LINK
:
74 ss_parm
= clk_src
->dvi_ss_params
;
75 entrys_num
= clk_src
->dvi_ss_params_cnt
;
78 case SIGNAL_TYPE_HDMI_TYPE_A
:
79 ss_parm
= clk_src
->hdmi_ss_params
;
80 entrys_num
= clk_src
->hdmi_ss_params_cnt
;
83 case SIGNAL_TYPE_LVDS
:
84 ss_parm
= clk_src
->lvds_ss_params
;
85 entrys_num
= clk_src
->lvds_ss_params_cnt
;
88 case SIGNAL_TYPE_DISPLAY_PORT
:
89 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
91 case SIGNAL_TYPE_VIRTUAL
:
92 ss_parm
= clk_src
->dp_ss_params
;
93 entrys_num
= clk_src
->dp_ss_params_cnt
;
105 for (i
= 0; i
< entrys_num
; ++i
, ++ss_parm
) {
106 if (ss_parm
->freq_range_khz
>= pix_clk_khz
) {
116 * Function: calculate_fb_and_fractional_fb_divider
118 * * DESCRIPTION: Calculates feedback and fractional feedback dividers values
121 * targetPixelClock Desired frequency in 100 Hz
122 * ref_divider Reference divider (already known)
123 * postDivider Post Divider (already known)
124 * feedback_divider_param Pointer where to store
125 * calculated feedback divider value
126 * fract_feedback_divider_param Pointer where to store
127 * calculated fract feedback divider value
130 * It fills the locations pointed by feedback_divider_param
131 * and fract_feedback_divider_param
132 * It returns - true if feedback divider not 0
133 * - false should never happen)
135 static bool calculate_fb_and_fractional_fb_divider(
136 struct calc_pll_clock_source
*calc_pll_cs
,
137 uint32_t target_pix_clk_100hz
,
138 uint32_t ref_divider
,
139 uint32_t post_divider
,
140 uint32_t *feedback_divider_param
,
141 uint32_t *fract_feedback_divider_param
)
143 uint64_t feedback_divider
;
146 (uint64_t)target_pix_clk_100hz
* ref_divider
* post_divider
;
147 feedback_divider
*= 10;
148 /* additional factor, since we divide by 10 afterwards */
149 feedback_divider
*= (uint64_t)(calc_pll_cs
->fract_fb_divider_factor
);
150 feedback_divider
= div_u64(feedback_divider
, calc_pll_cs
->ref_freq_khz
* 10ull);
152 /*Round to the number of precision
153 * The following code replace the old code (ullfeedbackDivider + 5)/10
154 * for example if the difference between the number
155 * of fractional feedback decimal point and the fractional FB Divider precision
156 * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
158 feedback_divider
+= 5ULL *
159 calc_pll_cs
->fract_fb_divider_precision_factor
;
161 div_u64(feedback_divider
,
162 calc_pll_cs
->fract_fb_divider_precision_factor
* 10);
163 feedback_divider
*= (uint64_t)
164 (calc_pll_cs
->fract_fb_divider_precision_factor
);
166 *feedback_divider_param
=
169 calc_pll_cs
->fract_fb_divider_factor
,
170 fract_feedback_divider_param
);
172 if (*feedback_divider_param
!= 0)
178 *calc_fb_divider_checking_tolerance
180 *DESCRIPTION: Calculates Feedback and Fractional Feedback divider values
181 * for passed Reference and Post divider, checking for tolerance.
183 * pll_settings Pointer to structure
184 * ref_divider Reference divider (already known)
185 * postDivider Post Divider (already known)
186 * tolerance Tolerance for Calculated Pixel Clock to be within
189 * It fills the PLLSettings structure with PLL Dividers values
190 * if calculated values are within required tolerance
191 * It returns - true if error is within tolerance
192 * - false if error is not within tolerance
194 static bool calc_fb_divider_checking_tolerance(
195 struct calc_pll_clock_source
*calc_pll_cs
,
196 struct pll_settings
*pll_settings
,
197 uint32_t ref_divider
,
198 uint32_t post_divider
,
201 uint32_t feedback_divider
;
202 uint32_t fract_feedback_divider
;
203 uint32_t actual_calculated_clock_100hz
;
205 uint64_t actual_calc_clk_100hz
;
207 calculate_fb_and_fractional_fb_divider(
209 pll_settings
->adjusted_pix_clk_100hz
,
213 &fract_feedback_divider
);
215 /*Actual calculated value*/
216 actual_calc_clk_100hz
= (uint64_t)feedback_divider
*
217 calc_pll_cs
->fract_fb_divider_factor
+
218 fract_feedback_divider
;
219 actual_calc_clk_100hz
*= calc_pll_cs
->ref_freq_khz
* 10;
220 actual_calc_clk_100hz
=
221 div_u64(actual_calc_clk_100hz
,
222 ref_divider
* post_divider
*
223 calc_pll_cs
->fract_fb_divider_factor
);
225 actual_calculated_clock_100hz
= (uint32_t)(actual_calc_clk_100hz
);
227 abs_err
= (actual_calculated_clock_100hz
>
228 pll_settings
->adjusted_pix_clk_100hz
)
229 ? actual_calculated_clock_100hz
-
230 pll_settings
->adjusted_pix_clk_100hz
231 : pll_settings
->adjusted_pix_clk_100hz
-
232 actual_calculated_clock_100hz
;
234 if (abs_err
<= tolerance
) {
235 /*found good values*/
236 pll_settings
->reference_freq
= calc_pll_cs
->ref_freq_khz
;
237 pll_settings
->reference_divider
= ref_divider
;
238 pll_settings
->feedback_divider
= feedback_divider
;
239 pll_settings
->fract_feedback_divider
= fract_feedback_divider
;
240 pll_settings
->pix_clk_post_divider
= post_divider
;
241 pll_settings
->calculated_pix_clk_100hz
=
242 actual_calculated_clock_100hz
;
243 pll_settings
->vco_freq
=
244 actual_calculated_clock_100hz
* post_divider
/ 10;
250 static bool calc_pll_dividers_in_range(
251 struct calc_pll_clock_source
*calc_pll_cs
,
252 struct pll_settings
*pll_settings
,
253 uint32_t min_ref_divider
,
254 uint32_t max_ref_divider
,
255 uint32_t min_post_divider
,
256 uint32_t max_post_divider
,
257 uint32_t err_tolerance
)
259 uint32_t ref_divider
;
260 uint32_t post_divider
;
263 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
264 * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
265 tolerance
= (pll_settings
->adjusted_pix_clk_100hz
* err_tolerance
) /
267 if (tolerance
< CALC_PLL_CLK_SRC_ERR_TOLERANCE
)
268 tolerance
= CALC_PLL_CLK_SRC_ERR_TOLERANCE
;
271 post_divider
= max_post_divider
;
272 post_divider
>= min_post_divider
;
275 ref_divider
= min_ref_divider
;
276 ref_divider
<= max_ref_divider
;
278 if (calc_fb_divider_checking_tolerance(
292 static uint32_t calculate_pixel_clock_pll_dividers(
293 struct calc_pll_clock_source
*calc_pll_cs
,
294 struct pll_settings
*pll_settings
)
296 uint32_t err_tolerance
;
297 uint32_t min_post_divider
;
298 uint32_t max_post_divider
;
299 uint32_t min_ref_divider
;
300 uint32_t max_ref_divider
;
302 if (pll_settings
->adjusted_pix_clk_100hz
== 0) {
304 "%s Bad requested pixel clock", __func__
);
305 return MAX_PLL_CALC_ERROR
;
308 /* 1) Find Post divider ranges */
309 if (pll_settings
->pix_clk_post_divider
) {
310 min_post_divider
= pll_settings
->pix_clk_post_divider
;
311 max_post_divider
= pll_settings
->pix_clk_post_divider
;
313 min_post_divider
= calc_pll_cs
->min_pix_clock_pll_post_divider
;
314 if (min_post_divider
* pll_settings
->adjusted_pix_clk_100hz
<
315 calc_pll_cs
->min_vco_khz
* 10) {
316 min_post_divider
= calc_pll_cs
->min_vco_khz
* 10 /
317 pll_settings
->adjusted_pix_clk_100hz
;
318 if ((min_post_divider
*
319 pll_settings
->adjusted_pix_clk_100hz
) <
320 calc_pll_cs
->min_vco_khz
* 10)
324 max_post_divider
= calc_pll_cs
->max_pix_clock_pll_post_divider
;
325 if (max_post_divider
* pll_settings
->adjusted_pix_clk_100hz
326 > calc_pll_cs
->max_vco_khz
* 10)
327 max_post_divider
= calc_pll_cs
->max_vco_khz
* 10 /
328 pll_settings
->adjusted_pix_clk_100hz
;
331 /* 2) Find Reference divider ranges
332 * When SS is enabled, or for Display Port even without SS,
333 * pll_settings->referenceDivider is not zero.
334 * So calculate PPLL FB and fractional FB divider
335 * using the passed reference divider*/
337 if (pll_settings
->reference_divider
) {
338 min_ref_divider
= pll_settings
->reference_divider
;
339 max_ref_divider
= pll_settings
->reference_divider
;
341 min_ref_divider
= ((calc_pll_cs
->ref_freq_khz
342 / calc_pll_cs
->max_pll_input_freq_khz
)
343 > calc_pll_cs
->min_pll_ref_divider
)
344 ? calc_pll_cs
->ref_freq_khz
345 / calc_pll_cs
->max_pll_input_freq_khz
346 : calc_pll_cs
->min_pll_ref_divider
;
348 max_ref_divider
= ((calc_pll_cs
->ref_freq_khz
349 / calc_pll_cs
->min_pll_input_freq_khz
)
350 < calc_pll_cs
->max_pll_ref_divider
)
351 ? calc_pll_cs
->ref_freq_khz
/
352 calc_pll_cs
->min_pll_input_freq_khz
353 : calc_pll_cs
->max_pll_ref_divider
;
356 /* If some parameters are invalid we could have scenario when "min">"max"
357 * which produced endless loop later.
358 * We should investigate why we get the wrong parameters.
359 * But to follow the similar logic when "adjustedPixelClock" is set to be 0
360 * it is better to return here than cause system hang/watchdog timeout later.
361 * ## SVS Wed 15 Jul 2009 */
363 if (min_post_divider
> max_post_divider
) {
365 "%s Post divider range is invalid", __func__
);
366 return MAX_PLL_CALC_ERROR
;
369 if (min_ref_divider
> max_ref_divider
) {
371 "%s Reference divider range is invalid", __func__
);
372 return MAX_PLL_CALC_ERROR
;
375 /* 3) Try to find PLL dividers given ranges
376 * starting with minimal error tolerance.
377 * Increase error tolerance until PLL dividers found*/
378 err_tolerance
= MAX_PLL_CALC_ERROR
;
380 while (!calc_pll_dividers_in_range(
388 err_tolerance
+= (err_tolerance
> 10)
389 ? (err_tolerance
/ 10)
392 return err_tolerance
;
395 static bool pll_adjust_pix_clk(
396 struct dce110_clk_src
*clk_src
,
397 struct pixel_clk_params
*pix_clk_params
,
398 struct pll_settings
*pll_settings
)
400 uint32_t actual_pix_clk_100hz
= 0;
401 uint32_t requested_clk_100hz
= 0;
402 struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params
= {
404 enum bp_result bp_result
;
405 switch (pix_clk_params
->signal_type
) {
406 case SIGNAL_TYPE_HDMI_TYPE_A
: {
407 requested_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
408 if (pix_clk_params
->pixel_encoding
!= PIXEL_ENCODING_YCBCR422
) {
409 switch (pix_clk_params
->color_depth
) {
410 case COLOR_DEPTH_101010
:
411 requested_clk_100hz
= (requested_clk_100hz
* 5) >> 2;
413 case COLOR_DEPTH_121212
:
414 requested_clk_100hz
= (requested_clk_100hz
* 6) >> 2;
416 case COLOR_DEPTH_161616
:
417 requested_clk_100hz
= requested_clk_100hz
* 2;
423 actual_pix_clk_100hz
= requested_clk_100hz
;
427 case SIGNAL_TYPE_DISPLAY_PORT
:
428 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
429 case SIGNAL_TYPE_EDP
:
430 requested_clk_100hz
= pix_clk_params
->requested_sym_clk
* 10;
431 actual_pix_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
435 requested_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
436 actual_pix_clk_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
440 bp_adjust_pixel_clock_params
.pixel_clock
= requested_clk_100hz
/ 10;
441 bp_adjust_pixel_clock_params
.
442 encoder_object_id
= pix_clk_params
->encoder_object_id
;
443 bp_adjust_pixel_clock_params
.signal_type
= pix_clk_params
->signal_type
;
444 bp_adjust_pixel_clock_params
.
445 ss_enable
= pix_clk_params
->flags
.ENABLE_SS
;
446 bp_result
= clk_src
->bios
->funcs
->adjust_pixel_clock(
447 clk_src
->bios
, &bp_adjust_pixel_clock_params
);
448 if (bp_result
== BP_RESULT_OK
) {
449 pll_settings
->actual_pix_clk_100hz
= actual_pix_clk_100hz
;
450 pll_settings
->adjusted_pix_clk_100hz
=
451 bp_adjust_pixel_clock_params
.adjusted_pixel_clock
* 10;
452 pll_settings
->reference_divider
=
453 bp_adjust_pixel_clock_params
.reference_divider
;
454 pll_settings
->pix_clk_post_divider
=
455 bp_adjust_pixel_clock_params
.pixel_clock_post_divider
;
464 * Calculate PLL Dividers for given Clock Value.
465 * First will call VBIOS Adjust Exec table to check if requested Pixel clock
466 * will be Adjusted based on usage.
467 * Then it will calculate PLL Dividers for this Adjusted clock using preferred
468 * method (Maximum VCO frequency).
471 * Calculation error in units of 0.01%
474 static uint32_t dce110_get_pix_clk_dividers_helper (
475 struct dce110_clk_src
*clk_src
,
476 struct pll_settings
*pll_settings
,
477 struct pixel_clk_params
*pix_clk_params
)
480 uint32_t pll_calc_error
= MAX_PLL_CALC_ERROR
;
482 /* Check if reference clock is external (not pcie/xtalin)
484 * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB
485 * 04 - HSYNCA, 05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
486 REG_GET(PLL_CNTL
, PLL_REF_DIV_SRC
, &field
);
487 pll_settings
->use_external_clk
= (field
> 1);
489 /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
490 * (we do not care any more from SI for some older DP Sink which
491 * does not report SS support, no known issues) */
492 if ((pix_clk_params
->flags
.ENABLE_SS
) ||
493 (dc_is_dp_signal(pix_clk_params
->signal_type
))) {
495 const struct spread_spectrum_data
*ss_data
= get_ss_data_entry(
497 pix_clk_params
->signal_type
,
498 pll_settings
->adjusted_pix_clk_100hz
/ 10);
501 pll_settings
->ss_percentage
= ss_data
->percentage
;
504 /* Check VBIOS AdjustPixelClock Exec table */
505 if (!pll_adjust_pix_clk(clk_src
, pix_clk_params
, pll_settings
)) {
506 /* Should never happen, ASSERT and fill up values to be able
509 "%s: Failed to adjust pixel clock!!", __func__
);
510 pll_settings
->actual_pix_clk_100hz
=
511 pix_clk_params
->requested_pix_clk_100hz
;
512 pll_settings
->adjusted_pix_clk_100hz
=
513 pix_clk_params
->requested_pix_clk_100hz
;
515 if (dc_is_dp_signal(pix_clk_params
->signal_type
))
516 pll_settings
->adjusted_pix_clk_100hz
= 1000000;
519 /* Calculate Dividers */
520 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
)
521 /*Calculate Dividers by HDMI object, no SS case or SS case */
523 calculate_pixel_clock_pll_dividers(
524 &clk_src
->calc_pll_hdmi
,
527 /*Calculate Dividers by default object, no SS case or SS case */
529 calculate_pixel_clock_pll_dividers(
533 return pll_calc_error
;
536 static void dce112_get_pix_clk_dividers_helper (
537 struct dce110_clk_src
*clk_src
,
538 struct pll_settings
*pll_settings
,
539 struct pixel_clk_params
*pix_clk_params
)
541 uint32_t actual_pixel_clock_100hz
;
543 actual_pixel_clock_100hz
= pix_clk_params
->requested_pix_clk_100hz
;
544 /* Calculate Dividers */
545 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
546 switch (pix_clk_params
->color_depth
) {
547 case COLOR_DEPTH_101010
:
548 actual_pixel_clock_100hz
= (actual_pixel_clock_100hz
* 5) >> 2;
550 case COLOR_DEPTH_121212
:
551 actual_pixel_clock_100hz
= (actual_pixel_clock_100hz
* 6) >> 2;
553 case COLOR_DEPTH_161616
:
554 actual_pixel_clock_100hz
= actual_pixel_clock_100hz
* 2;
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
;
565 static 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
)
570 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
571 uint32_t pll_calc_error
= MAX_PLL_CALC_ERROR
;
574 if (pix_clk_params
== NULL
|| pll_settings
== NULL
575 || pix_clk_params
->requested_pix_clk_100hz
== 0) {
577 "%s: Invalid parameters!!\n", __func__
);
578 return pll_calc_error
;
581 memset(pll_settings
, 0, sizeof(*pll_settings
));
583 if (cs
->id
== CLOCK_SOURCE_ID_DP_DTO
||
584 cs
->id
== CLOCK_SOURCE_ID_EXTERNAL
) {
585 pll_settings
->adjusted_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
586 pll_settings
->calculated_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
587 pll_settings
->actual_pix_clk_100hz
=
588 pix_clk_params
->requested_pix_clk_100hz
;
592 pll_calc_error
= dce110_get_pix_clk_dividers_helper(clk_src
,
593 pll_settings
, pix_clk_params
);
595 return pll_calc_error
;
598 static uint32_t dce112_get_pix_clk_dividers(
599 struct clock_source
*cs
,
600 struct pixel_clk_params
*pix_clk_params
,
601 struct pll_settings
*pll_settings
)
603 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
606 if (pix_clk_params
== NULL
|| pll_settings
== NULL
607 || pix_clk_params
->requested_pix_clk_100hz
== 0) {
609 "%s: Invalid parameters!!\n", __func__
);
613 memset(pll_settings
, 0, sizeof(*pll_settings
));
615 if (cs
->id
== CLOCK_SOURCE_ID_DP_DTO
||
616 cs
->id
== CLOCK_SOURCE_ID_EXTERNAL
) {
617 pll_settings
->adjusted_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
618 pll_settings
->calculated_pix_clk_100hz
= clk_src
->ext_clk_khz
* 10;
619 pll_settings
->actual_pix_clk_100hz
=
620 pix_clk_params
->requested_pix_clk_100hz
;
624 dce112_get_pix_clk_dividers_helper(clk_src
,
625 pll_settings
, pix_clk_params
);
630 static bool disable_spread_spectrum(struct dce110_clk_src
*clk_src
)
632 enum bp_result result
;
633 struct bp_spread_spectrum_parameters bp_ss_params
= {0};
635 bp_ss_params
.pll_id
= clk_src
->base
.id
;
637 /*Call ASICControl to process ATOMBIOS Exec table*/
638 result
= clk_src
->bios
->funcs
->enable_spread_spectrum_on_ppll(
643 return result
== BP_RESULT_OK
;
646 static bool calculate_ss(
647 const struct pll_settings
*pll_settings
,
648 const struct spread_spectrum_data
*ss_data
,
649 struct delta_sigma_data
*ds_data
)
651 struct fixed31_32 fb_div
;
652 struct fixed31_32 ss_amount
;
653 struct fixed31_32 ss_nslip_amount
;
654 struct fixed31_32 ss_ds_frac_amount
;
655 struct fixed31_32 ss_step_size
;
656 struct fixed31_32 modulation_time
;
662 if (ss_data
->percentage
== 0)
664 if (pll_settings
== NULL
)
667 memset(ds_data
, 0, sizeof(struct delta_sigma_data
));
669 /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
670 /* 6 decimal point support in fractional feedback divider */
671 fb_div
= dc_fixpt_from_fraction(
672 pll_settings
->fract_feedback_divider
, 1000000);
673 fb_div
= dc_fixpt_add_int(fb_div
, pll_settings
->feedback_divider
);
675 ds_data
->ds_frac_amount
= 0;
676 /*spreadSpectrumPercentage is in the unit of .01%,
677 * so have to divided by 100 * 100*/
678 ss_amount
= dc_fixpt_mul(
679 fb_div
, dc_fixpt_from_fraction(ss_data
->percentage
,
680 100 * ss_data
->percentage_divider
));
681 ds_data
->feedback_amount
= dc_fixpt_floor(ss_amount
);
683 ss_nslip_amount
= dc_fixpt_sub(ss_amount
,
684 dc_fixpt_from_int(ds_data
->feedback_amount
));
685 ss_nslip_amount
= dc_fixpt_mul_int(ss_nslip_amount
, 10);
686 ds_data
->nfrac_amount
= dc_fixpt_floor(ss_nslip_amount
);
688 ss_ds_frac_amount
= dc_fixpt_sub(ss_nslip_amount
,
689 dc_fixpt_from_int(ds_data
->nfrac_amount
));
690 ss_ds_frac_amount
= dc_fixpt_mul_int(ss_ds_frac_amount
, 65536);
691 ds_data
->ds_frac_amount
= dc_fixpt_floor(ss_ds_frac_amount
);
693 /* compute SS_STEP_SIZE_DSFRAC */
694 modulation_time
= dc_fixpt_from_fraction(
695 pll_settings
->reference_freq
* 1000,
696 pll_settings
->reference_divider
* ss_data
->modulation_freq_hz
);
698 if (ss_data
->flags
.CENTER_SPREAD
)
699 modulation_time
= dc_fixpt_div_int(modulation_time
, 4);
701 modulation_time
= dc_fixpt_div_int(modulation_time
, 2);
703 ss_step_size
= dc_fixpt_div(ss_amount
, modulation_time
);
704 /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
705 ss_step_size
= dc_fixpt_mul_int(ss_step_size
, 65536 * 10);
706 ds_data
->ds_frac_size
= dc_fixpt_floor(ss_step_size
);
711 static bool enable_spread_spectrum(
712 struct dce110_clk_src
*clk_src
,
713 enum signal_type signal
, struct pll_settings
*pll_settings
)
715 struct bp_spread_spectrum_parameters bp_params
= {0};
716 struct delta_sigma_data d_s_data
;
717 const struct spread_spectrum_data
*ss_data
= NULL
;
719 ss_data
= get_ss_data_entry(
722 pll_settings
->calculated_pix_clk_100hz
/ 10);
724 /* Pixel clock PLL has been programmed to generate desired pixel clock,
725 * now enable SS on pixel clock */
726 /* TODO is it OK to return true not doing anything ??*/
727 if (ss_data
!= NULL
&& pll_settings
->ss_percentage
!= 0) {
728 if (calculate_ss(pll_settings
, ss_data
, &d_s_data
)) {
729 bp_params
.ds
.feedback_amount
=
730 d_s_data
.feedback_amount
;
731 bp_params
.ds
.nfrac_amount
=
732 d_s_data
.nfrac_amount
;
733 bp_params
.ds
.ds_frac_size
= d_s_data
.ds_frac_size
;
734 bp_params
.ds_frac_amount
=
735 d_s_data
.ds_frac_amount
;
736 bp_params
.flags
.DS_TYPE
= 1;
737 bp_params
.pll_id
= clk_src
->base
.id
;
738 bp_params
.percentage
= ss_data
->percentage
;
739 if (ss_data
->flags
.CENTER_SPREAD
)
740 bp_params
.flags
.CENTER_SPREAD
= 1;
741 if (ss_data
->flags
.EXTERNAL_SS
)
742 bp_params
.flags
.EXTERNAL_SS
= 1;
745 clk_src
->bios
->funcs
->
746 enable_spread_spectrum_on_ppll(
757 static void dce110_program_pixel_clk_resync(
758 struct dce110_clk_src
*clk_src
,
759 enum signal_type signal_type
,
760 enum dc_color_depth colordepth
)
762 REG_UPDATE(RESYNC_CNTL
,
763 DCCG_DEEP_COLOR_CNTL1
, 0);
765 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
766 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
767 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
768 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
770 if (signal_type
!= SIGNAL_TYPE_HDMI_TYPE_A
)
773 switch (colordepth
) {
774 case COLOR_DEPTH_888
:
775 REG_UPDATE(RESYNC_CNTL
,
776 DCCG_DEEP_COLOR_CNTL1
, 0);
778 case COLOR_DEPTH_101010
:
779 REG_UPDATE(RESYNC_CNTL
,
780 DCCG_DEEP_COLOR_CNTL1
, 1);
782 case COLOR_DEPTH_121212
:
783 REG_UPDATE(RESYNC_CNTL
,
784 DCCG_DEEP_COLOR_CNTL1
, 2);
786 case COLOR_DEPTH_161616
:
787 REG_UPDATE(RESYNC_CNTL
,
788 DCCG_DEEP_COLOR_CNTL1
, 3);
795 static void dce112_program_pixel_clk_resync(
796 struct dce110_clk_src
*clk_src
,
797 enum signal_type signal_type
,
798 enum dc_color_depth colordepth
,
799 bool enable_ycbcr420
)
801 uint32_t deep_color_cntl
= 0;
802 uint32_t double_rate_enable
= 0;
805 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
806 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
807 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
808 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
810 if (signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
811 double_rate_enable
= enable_ycbcr420
? 1 : 0;
813 switch (colordepth
) {
814 case COLOR_DEPTH_888
:
817 case COLOR_DEPTH_101010
:
820 case COLOR_DEPTH_121212
:
823 case COLOR_DEPTH_161616
:
831 if (clk_src
->cs_mask
->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE
)
832 REG_UPDATE_2(PIXCLK_RESYNC_CNTL
,
833 PHYPLLA_DCCG_DEEP_COLOR_CNTL
, deep_color_cntl
,
834 PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE
, double_rate_enable
);
836 REG_UPDATE(PIXCLK_RESYNC_CNTL
,
837 PHYPLLA_DCCG_DEEP_COLOR_CNTL
, deep_color_cntl
);
841 static bool dce110_program_pix_clk(
842 struct clock_source
*clock_source
,
843 struct pixel_clk_params
*pix_clk_params
,
844 struct pll_settings
*pll_settings
)
846 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
847 struct bp_pixel_clock_parameters bp_pc_params
= {0};
850 * ATOMBIOS will enable by default SS on PLL for DP,
851 * do not disable it here
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
);
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
;
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
;
874 if (clk_src
->bios
->funcs
->set_pixel_clock(
875 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
878 * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
879 * based on HW display PLL team, SS control settings should be programmed
880 * during PLL Reset, but they do not have effect
881 * until SS_EN is asserted.*/
882 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
883 && !dc_is_dp_signal(pix_clk_params
->signal_type
)) {
885 if (pix_clk_params
->flags
.ENABLE_SS
)
886 if (!enable_spread_spectrum(clk_src
,
887 pix_clk_params
->signal_type
,
891 /* Resync deep color DTO */
892 dce110_program_pixel_clk_resync(clk_src
,
893 pix_clk_params
->signal_type
,
894 pix_clk_params
->color_depth
);
900 static bool dce112_program_pix_clk(
901 struct clock_source
*clock_source
,
902 struct pixel_clk_params
*pix_clk_params
,
903 struct pll_settings
*pll_settings
)
905 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
906 struct bp_pixel_clock_parameters bp_pc_params
= {0};
908 #if defined(CONFIG_DRM_AMD_DC_DCN)
909 if (IS_FPGA_MAXIMUS_DC(clock_source
->ctx
->dce_environment
)) {
910 unsigned int inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
911 unsigned dp_dto_ref_100hz
= 7000000;
912 unsigned clock_100hz
= pll_settings
->actual_pix_clk_100hz
;
914 /* Set DTO values: phase = target clock, modulo = reference clock */
915 REG_WRITE(PHASE
[inst
], clock_100hz
);
916 REG_WRITE(MODULO
[inst
], dp_dto_ref_100hz
);
919 REG_UPDATE(PIXEL_RATE_CNTL
[inst
], DP_DTO0_ENABLE
, 1);
924 * ATOMBIOS will enable by default SS on PLL for DP,
925 * do not disable it here
927 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
&&
928 !dc_is_dp_signal(pix_clk_params
->signal_type
) &&
929 clock_source
->ctx
->dce_version
<= DCE_VERSION_11_0
)
930 disable_spread_spectrum(clk_src
);
932 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
933 bp_pc_params
.controller_id
= pix_clk_params
->controller_id
;
934 bp_pc_params
.pll_id
= clock_source
->id
;
935 bp_pc_params
.target_pixel_clock_100hz
= pll_settings
->actual_pix_clk_100hz
;
936 bp_pc_params
.encoder_object_id
= pix_clk_params
->encoder_object_id
;
937 bp_pc_params
.signal_type
= pix_clk_params
->signal_type
;
939 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
) {
940 bp_pc_params
.flags
.SET_GENLOCK_REF_DIV_SRC
=
941 pll_settings
->use_external_clk
;
942 bp_pc_params
.flags
.SET_XTALIN_REF_SRC
=
943 !pll_settings
->use_external_clk
;
944 if (pix_clk_params
->flags
.SUPPORT_YCBCR420
) {
945 bp_pc_params
.flags
.SUPPORT_YUV_420
= 1;
948 if (clk_src
->bios
->funcs
->set_pixel_clock(
949 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
951 /* Resync deep color DTO */
952 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
)
953 dce112_program_pixel_clk_resync(clk_src
,
954 pix_clk_params
->signal_type
,
955 pix_clk_params
->color_depth
,
956 pix_clk_params
->flags
.SUPPORT_YCBCR420
);
962 static bool dce110_clock_source_power_down(
963 struct clock_source
*clk_src
)
965 struct dce110_clk_src
*dce110_clk_src
= TO_DCE110_CLK_SRC(clk_src
);
966 enum bp_result bp_result
;
967 struct bp_pixel_clock_parameters bp_pixel_clock_params
= {0};
969 if (clk_src
->dp_clk_src
)
972 /* If Pixel Clock is 0 it means Power Down Pll*/
973 bp_pixel_clock_params
.controller_id
= CONTROLLER_ID_UNDEFINED
;
974 bp_pixel_clock_params
.pll_id
= clk_src
->id
;
975 bp_pixel_clock_params
.flags
.FORCE_PROGRAMMING_OF_PLL
= 1;
977 /*Call ASICControl to process ATOMBIOS Exec table*/
978 bp_result
= dce110_clk_src
->bios
->funcs
->set_pixel_clock(
979 dce110_clk_src
->bios
,
980 &bp_pixel_clock_params
);
982 return bp_result
== BP_RESULT_OK
;
985 static bool get_pixel_clk_frequency_100hz(
986 const struct clock_source
*clock_source
,
988 unsigned int *pixel_clk_khz
)
990 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(clock_source
);
991 unsigned int clock_hz
= 0;
993 if (clock_source
->id
== CLOCK_SOURCE_ID_DP_DTO
) {
994 clock_hz
= REG_READ(PHASE
[inst
]);
996 /* NOTE: There is agreement with VBIOS here that MODULO is
997 * programmed equal to DPREFCLK, in which case PHASE will be
998 * equivalent to pixel clock.
1000 *pixel_clk_khz
= clock_hz
/ 100;
1008 /* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
1009 struct pixel_rate_range_table_entry
{
1010 unsigned int range_min_khz
;
1011 unsigned int range_max_khz
;
1012 unsigned int target_pixel_rate_khz
;
1013 unsigned short mult_factor
;
1014 unsigned short div_factor
;
1017 static const struct pixel_rate_range_table_entry video_optimized_pixel_rates
[] = {
1019 {25170, 25180, 25200, 1000, 1001}, //25.2MHz -> 25.17
1020 {59340, 59350, 59400, 1000, 1001}, //59.4Mhz -> 59.340
1021 {74170, 74180, 74250, 1000, 1001}, //74.25Mhz -> 74.1758
1022 {125870, 125880, 126000, 1000, 1001}, //126Mhz -> 125.87
1023 {148350, 148360, 148500, 1000, 1001}, //148.5Mhz -> 148.3516
1024 {167830, 167840, 168000, 1000, 1001}, //168Mhz -> 167.83
1025 {222520, 222530, 222750, 1000, 1001}, //222.75Mhz -> 222.527
1026 {257140, 257150, 257400, 1000, 1001}, //257.4Mhz -> 257.1429
1027 {296700, 296710, 297000, 1000, 1001}, //297Mhz -> 296.7033
1028 {342850, 342860, 343200, 1000, 1001}, //343.2Mhz -> 342.857
1029 {395600, 395610, 396000, 1000, 1001}, //396Mhz -> 395.6
1030 {409090, 409100, 409500, 1000, 1001}, //409.5Mhz -> 409.091
1031 {445050, 445060, 445500, 1000, 1001}, //445.5Mhz -> 445.055
1032 {467530, 467540, 468000, 1000, 1001}, //468Mhz -> 467.5325
1033 {519230, 519240, 519750, 1000, 1001}, //519.75Mhz -> 519.231
1034 {525970, 525980, 526500, 1000, 1001}, //526.5Mhz -> 525.974
1035 {545450, 545460, 546000, 1000, 1001}, //546Mhz -> 545.455
1036 {593400, 593410, 594000, 1000, 1001}, //594Mhz -> 593.4066
1037 {623370, 623380, 624000, 1000, 1001}, //624Mhz -> 623.377
1038 {692300, 692310, 693000, 1000, 1001}, //693Mhz -> 692.308
1039 {701290, 701300, 702000, 1000, 1001}, //702Mhz -> 701.2987
1040 {791200, 791210, 792000, 1000, 1001}, //792Mhz -> 791.209
1041 {890100, 890110, 891000, 1000, 1001}, //891Mhz -> 890.1099
1042 {1186810, 1186820, 1188000, 1000, 1001},//1188Mhz -> 1186.8131
1045 {27020, 27030, 27000, 1001, 1000}, //27Mhz
1046 {54050, 54060, 54000, 1001, 1000}, //54Mhz
1047 {108100, 108110, 108000, 1001, 1000},//108Mhz
1050 static bool dcn20_program_pix_clk(
1051 struct clock_source
*clock_source
,
1052 struct pixel_clk_params
*pix_clk_params
,
1053 struct pll_settings
*pll_settings
)
1055 dce112_program_pix_clk(clock_source
, pix_clk_params
, pll_settings
);
1060 static const struct clock_source_funcs dcn20_clk_src_funcs
= {
1061 .cs_power_down
= dce110_clock_source_power_down
,
1062 .program_pix_clk
= dcn20_program_pix_clk
,
1063 .get_pix_clk_dividers
= dce112_get_pix_clk_dividers
,
1064 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1067 /*****************************************/
1069 /*****************************************/
1071 static const struct clock_source_funcs dce112_clk_src_funcs
= {
1072 .cs_power_down
= dce110_clock_source_power_down
,
1073 .program_pix_clk
= dce112_program_pix_clk
,
1074 .get_pix_clk_dividers
= dce112_get_pix_clk_dividers
,
1075 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1077 static const struct clock_source_funcs dce110_clk_src_funcs
= {
1078 .cs_power_down
= dce110_clock_source_power_down
,
1079 .program_pix_clk
= dce110_program_pix_clk
,
1080 .get_pix_clk_dividers
= dce110_get_pix_clk_dividers
,
1081 .get_pixel_clk_frequency_100hz
= get_pixel_clk_frequency_100hz
1085 static void get_ss_info_from_atombios(
1086 struct dce110_clk_src
*clk_src
,
1087 enum as_signal_type as_signal
,
1088 struct spread_spectrum_data
*spread_spectrum_data
[],
1089 uint32_t *ss_entries_num
)
1091 enum bp_result bp_result
= BP_RESULT_FAILURE
;
1092 struct spread_spectrum_info
*ss_info
;
1093 struct spread_spectrum_data
*ss_data
;
1094 struct spread_spectrum_info
*ss_info_cur
;
1095 struct spread_spectrum_data
*ss_data_cur
;
1098 if (ss_entries_num
== NULL
) {
1100 "Invalid entry !!!\n");
1103 if (spread_spectrum_data
== NULL
) {
1105 "Invalid array pointer!!!\n");
1109 spread_spectrum_data
[0] = NULL
;
1110 *ss_entries_num
= 0;
1112 *ss_entries_num
= clk_src
->bios
->funcs
->get_ss_entry_number(
1116 if (*ss_entries_num
== 0)
1119 ss_info
= kcalloc(*ss_entries_num
,
1120 sizeof(struct spread_spectrum_info
),
1122 ss_info_cur
= ss_info
;
1123 if (ss_info
== NULL
)
1126 ss_data
= kcalloc(*ss_entries_num
,
1127 sizeof(struct spread_spectrum_data
),
1129 if (ss_data
== NULL
)
1132 for (i
= 0, ss_info_cur
= ss_info
;
1133 i
< (*ss_entries_num
);
1134 ++i
, ++ss_info_cur
) {
1136 bp_result
= clk_src
->bios
->funcs
->get_spread_spectrum_info(
1142 if (bp_result
!= BP_RESULT_OK
)
1146 for (i
= 0, ss_info_cur
= ss_info
, ss_data_cur
= ss_data
;
1147 i
< (*ss_entries_num
);
1148 ++i
, ++ss_info_cur
, ++ss_data_cur
) {
1150 if (ss_info_cur
->type
.STEP_AND_DELAY_INFO
!= false) {
1152 "Invalid ATOMBIOS SS Table!!!\n");
1156 /* for HDMI check SS percentage,
1157 * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1158 if (as_signal
== AS_SIGNAL_TYPE_HDMI
1159 && ss_info_cur
->spread_spectrum_percentage
> 6){
1160 /* invalid input, do nothing */
1162 "Invalid SS percentage ");
1164 "for HDMI in ATOMBIOS info Table!!!\n");
1167 if (ss_info_cur
->spread_percentage_divider
== 1000) {
1168 /* Keep previous precision from ATOMBIOS for these
1169 * in case new precision set by ATOMBIOS for these
1170 * (otherwise all code in DCE specific classes
1171 * for all previous ASICs would need
1172 * to be updated for SS calculations,
1173 * Audio SS compensation and DP DTO SS compensation
1174 * which assumes fixed SS percentage Divider = 100)*/
1175 ss_info_cur
->spread_spectrum_percentage
/= 10;
1176 ss_info_cur
->spread_percentage_divider
= 100;
1179 ss_data_cur
->freq_range_khz
= ss_info_cur
->target_clock_range
;
1180 ss_data_cur
->percentage
=
1181 ss_info_cur
->spread_spectrum_percentage
;
1182 ss_data_cur
->percentage_divider
=
1183 ss_info_cur
->spread_percentage_divider
;
1184 ss_data_cur
->modulation_freq_hz
=
1185 ss_info_cur
->spread_spectrum_range
;
1187 if (ss_info_cur
->type
.CENTER_MODE
)
1188 ss_data_cur
->flags
.CENTER_SPREAD
= 1;
1190 if (ss_info_cur
->type
.EXTERNAL
)
1191 ss_data_cur
->flags
.EXTERNAL_SS
= 1;
1195 *spread_spectrum_data
= ss_data
;
1201 *ss_entries_num
= 0;
1206 static void ss_info_from_atombios_create(
1207 struct dce110_clk_src
*clk_src
)
1209 get_ss_info_from_atombios(
1211 AS_SIGNAL_TYPE_DISPLAY_PORT
,
1212 &clk_src
->dp_ss_params
,
1213 &clk_src
->dp_ss_params_cnt
);
1214 get_ss_info_from_atombios(
1216 AS_SIGNAL_TYPE_HDMI
,
1217 &clk_src
->hdmi_ss_params
,
1218 &clk_src
->hdmi_ss_params_cnt
);
1219 get_ss_info_from_atombios(
1222 &clk_src
->dvi_ss_params
,
1223 &clk_src
->dvi_ss_params_cnt
);
1224 get_ss_info_from_atombios(
1226 AS_SIGNAL_TYPE_LVDS
,
1227 &clk_src
->lvds_ss_params
,
1228 &clk_src
->lvds_ss_params_cnt
);
1231 static bool calc_pll_max_vco_construct(
1232 struct calc_pll_clock_source
*calc_pll_cs
,
1233 struct calc_pll_clock_source_init_data
*init_data
)
1236 struct dc_firmware_info
*fw_info
;
1237 if (calc_pll_cs
== NULL
||
1238 init_data
== NULL
||
1239 init_data
->bp
== NULL
)
1242 if (!init_data
->bp
->fw_info_valid
)
1245 fw_info
= &init_data
->bp
->fw_info
;
1246 calc_pll_cs
->ctx
= init_data
->ctx
;
1247 calc_pll_cs
->ref_freq_khz
= fw_info
->pll_info
.crystal_frequency
;
1248 calc_pll_cs
->min_vco_khz
=
1249 fw_info
->pll_info
.min_output_pxl_clk_pll_frequency
;
1250 calc_pll_cs
->max_vco_khz
=
1251 fw_info
->pll_info
.max_output_pxl_clk_pll_frequency
;
1253 if (init_data
->max_override_input_pxl_clk_pll_freq_khz
!= 0)
1254 calc_pll_cs
->max_pll_input_freq_khz
=
1255 init_data
->max_override_input_pxl_clk_pll_freq_khz
;
1257 calc_pll_cs
->max_pll_input_freq_khz
=
1258 fw_info
->pll_info
.max_input_pxl_clk_pll_frequency
;
1260 if (init_data
->min_override_input_pxl_clk_pll_freq_khz
!= 0)
1261 calc_pll_cs
->min_pll_input_freq_khz
=
1262 init_data
->min_override_input_pxl_clk_pll_freq_khz
;
1264 calc_pll_cs
->min_pll_input_freq_khz
=
1265 fw_info
->pll_info
.min_input_pxl_clk_pll_frequency
;
1267 calc_pll_cs
->min_pix_clock_pll_post_divider
=
1268 init_data
->min_pix_clk_pll_post_divider
;
1269 calc_pll_cs
->max_pix_clock_pll_post_divider
=
1270 init_data
->max_pix_clk_pll_post_divider
;
1271 calc_pll_cs
->min_pll_ref_divider
=
1272 init_data
->min_pll_ref_divider
;
1273 calc_pll_cs
->max_pll_ref_divider
=
1274 init_data
->max_pll_ref_divider
;
1276 if (init_data
->num_fract_fb_divider_decimal_point
== 0 ||
1277 init_data
->num_fract_fb_divider_decimal_point_precision
>
1278 init_data
->num_fract_fb_divider_decimal_point
) {
1280 "The dec point num or precision is incorrect!");
1283 if (init_data
->num_fract_fb_divider_decimal_point_precision
== 0) {
1285 "Incorrect fract feedback divider precision num!");
1289 calc_pll_cs
->fract_fb_divider_decimal_points_num
=
1290 init_data
->num_fract_fb_divider_decimal_point
;
1291 calc_pll_cs
->fract_fb_divider_precision
=
1292 init_data
->num_fract_fb_divider_decimal_point_precision
;
1293 calc_pll_cs
->fract_fb_divider_factor
= 1;
1294 for (i
= 0; i
< calc_pll_cs
->fract_fb_divider_decimal_points_num
; ++i
)
1295 calc_pll_cs
->fract_fb_divider_factor
*= 10;
1297 calc_pll_cs
->fract_fb_divider_precision_factor
= 1;
1300 i
< (calc_pll_cs
->fract_fb_divider_decimal_points_num
-
1301 calc_pll_cs
->fract_fb_divider_precision
);
1303 calc_pll_cs
->fract_fb_divider_precision_factor
*= 10;
1308 bool dce110_clk_src_construct(
1309 struct dce110_clk_src
*clk_src
,
1310 struct dc_context
*ctx
,
1311 struct dc_bios
*bios
,
1312 enum clock_source_id id
,
1313 const struct dce110_clk_src_regs
*regs
,
1314 const struct dce110_clk_src_shift
*cs_shift
,
1315 const struct dce110_clk_src_mask
*cs_mask
)
1317 struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi
;
1318 struct calc_pll_clock_source_init_data calc_pll_cs_init_data
;
1320 clk_src
->base
.ctx
= ctx
;
1321 clk_src
->bios
= bios
;
1322 clk_src
->base
.id
= id
;
1323 clk_src
->base
.funcs
= &dce110_clk_src_funcs
;
1325 clk_src
->regs
= regs
;
1326 clk_src
->cs_shift
= cs_shift
;
1327 clk_src
->cs_mask
= cs_mask
;
1329 if (!clk_src
->bios
->fw_info_valid
) {
1330 ASSERT_CRITICAL(false);
1331 goto unexpected_failure
;
1334 clk_src
->ext_clk_khz
= clk_src
->bios
->fw_info
.external_clock_source_frequency_for_dp
;
1336 /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1337 calc_pll_cs_init_data
.bp
= bios
;
1338 calc_pll_cs_init_data
.min_pix_clk_pll_post_divider
= 1;
1339 calc_pll_cs_init_data
.max_pix_clk_pll_post_divider
=
1340 clk_src
->cs_mask
->PLL_POST_DIV_PIXCLK
;
1341 calc_pll_cs_init_data
.min_pll_ref_divider
= 1;
1342 calc_pll_cs_init_data
.max_pll_ref_divider
= clk_src
->cs_mask
->PLL_REF_DIV
;
1343 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1344 calc_pll_cs_init_data
.min_override_input_pxl_clk_pll_freq_khz
= 0;
1345 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1346 calc_pll_cs_init_data
.max_override_input_pxl_clk_pll_freq_khz
= 0;
1347 /*numberOfFractFBDividerDecimalPoints*/
1348 calc_pll_cs_init_data
.num_fract_fb_divider_decimal_point
=
1349 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1350 /*number of decimal point to round off for fractional feedback divider value*/
1351 calc_pll_cs_init_data
.num_fract_fb_divider_decimal_point_precision
=
1352 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1353 calc_pll_cs_init_data
.ctx
= ctx
;
1355 /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1356 calc_pll_cs_init_data_hdmi
.bp
= bios
;
1357 calc_pll_cs_init_data_hdmi
.min_pix_clk_pll_post_divider
= 1;
1358 calc_pll_cs_init_data_hdmi
.max_pix_clk_pll_post_divider
=
1359 clk_src
->cs_mask
->PLL_POST_DIV_PIXCLK
;
1360 calc_pll_cs_init_data_hdmi
.min_pll_ref_divider
= 1;
1361 calc_pll_cs_init_data_hdmi
.max_pll_ref_divider
= clk_src
->cs_mask
->PLL_REF_DIV
;
1362 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1363 calc_pll_cs_init_data_hdmi
.min_override_input_pxl_clk_pll_freq_khz
= 13500;
1364 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1365 calc_pll_cs_init_data_hdmi
.max_override_input_pxl_clk_pll_freq_khz
= 27000;
1366 /*numberOfFractFBDividerDecimalPoints*/
1367 calc_pll_cs_init_data_hdmi
.num_fract_fb_divider_decimal_point
=
1368 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1369 /*number of decimal point to round off for fractional feedback divider value*/
1370 calc_pll_cs_init_data_hdmi
.num_fract_fb_divider_decimal_point_precision
=
1371 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1372 calc_pll_cs_init_data_hdmi
.ctx
= ctx
;
1374 clk_src
->ref_freq_khz
= clk_src
->bios
->fw_info
.pll_info
.crystal_frequency
;
1376 if (clk_src
->base
.id
== CLOCK_SOURCE_ID_EXTERNAL
)
1379 /* PLL only from here on */
1380 ss_info_from_atombios_create(clk_src
);
1382 if (!calc_pll_max_vco_construct(
1384 &calc_pll_cs_init_data
)) {
1385 ASSERT_CRITICAL(false);
1386 goto unexpected_failure
;
1390 calc_pll_cs_init_data_hdmi
.
1391 min_override_input_pxl_clk_pll_freq_khz
= clk_src
->ref_freq_khz
/2;
1392 calc_pll_cs_init_data_hdmi
.
1393 max_override_input_pxl_clk_pll_freq_khz
= clk_src
->ref_freq_khz
;
1396 if (!calc_pll_max_vco_construct(
1397 &clk_src
->calc_pll_hdmi
, &calc_pll_cs_init_data_hdmi
)) {
1398 ASSERT_CRITICAL(false);
1399 goto unexpected_failure
;
1408 bool dce112_clk_src_construct(
1409 struct dce110_clk_src
*clk_src
,
1410 struct dc_context
*ctx
,
1411 struct dc_bios
*bios
,
1412 enum clock_source_id id
,
1413 const struct dce110_clk_src_regs
*regs
,
1414 const struct dce110_clk_src_shift
*cs_shift
,
1415 const struct dce110_clk_src_mask
*cs_mask
)
1417 clk_src
->base
.ctx
= ctx
;
1418 clk_src
->bios
= bios
;
1419 clk_src
->base
.id
= id
;
1420 clk_src
->base
.funcs
= &dce112_clk_src_funcs
;
1422 clk_src
->regs
= regs
;
1423 clk_src
->cs_shift
= cs_shift
;
1424 clk_src
->cs_mask
= cs_mask
;
1426 if (!clk_src
->bios
->fw_info_valid
) {
1427 ASSERT_CRITICAL(false);
1431 clk_src
->ext_clk_khz
= clk_src
->bios
->fw_info
.external_clock_source_frequency_for_dp
;
1436 bool dcn20_clk_src_construct(
1437 struct dce110_clk_src
*clk_src
,
1438 struct dc_context
*ctx
,
1439 struct dc_bios
*bios
,
1440 enum clock_source_id id
,
1441 const struct dce110_clk_src_regs
*regs
,
1442 const struct dce110_clk_src_shift
*cs_shift
,
1443 const struct dce110_clk_src_mask
*cs_mask
)
1445 bool ret
= dce112_clk_src_construct(clk_src
, ctx
, bios
, id
, regs
, cs_shift
, cs_mask
);
1447 clk_src
->base
.funcs
= &dcn20_clk_src_funcs
;