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"
37 #include "reg_helper.h"
46 #define FN(reg_name, field_name) \
47 clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
49 #define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
50 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
51 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF
53 static const struct spread_spectrum_data
*get_ss_data_entry(
54 struct dce110_clk_src
*clk_src
,
55 enum signal_type signal
,
61 struct spread_spectrum_data
*ss_parm
= NULL
;
62 struct spread_spectrum_data
*ret
= NULL
;
65 case SIGNAL_TYPE_DVI_SINGLE_LINK
:
66 case SIGNAL_TYPE_DVI_DUAL_LINK
:
67 ss_parm
= clk_src
->dvi_ss_params
;
68 entrys_num
= clk_src
->dvi_ss_params_cnt
;
71 case SIGNAL_TYPE_HDMI_TYPE_A
:
72 ss_parm
= clk_src
->hdmi_ss_params
;
73 entrys_num
= clk_src
->hdmi_ss_params_cnt
;
76 case SIGNAL_TYPE_DISPLAY_PORT
:
77 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
79 case SIGNAL_TYPE_VIRTUAL
:
80 ss_parm
= clk_src
->dp_ss_params
;
81 entrys_num
= clk_src
->dp_ss_params_cnt
;
93 for (i
= 0; i
< entrys_num
; ++i
, ++ss_parm
) {
94 if (ss_parm
->freq_range_khz
>= pix_clk_khz
) {
104 * Function: calculate_fb_and_fractional_fb_divider
106 * * DESCRIPTION: Calculates feedback and fractional feedback dividers values
109 * targetPixelClock Desired frequency in 10 KHz
110 * ref_divider Reference divider (already known)
111 * postDivider Post Divider (already known)
112 * feedback_divider_param Pointer where to store
113 * calculated feedback divider value
114 * fract_feedback_divider_param Pointer where to store
115 * calculated fract feedback divider value
118 * It fills the locations pointed by feedback_divider_param
119 * and fract_feedback_divider_param
120 * It returns - true if feedback divider not 0
121 * - false should never happen)
123 static bool calculate_fb_and_fractional_fb_divider(
124 struct calc_pll_clock_source
*calc_pll_cs
,
125 uint32_t target_pix_clk_khz
,
126 uint32_t ref_divider
,
127 uint32_t post_divider
,
128 uint32_t *feedback_divider_param
,
129 uint32_t *fract_feedback_divider_param
)
131 uint64_t feedback_divider
;
134 (uint64_t)target_pix_clk_khz
* ref_divider
* post_divider
;
135 feedback_divider
*= 10;
136 /* additional factor, since we divide by 10 afterwards */
137 feedback_divider
*= (uint64_t)(calc_pll_cs
->fract_fb_divider_factor
);
138 feedback_divider
= div_u64(feedback_divider
, calc_pll_cs
->ref_freq_khz
);
140 /*Round to the number of precision
141 * The following code replace the old code (ullfeedbackDivider + 5)/10
142 * for example if the difference between the number
143 * of fractional feedback decimal point and the fractional FB Divider precision
144 * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
146 feedback_divider
+= 5ULL *
147 calc_pll_cs
->fract_fb_divider_precision_factor
;
149 div_u64(feedback_divider
,
150 calc_pll_cs
->fract_fb_divider_precision_factor
* 10);
151 feedback_divider
*= (uint64_t)
152 (calc_pll_cs
->fract_fb_divider_precision_factor
);
154 *feedback_divider_param
=
157 calc_pll_cs
->fract_fb_divider_factor
,
158 fract_feedback_divider_param
);
160 if (*feedback_divider_param
!= 0)
166 *calc_fb_divider_checking_tolerance
168 *DESCRIPTION: Calculates Feedback and Fractional Feedback divider values
169 * for passed Reference and Post divider, checking for tolerance.
171 * pll_settings Pointer to structure
172 * ref_divider Reference divider (already known)
173 * postDivider Post Divider (already known)
174 * tolerance Tolerance for Calculated Pixel Clock to be within
177 * It fills the PLLSettings structure with PLL Dividers values
178 * if calculated values are within required tolerance
179 * It returns - true if eror is within tolerance
180 * - false if eror is not within tolerance
182 static bool calc_fb_divider_checking_tolerance(
183 struct calc_pll_clock_source
*calc_pll_cs
,
184 struct pll_settings
*pll_settings
,
185 uint32_t ref_divider
,
186 uint32_t post_divider
,
189 uint32_t feedback_divider
;
190 uint32_t fract_feedback_divider
;
191 uint32_t actual_calculated_clock_khz
;
193 uint64_t actual_calc_clk_khz
;
195 calculate_fb_and_fractional_fb_divider(
197 pll_settings
->adjusted_pix_clk
,
201 &fract_feedback_divider
);
203 /*Actual calculated value*/
204 actual_calc_clk_khz
= (uint64_t)feedback_divider
*
205 calc_pll_cs
->fract_fb_divider_factor
+
206 fract_feedback_divider
;
207 actual_calc_clk_khz
*= calc_pll_cs
->ref_freq_khz
;
208 actual_calc_clk_khz
=
209 div_u64(actual_calc_clk_khz
,
210 ref_divider
* post_divider
*
211 calc_pll_cs
->fract_fb_divider_factor
);
213 actual_calculated_clock_khz
= (uint32_t)(actual_calc_clk_khz
);
215 abs_err
= (actual_calculated_clock_khz
>
216 pll_settings
->adjusted_pix_clk
)
217 ? actual_calculated_clock_khz
-
218 pll_settings
->adjusted_pix_clk
219 : pll_settings
->adjusted_pix_clk
-
220 actual_calculated_clock_khz
;
222 if (abs_err
<= tolerance
) {
223 /*found good values*/
224 pll_settings
->reference_freq
= calc_pll_cs
->ref_freq_khz
;
225 pll_settings
->reference_divider
= ref_divider
;
226 pll_settings
->feedback_divider
= feedback_divider
;
227 pll_settings
->fract_feedback_divider
= fract_feedback_divider
;
228 pll_settings
->pix_clk_post_divider
= post_divider
;
229 pll_settings
->calculated_pix_clk
=
230 actual_calculated_clock_khz
;
231 pll_settings
->vco_freq
=
232 actual_calculated_clock_khz
* post_divider
;
238 static bool calc_pll_dividers_in_range(
239 struct calc_pll_clock_source
*calc_pll_cs
,
240 struct pll_settings
*pll_settings
,
241 uint32_t min_ref_divider
,
242 uint32_t max_ref_divider
,
243 uint32_t min_post_divider
,
244 uint32_t max_post_divider
,
245 uint32_t err_tolerance
)
247 uint32_t ref_divider
;
248 uint32_t post_divider
;
251 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
252 * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
253 tolerance
= (pll_settings
->adjusted_pix_clk
* err_tolerance
) /
255 if (tolerance
< CALC_PLL_CLK_SRC_ERR_TOLERANCE
)
256 tolerance
= CALC_PLL_CLK_SRC_ERR_TOLERANCE
;
259 post_divider
= max_post_divider
;
260 post_divider
>= min_post_divider
;
263 ref_divider
= min_ref_divider
;
264 ref_divider
<= max_ref_divider
;
266 if (calc_fb_divider_checking_tolerance(
280 static uint32_t calculate_pixel_clock_pll_dividers(
281 struct calc_pll_clock_source
*calc_pll_cs
,
282 struct pll_settings
*pll_settings
)
284 uint32_t err_tolerance
;
285 uint32_t min_post_divider
;
286 uint32_t max_post_divider
;
287 uint32_t min_ref_divider
;
288 uint32_t max_ref_divider
;
290 if (pll_settings
->adjusted_pix_clk
== 0) {
291 dm_logger_write(calc_pll_cs
->ctx
->logger
, LOG_ERROR
,
292 "%s Bad requested pixel clock", __func__
);
293 return MAX_PLL_CALC_ERROR
;
296 /* 1) Find Post divider ranges */
297 if (pll_settings
->pix_clk_post_divider
) {
298 min_post_divider
= pll_settings
->pix_clk_post_divider
;
299 max_post_divider
= pll_settings
->pix_clk_post_divider
;
301 min_post_divider
= calc_pll_cs
->min_pix_clock_pll_post_divider
;
302 if (min_post_divider
* pll_settings
->adjusted_pix_clk
<
303 calc_pll_cs
->min_vco_khz
) {
304 min_post_divider
= calc_pll_cs
->min_vco_khz
/
305 pll_settings
->adjusted_pix_clk
;
306 if ((min_post_divider
*
307 pll_settings
->adjusted_pix_clk
) <
308 calc_pll_cs
->min_vco_khz
)
312 max_post_divider
= calc_pll_cs
->max_pix_clock_pll_post_divider
;
313 if (max_post_divider
* pll_settings
->adjusted_pix_clk
314 > calc_pll_cs
->max_vco_khz
)
315 max_post_divider
= calc_pll_cs
->max_vco_khz
/
316 pll_settings
->adjusted_pix_clk
;
319 /* 2) Find Reference divider ranges
320 * When SS is enabled, or for Display Port even without SS,
321 * pll_settings->referenceDivider is not zero.
322 * So calculate PPLL FB and fractional FB divider
323 * using the passed reference divider*/
325 if (pll_settings
->reference_divider
) {
326 min_ref_divider
= pll_settings
->reference_divider
;
327 max_ref_divider
= pll_settings
->reference_divider
;
329 min_ref_divider
= ((calc_pll_cs
->ref_freq_khz
330 / calc_pll_cs
->max_pll_input_freq_khz
)
331 > calc_pll_cs
->min_pll_ref_divider
)
332 ? calc_pll_cs
->ref_freq_khz
333 / calc_pll_cs
->max_pll_input_freq_khz
334 : calc_pll_cs
->min_pll_ref_divider
;
336 max_ref_divider
= ((calc_pll_cs
->ref_freq_khz
337 / calc_pll_cs
->min_pll_input_freq_khz
)
338 < calc_pll_cs
->max_pll_ref_divider
)
339 ? calc_pll_cs
->ref_freq_khz
/
340 calc_pll_cs
->min_pll_input_freq_khz
341 : calc_pll_cs
->max_pll_ref_divider
;
344 /* If some parameters are invalid we could have scenario when "min">"max"
345 * which produced endless loop later.
346 * We should investigate why we get the wrong parameters.
347 * But to follow the similar logic when "adjustedPixelClock" is set to be 0
348 * it is better to return here than cause system hang/watchdog timeout later.
349 * ## SVS Wed 15 Jul 2009 */
351 if (min_post_divider
> max_post_divider
) {
352 dm_logger_write(calc_pll_cs
->ctx
->logger
, LOG_ERROR
,
353 "%s Post divider range is invalid", __func__
);
354 return MAX_PLL_CALC_ERROR
;
357 if (min_ref_divider
> max_ref_divider
) {
358 dm_logger_write(calc_pll_cs
->ctx
->logger
, LOG_ERROR
,
359 "%s Reference divider range is invalid", __func__
);
360 return MAX_PLL_CALC_ERROR
;
363 /* 3) Try to find PLL dividers given ranges
364 * starting with minimal error tolerance.
365 * Increase error tolerance until PLL dividers found*/
366 err_tolerance
= MAX_PLL_CALC_ERROR
;
368 while (!calc_pll_dividers_in_range(
376 err_tolerance
+= (err_tolerance
> 10)
377 ? (err_tolerance
/ 10)
380 return err_tolerance
;
383 static bool pll_adjust_pix_clk(
384 struct dce110_clk_src
*clk_src
,
385 struct pixel_clk_params
*pix_clk_params
,
386 struct pll_settings
*pll_settings
)
388 uint32_t actual_pix_clk_khz
= 0;
389 uint32_t requested_clk_khz
= 0;
390 struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params
= {
392 enum bp_result bp_result
;
393 switch (pix_clk_params
->signal_type
) {
394 case SIGNAL_TYPE_HDMI_TYPE_A
: {
395 requested_clk_khz
= pix_clk_params
->requested_pix_clk
;
396 if (pix_clk_params
->pixel_encoding
!= PIXEL_ENCODING_YCBCR422
) {
397 switch (pix_clk_params
->color_depth
) {
398 case COLOR_DEPTH_101010
:
399 requested_clk_khz
= (requested_clk_khz
* 5) >> 2;
401 case COLOR_DEPTH_121212
:
402 requested_clk_khz
= (requested_clk_khz
* 6) >> 2;
404 case COLOR_DEPTH_161616
:
405 requested_clk_khz
= requested_clk_khz
* 2;
411 actual_pix_clk_khz
= requested_clk_khz
;
415 case SIGNAL_TYPE_DISPLAY_PORT
:
416 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
417 case SIGNAL_TYPE_EDP
:
418 requested_clk_khz
= pix_clk_params
->requested_sym_clk
;
419 actual_pix_clk_khz
= pix_clk_params
->requested_pix_clk
;
423 requested_clk_khz
= pix_clk_params
->requested_pix_clk
;
424 actual_pix_clk_khz
= pix_clk_params
->requested_pix_clk
;
428 bp_adjust_pixel_clock_params
.pixel_clock
= requested_clk_khz
;
429 bp_adjust_pixel_clock_params
.
430 encoder_object_id
= pix_clk_params
->encoder_object_id
;
431 bp_adjust_pixel_clock_params
.signal_type
= pix_clk_params
->signal_type
;
432 bp_adjust_pixel_clock_params
.
433 ss_enable
= pix_clk_params
->flags
.ENABLE_SS
;
434 bp_result
= clk_src
->bios
->funcs
->adjust_pixel_clock(
435 clk_src
->bios
, &bp_adjust_pixel_clock_params
);
436 if (bp_result
== BP_RESULT_OK
) {
437 pll_settings
->actual_pix_clk
= actual_pix_clk_khz
;
438 pll_settings
->adjusted_pix_clk
=
439 bp_adjust_pixel_clock_params
.adjusted_pixel_clock
;
440 pll_settings
->reference_divider
=
441 bp_adjust_pixel_clock_params
.reference_divider
;
442 pll_settings
->pix_clk_post_divider
=
443 bp_adjust_pixel_clock_params
.pixel_clock_post_divider
;
452 * Calculate PLL Dividers for given Clock Value.
453 * First will call VBIOS Adjust Exec table to check if requested Pixel clock
454 * will be Adjusted based on usage.
455 * Then it will calculate PLL Dividers for this Adjusted clock using preferred
456 * method (Maximum VCO frequency).
459 * Calculation error in units of 0.01%
462 static uint32_t dce110_get_pix_clk_dividers_helper (
463 struct dce110_clk_src
*clk_src
,
464 struct pll_settings
*pll_settings
,
465 struct pixel_clk_params
*pix_clk_params
)
468 uint32_t pll_calc_error
= MAX_PLL_CALC_ERROR
;
470 /* Check if reference clock is external (not pcie/xtalin)
472 * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB
473 * 04 - HSYNCA, 05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
474 REG_GET(PLL_CNTL
, PLL_REF_DIV_SRC
, &field
);
475 pll_settings
->use_external_clk
= (field
> 1);
477 /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
478 * (we do not care any more from SI for some older DP Sink which
479 * does not report SS support, no known issues) */
480 if ((pix_clk_params
->flags
.ENABLE_SS
) ||
481 (dc_is_dp_signal(pix_clk_params
->signal_type
))) {
483 const struct spread_spectrum_data
*ss_data
= get_ss_data_entry(
485 pix_clk_params
->signal_type
,
486 pll_settings
->adjusted_pix_clk
);
489 pll_settings
->ss_percentage
= ss_data
->percentage
;
492 /* Check VBIOS AdjustPixelClock Exec table */
493 if (!pll_adjust_pix_clk(clk_src
, pix_clk_params
, pll_settings
)) {
494 /* Should never happen, ASSERT and fill up values to be able
496 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_ERROR
,
497 "%s: Failed to adjust pixel clock!!", __func__
);
498 pll_settings
->actual_pix_clk
=
499 pix_clk_params
->requested_pix_clk
;
500 pll_settings
->adjusted_pix_clk
=
501 pix_clk_params
->requested_pix_clk
;
503 if (dc_is_dp_signal(pix_clk_params
->signal_type
))
504 pll_settings
->adjusted_pix_clk
= 100000;
507 /* Calculate Dividers */
508 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
)
509 /*Calculate Dividers by HDMI object, no SS case or SS case */
511 calculate_pixel_clock_pll_dividers(
512 &clk_src
->calc_pll_hdmi
,
515 /*Calculate Dividers by default object, no SS case or SS case */
517 calculate_pixel_clock_pll_dividers(
521 return pll_calc_error
;
524 static void dce112_get_pix_clk_dividers_helper (
525 struct dce110_clk_src
*clk_src
,
526 struct pll_settings
*pll_settings
,
527 struct pixel_clk_params
*pix_clk_params
)
529 uint32_t actualPixelClockInKHz
;
531 actualPixelClockInKHz
= pix_clk_params
->requested_pix_clk
;
532 /* Calculate Dividers */
533 if (pix_clk_params
->signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
534 switch (pix_clk_params
->color_depth
) {
535 case COLOR_DEPTH_101010
:
536 actualPixelClockInKHz
= (actualPixelClockInKHz
* 5) >> 2;
538 case COLOR_DEPTH_121212
:
539 actualPixelClockInKHz
= (actualPixelClockInKHz
* 6) >> 2;
541 case COLOR_DEPTH_161616
:
542 actualPixelClockInKHz
= actualPixelClockInKHz
* 2;
548 pll_settings
->actual_pix_clk
= actualPixelClockInKHz
;
549 pll_settings
->adjusted_pix_clk
= actualPixelClockInKHz
;
550 pll_settings
->calculated_pix_clk
= pix_clk_params
->requested_pix_clk
;
553 static uint32_t dce110_get_pix_clk_dividers(
554 struct clock_source
*cs
,
555 struct pixel_clk_params
*pix_clk_params
,
556 struct pll_settings
*pll_settings
)
558 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
559 uint32_t pll_calc_error
= MAX_PLL_CALC_ERROR
;
561 if (pix_clk_params
== NULL
|| pll_settings
== NULL
562 || pix_clk_params
->requested_pix_clk
== 0) {
563 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_ERROR
,
564 "%s: Invalid parameters!!\n", __func__
);
565 return pll_calc_error
;
568 memset(pll_settings
, 0, sizeof(*pll_settings
));
570 if (cs
->id
== CLOCK_SOURCE_ID_DP_DTO
||
571 cs
->id
== CLOCK_SOURCE_ID_EXTERNAL
) {
572 pll_settings
->adjusted_pix_clk
= clk_src
->ext_clk_khz
;
573 pll_settings
->calculated_pix_clk
= clk_src
->ext_clk_khz
;
574 pll_settings
->actual_pix_clk
=
575 pix_clk_params
->requested_pix_clk
;
579 switch (cs
->ctx
->dce_version
) {
580 case DCE_VERSION_8_0
:
581 case DCE_VERSION_8_1
:
582 case DCE_VERSION_8_3
:
583 case DCE_VERSION_10_0
:
584 case DCE_VERSION_11_0
:
586 dce110_get_pix_clk_dividers_helper(clk_src
,
587 pll_settings
, pix_clk_params
);
589 case DCE_VERSION_11_2
:
590 case DCE_VERSION_12_0
:
591 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
592 case DCN_VERSION_1_0
:
595 dce112_get_pix_clk_dividers_helper(clk_src
,
596 pll_settings
, pix_clk_params
);
602 return pll_calc_error
;
605 static uint32_t dce110_get_pll_pixel_rate_in_hz(
606 struct clock_source
*cs
,
607 struct pixel_clk_params
*pix_clk_params
,
608 struct pll_settings
*pll_settings
)
610 uint32_t inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
611 struct dc
*dc_core
= cs
->ctx
->dc
;
612 struct dc_state
*context
= dc_core
->current_state
;
613 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[inst
];
615 /* This function need separate to different DCE version, before separate, just use pixel clock */
616 return pipe_ctx
->stream
->phy_pix_clk
;
620 static uint32_t dce110_get_dp_pixel_rate_from_combo_phy_pll(
621 struct clock_source
*cs
,
622 struct pixel_clk_params
*pix_clk_params
,
623 struct pll_settings
*pll_settings
)
625 uint32_t inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
626 struct dc
*dc_core
= cs
->ctx
->dc
;
627 struct dc_state
*context
= dc_core
->current_state
;
628 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[inst
];
630 /* This function need separate to different DCE version, before separate, just use pixel clock */
631 return pipe_ctx
->stream
->phy_pix_clk
;
634 static uint32_t dce110_get_d_to_pixel_rate_in_hz(
635 struct clock_source
*cs
,
636 struct pixel_clk_params
*pix_clk_params
,
637 struct pll_settings
*pll_settings
)
639 uint32_t inst
= pix_clk_params
->controller_id
- CONTROLLER_ID_D0
;
640 struct dce110_clk_src
*clk_src
= TO_DCE110_CLK_SRC(cs
);
642 struct fixed31_32 pix_rate
;
644 REG_GET(PIXEL_RATE_CNTL
[inst
], DP_DTO0_ENABLE
, &dto_enabled
);
649 REG_GET(PHASE
[inst
], DP_DTO0_PHASE
, &phase
);
650 REG_GET(MODULO
[inst
], DP_DTO0_MODULO
, &modulo
);
656 pix_rate
= dal_fixed31_32_from_int(clk_src
->ref_freq_khz
);
657 pix_rate
= dal_fixed31_32_mul_int(pix_rate
, 1000);
658 pix_rate
= dal_fixed31_32_mul_int(pix_rate
, phase
);
659 pix_rate
= dal_fixed31_32_div_int(pix_rate
, modulo
);
661 return dal_fixed31_32_round(pix_rate
);
663 return dce110_get_dp_pixel_rate_from_combo_phy_pll(cs
, pix_clk_params
, pll_settings
);
667 static uint32_t dce110_get_pix_rate_in_hz(
668 struct clock_source
*cs
,
669 struct pixel_clk_params
*pix_clk_params
,
670 struct pll_settings
*pll_settings
)
672 uint32_t pix_rate
= 0;
673 switch (pix_clk_params
->signal_type
) {
674 case SIGNAL_TYPE_DISPLAY_PORT
:
675 case SIGNAL_TYPE_DISPLAY_PORT_MST
:
676 case SIGNAL_TYPE_EDP
:
677 case SIGNAL_TYPE_VIRTUAL
:
678 pix_rate
= dce110_get_d_to_pixel_rate_in_hz(cs
, pix_clk_params
, pll_settings
);
680 case SIGNAL_TYPE_HDMI_TYPE_A
:
682 pix_rate
= dce110_get_pll_pixel_rate_in_hz(cs
, pix_clk_params
, pll_settings
);
689 static bool disable_spread_spectrum(struct dce110_clk_src
*clk_src
)
691 enum bp_result result
;
692 struct bp_spread_spectrum_parameters bp_ss_params
= {0};
694 bp_ss_params
.pll_id
= clk_src
->base
.id
;
696 /*Call ASICControl to process ATOMBIOS Exec table*/
697 result
= clk_src
->bios
->funcs
->enable_spread_spectrum_on_ppll(
702 return result
== BP_RESULT_OK
;
705 static bool calculate_ss(
706 const struct pll_settings
*pll_settings
,
707 const struct spread_spectrum_data
*ss_data
,
708 struct delta_sigma_data
*ds_data
)
710 struct fixed32_32 fb_div
;
711 struct fixed32_32 ss_amount
;
712 struct fixed32_32 ss_nslip_amount
;
713 struct fixed32_32 ss_ds_frac_amount
;
714 struct fixed32_32 ss_step_size
;
715 struct fixed32_32 modulation_time
;
721 if (ss_data
->percentage
== 0)
723 if (pll_settings
== NULL
)
726 memset(ds_data
, 0, sizeof(struct delta_sigma_data
));
728 /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
729 /* 6 decimal point support in fractional feedback divider */
730 fb_div
= dal_fixed32_32_from_fraction(
731 pll_settings
->fract_feedback_divider
, 1000000);
732 fb_div
= dal_fixed32_32_add_int(fb_div
, pll_settings
->feedback_divider
);
734 ds_data
->ds_frac_amount
= 0;
735 /*spreadSpectrumPercentage is in the unit of .01%,
736 * so have to divided by 100 * 100*/
737 ss_amount
= dal_fixed32_32_mul(
738 fb_div
, dal_fixed32_32_from_fraction(ss_data
->percentage
,
739 100 * ss_data
->percentage_divider
));
740 ds_data
->feedback_amount
= dal_fixed32_32_floor(ss_amount
);
742 ss_nslip_amount
= dal_fixed32_32_sub(ss_amount
,
743 dal_fixed32_32_from_int(ds_data
->feedback_amount
));
744 ss_nslip_amount
= dal_fixed32_32_mul_int(ss_nslip_amount
, 10);
745 ds_data
->nfrac_amount
= dal_fixed32_32_floor(ss_nslip_amount
);
747 ss_ds_frac_amount
= dal_fixed32_32_sub(ss_nslip_amount
,
748 dal_fixed32_32_from_int(ds_data
->nfrac_amount
));
749 ss_ds_frac_amount
= dal_fixed32_32_mul_int(ss_ds_frac_amount
, 65536);
750 ds_data
->ds_frac_amount
= dal_fixed32_32_floor(ss_ds_frac_amount
);
752 /* compute SS_STEP_SIZE_DSFRAC */
753 modulation_time
= dal_fixed32_32_from_fraction(
754 pll_settings
->reference_freq
* 1000,
755 pll_settings
->reference_divider
* ss_data
->modulation_freq_hz
);
757 if (ss_data
->flags
.CENTER_SPREAD
)
758 modulation_time
= dal_fixed32_32_div_int(modulation_time
, 4);
760 modulation_time
= dal_fixed32_32_div_int(modulation_time
, 2);
762 ss_step_size
= dal_fixed32_32_div(ss_amount
, modulation_time
);
763 /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
764 ss_step_size
= dal_fixed32_32_mul_int(ss_step_size
, 65536 * 10);
765 ds_data
->ds_frac_size
= dal_fixed32_32_floor(ss_step_size
);
770 static bool enable_spread_spectrum(
771 struct dce110_clk_src
*clk_src
,
772 enum signal_type signal
, struct pll_settings
*pll_settings
)
774 struct bp_spread_spectrum_parameters bp_params
= {0};
775 struct delta_sigma_data d_s_data
;
776 const struct spread_spectrum_data
*ss_data
= NULL
;
778 ss_data
= get_ss_data_entry(
781 pll_settings
->calculated_pix_clk
);
783 /* Pixel clock PLL has been programmed to generate desired pixel clock,
784 * now enable SS on pixel clock */
785 /* TODO is it OK to return true not doing anything ??*/
786 if (ss_data
!= NULL
&& pll_settings
->ss_percentage
!= 0) {
787 if (calculate_ss(pll_settings
, ss_data
, &d_s_data
)) {
788 bp_params
.ds
.feedback_amount
=
789 d_s_data
.feedback_amount
;
790 bp_params
.ds
.nfrac_amount
=
791 d_s_data
.nfrac_amount
;
792 bp_params
.ds
.ds_frac_size
= d_s_data
.ds_frac_size
;
793 bp_params
.ds_frac_amount
=
794 d_s_data
.ds_frac_amount
;
795 bp_params
.flags
.DS_TYPE
= 1;
796 bp_params
.pll_id
= clk_src
->base
.id
;
797 bp_params
.percentage
= ss_data
->percentage
;
798 if (ss_data
->flags
.CENTER_SPREAD
)
799 bp_params
.flags
.CENTER_SPREAD
= 1;
800 if (ss_data
->flags
.EXTERNAL_SS
)
801 bp_params
.flags
.EXTERNAL_SS
= 1;
804 clk_src
->bios
->funcs
->
805 enable_spread_spectrum_on_ppll(
816 static void dce110_program_pixel_clk_resync(
817 struct dce110_clk_src
*clk_src
,
818 enum signal_type signal_type
,
819 enum dc_color_depth colordepth
)
821 REG_UPDATE(RESYNC_CNTL
,
822 DCCG_DEEP_COLOR_CNTL1
, 0);
824 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
825 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
826 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
827 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
829 if (signal_type
!= SIGNAL_TYPE_HDMI_TYPE_A
)
832 switch (colordepth
) {
833 case COLOR_DEPTH_888
:
834 REG_UPDATE(RESYNC_CNTL
,
835 DCCG_DEEP_COLOR_CNTL1
, 0);
837 case COLOR_DEPTH_101010
:
838 REG_UPDATE(RESYNC_CNTL
,
839 DCCG_DEEP_COLOR_CNTL1
, 1);
841 case COLOR_DEPTH_121212
:
842 REG_UPDATE(RESYNC_CNTL
,
843 DCCG_DEEP_COLOR_CNTL1
, 2);
845 case COLOR_DEPTH_161616
:
846 REG_UPDATE(RESYNC_CNTL
,
847 DCCG_DEEP_COLOR_CNTL1
, 3);
854 static void dce112_program_pixel_clk_resync(
855 struct dce110_clk_src
*clk_src
,
856 enum signal_type signal_type
,
857 enum dc_color_depth colordepth
,
858 bool enable_ycbcr420
)
860 uint32_t deep_color_cntl
= 0;
861 uint32_t double_rate_enable
= 0;
864 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
865 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
866 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
867 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
869 if (signal_type
== SIGNAL_TYPE_HDMI_TYPE_A
) {
870 double_rate_enable
= enable_ycbcr420
? 1 : 0;
872 switch (colordepth
) {
873 case COLOR_DEPTH_888
:
876 case COLOR_DEPTH_101010
:
879 case COLOR_DEPTH_121212
:
882 case COLOR_DEPTH_161616
:
890 if (clk_src
->cs_mask
->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE
)
891 REG_UPDATE_2(PIXCLK_RESYNC_CNTL
,
892 PHYPLLA_DCCG_DEEP_COLOR_CNTL
, deep_color_cntl
,
893 PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE
, double_rate_enable
);
895 REG_UPDATE(PIXCLK_RESYNC_CNTL
,
896 PHYPLLA_DCCG_DEEP_COLOR_CNTL
, deep_color_cntl
);
900 static bool dce110_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_DCN1_0)
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_kHz
= 600000;
912 /* DPREF clock from FPGA TODO: Does FPGA have this value? */
913 unsigned clock_kHz
= pll_settings
->actual_pix_clk
;
915 /* For faster simulation, if mode pixe clock less than 290MHz,
916 * pixel clock can be hard coded to 290Mhz. For 4K mode, pixel clock
917 * is greater than 500Mhz, need real pixel clock
918 * clock_kHz = 290000;
920 /* TODO: un-hardcode when we can set display clock properly*/
921 /*clock_kHz = pix_clk_params->requested_pix_clk;*/
924 /* Set DTO values: phase = target clock, modulo = reference clock */
925 REG_WRITE(PHASE
[inst
], clock_kHz
);
926 REG_WRITE(MODULO
[inst
], dp_dto_ref_kHz
);
929 REG_UPDATE(PIXEL_RATE_CNTL
[inst
], DP_DTO0_ENABLE
, 1);
934 * ATOMBIOS will enable by default SS on PLL for DP,
935 * do not disable it here
937 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
&&
938 !dc_is_dp_signal(pix_clk_params
->signal_type
) &&
939 clock_source
->ctx
->dce_version
<= DCE_VERSION_11_0
)
940 disable_spread_spectrum(clk_src
);
942 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
943 bp_pc_params
.controller_id
= pix_clk_params
->controller_id
;
944 bp_pc_params
.pll_id
= clock_source
->id
;
945 bp_pc_params
.target_pixel_clock
= pll_settings
->actual_pix_clk
;
946 bp_pc_params
.encoder_object_id
= pix_clk_params
->encoder_object_id
;
947 bp_pc_params
.signal_type
= pix_clk_params
->signal_type
;
949 switch (clock_source
->ctx
->dce_version
) {
950 case DCE_VERSION_8_0
:
951 case DCE_VERSION_8_1
:
952 case DCE_VERSION_8_3
:
953 case DCE_VERSION_10_0
:
954 case DCE_VERSION_11_0
:
955 bp_pc_params
.reference_divider
= pll_settings
->reference_divider
;
956 bp_pc_params
.feedback_divider
= pll_settings
->feedback_divider
;
957 bp_pc_params
.fractional_feedback_divider
=
958 pll_settings
->fract_feedback_divider
;
959 bp_pc_params
.pixel_clock_post_divider
=
960 pll_settings
->pix_clk_post_divider
;
961 bp_pc_params
.flags
.SET_EXTERNAL_REF_DIV_SRC
=
962 pll_settings
->use_external_clk
;
964 if (clk_src
->bios
->funcs
->set_pixel_clock(
965 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
968 * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
969 * based on HW display PLL team, SS control settings should be programmed
970 * during PLL Reset, but they do not have effect
971 * until SS_EN is asserted.*/
972 if (clock_source
->id
!= CLOCK_SOURCE_ID_EXTERNAL
973 && !dc_is_dp_signal(pix_clk_params
->signal_type
)) {
975 if (pix_clk_params
->flags
.ENABLE_SS
)
976 if (!enable_spread_spectrum(clk_src
,
977 pix_clk_params
->signal_type
,
981 /* Resync deep color DTO */
982 dce110_program_pixel_clk_resync(clk_src
,
983 pix_clk_params
->signal_type
,
984 pix_clk_params
->color_depth
);
988 case DCE_VERSION_11_2
:
989 case DCE_VERSION_12_0
:
990 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
991 case DCN_VERSION_1_0
:
994 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
) {
995 bp_pc_params
.flags
.SET_GENLOCK_REF_DIV_SRC
=
996 pll_settings
->use_external_clk
;
997 bp_pc_params
.flags
.SET_XTALIN_REF_SRC
=
998 !pll_settings
->use_external_clk
;
999 if (pix_clk_params
->flags
.SUPPORT_YCBCR420
) {
1000 bp_pc_params
.flags
.SUPPORT_YUV_420
= 1;
1003 if (clk_src
->bios
->funcs
->set_pixel_clock(
1004 clk_src
->bios
, &bp_pc_params
) != BP_RESULT_OK
)
1006 /* Resync deep color DTO */
1007 if (clock_source
->id
!= CLOCK_SOURCE_ID_DP_DTO
)
1008 dce112_program_pixel_clk_resync(clk_src
,
1009 pix_clk_params
->signal_type
,
1010 pix_clk_params
->color_depth
,
1011 pix_clk_params
->flags
.SUPPORT_YCBCR420
);
1020 static bool dce110_clock_source_power_down(
1021 struct clock_source
*clk_src
)
1023 struct dce110_clk_src
*dce110_clk_src
= TO_DCE110_CLK_SRC(clk_src
);
1024 enum bp_result bp_result
;
1025 struct bp_pixel_clock_parameters bp_pixel_clock_params
= {0};
1027 if (clk_src
->dp_clk_src
)
1030 /* If Pixel Clock is 0 it means Power Down Pll*/
1031 bp_pixel_clock_params
.controller_id
= CONTROLLER_ID_UNDEFINED
;
1032 bp_pixel_clock_params
.pll_id
= clk_src
->id
;
1033 bp_pixel_clock_params
.flags
.FORCE_PROGRAMMING_OF_PLL
= 1;
1035 /*Call ASICControl to process ATOMBIOS Exec table*/
1036 bp_result
= dce110_clk_src
->bios
->funcs
->set_pixel_clock(
1037 dce110_clk_src
->bios
,
1038 &bp_pixel_clock_params
);
1040 return bp_result
== BP_RESULT_OK
;
1043 /*****************************************/
1045 /*****************************************/
1046 static const struct clock_source_funcs dce110_clk_src_funcs
= {
1047 .cs_power_down
= dce110_clock_source_power_down
,
1048 .program_pix_clk
= dce110_program_pix_clk
,
1049 .get_pix_clk_dividers
= dce110_get_pix_clk_dividers
,
1050 .get_pix_rate_in_hz
= dce110_get_pix_rate_in_hz
1053 static void get_ss_info_from_atombios(
1054 struct dce110_clk_src
*clk_src
,
1055 enum as_signal_type as_signal
,
1056 struct spread_spectrum_data
*spread_spectrum_data
[],
1057 uint32_t *ss_entries_num
)
1059 enum bp_result bp_result
= BP_RESULT_FAILURE
;
1060 struct spread_spectrum_info
*ss_info
;
1061 struct spread_spectrum_data
*ss_data
;
1062 struct spread_spectrum_info
*ss_info_cur
;
1063 struct spread_spectrum_data
*ss_data_cur
;
1066 if (ss_entries_num
== NULL
) {
1067 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_SYNC
,
1068 "Invalid entry !!!\n");
1071 if (spread_spectrum_data
== NULL
) {
1072 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_SYNC
,
1073 "Invalid array pointer!!!\n");
1077 spread_spectrum_data
[0] = NULL
;
1078 *ss_entries_num
= 0;
1080 *ss_entries_num
= clk_src
->bios
->funcs
->get_ss_entry_number(
1084 if (*ss_entries_num
== 0)
1087 ss_info
= kzalloc(sizeof(struct spread_spectrum_info
) * (*ss_entries_num
),
1089 ss_info_cur
= ss_info
;
1090 if (ss_info
== NULL
)
1093 ss_data
= kzalloc(sizeof(struct spread_spectrum_data
) * (*ss_entries_num
),
1095 if (ss_data
== NULL
)
1098 for (i
= 0, ss_info_cur
= ss_info
;
1099 i
< (*ss_entries_num
);
1100 ++i
, ++ss_info_cur
) {
1102 bp_result
= clk_src
->bios
->funcs
->get_spread_spectrum_info(
1108 if (bp_result
!= BP_RESULT_OK
)
1112 for (i
= 0, ss_info_cur
= ss_info
, ss_data_cur
= ss_data
;
1113 i
< (*ss_entries_num
);
1114 ++i
, ++ss_info_cur
, ++ss_data_cur
) {
1116 if (ss_info_cur
->type
.STEP_AND_DELAY_INFO
!= false) {
1117 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_SYNC
,
1118 "Invalid ATOMBIOS SS Table!!!\n");
1122 /* for HDMI check SS percentage,
1123 * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1124 if (as_signal
== AS_SIGNAL_TYPE_HDMI
1125 && ss_info_cur
->spread_spectrum_percentage
> 6){
1126 /* invalid input, do nothing */
1127 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_SYNC
,
1128 "Invalid SS percentage ");
1129 dm_logger_write(clk_src
->base
.ctx
->logger
, LOG_SYNC
,
1130 "for HDMI in ATOMBIOS info Table!!!\n");
1133 if (ss_info_cur
->spread_percentage_divider
== 1000) {
1134 /* Keep previous precision from ATOMBIOS for these
1135 * in case new precision set by ATOMBIOS for these
1136 * (otherwise all code in DCE specific classes
1137 * for all previous ASICs would need
1138 * to be updated for SS calculations,
1139 * Audio SS compensation and DP DTO SS compensation
1140 * which assumes fixed SS percentage Divider = 100)*/
1141 ss_info_cur
->spread_spectrum_percentage
/= 10;
1142 ss_info_cur
->spread_percentage_divider
= 100;
1145 ss_data_cur
->freq_range_khz
= ss_info_cur
->target_clock_range
;
1146 ss_data_cur
->percentage
=
1147 ss_info_cur
->spread_spectrum_percentage
;
1148 ss_data_cur
->percentage_divider
=
1149 ss_info_cur
->spread_percentage_divider
;
1150 ss_data_cur
->modulation_freq_hz
=
1151 ss_info_cur
->spread_spectrum_range
;
1153 if (ss_info_cur
->type
.CENTER_MODE
)
1154 ss_data_cur
->flags
.CENTER_SPREAD
= 1;
1156 if (ss_info_cur
->type
.EXTERNAL
)
1157 ss_data_cur
->flags
.EXTERNAL_SS
= 1;
1161 *spread_spectrum_data
= ss_data
;
1167 *ss_entries_num
= 0;
1172 static void ss_info_from_atombios_create(
1173 struct dce110_clk_src
*clk_src
)
1175 get_ss_info_from_atombios(
1177 AS_SIGNAL_TYPE_DISPLAY_PORT
,
1178 &clk_src
->dp_ss_params
,
1179 &clk_src
->dp_ss_params_cnt
);
1180 get_ss_info_from_atombios(
1182 AS_SIGNAL_TYPE_HDMI
,
1183 &clk_src
->hdmi_ss_params
,
1184 &clk_src
->hdmi_ss_params_cnt
);
1185 get_ss_info_from_atombios(
1188 &clk_src
->dvi_ss_params
,
1189 &clk_src
->dvi_ss_params_cnt
);
1192 static bool calc_pll_max_vco_construct(
1193 struct calc_pll_clock_source
*calc_pll_cs
,
1194 struct calc_pll_clock_source_init_data
*init_data
)
1197 struct dc_firmware_info fw_info
= { { 0 } };
1198 if (calc_pll_cs
== NULL
||
1199 init_data
== NULL
||
1200 init_data
->bp
== NULL
)
1203 if (init_data
->bp
->funcs
->get_firmware_info(
1205 &fw_info
) != BP_RESULT_OK
)
1208 calc_pll_cs
->ctx
= init_data
->ctx
;
1209 calc_pll_cs
->ref_freq_khz
= fw_info
.pll_info
.crystal_frequency
;
1210 calc_pll_cs
->min_vco_khz
=
1211 fw_info
.pll_info
.min_output_pxl_clk_pll_frequency
;
1212 calc_pll_cs
->max_vco_khz
=
1213 fw_info
.pll_info
.max_output_pxl_clk_pll_frequency
;
1215 if (init_data
->max_override_input_pxl_clk_pll_freq_khz
!= 0)
1216 calc_pll_cs
->max_pll_input_freq_khz
=
1217 init_data
->max_override_input_pxl_clk_pll_freq_khz
;
1219 calc_pll_cs
->max_pll_input_freq_khz
=
1220 fw_info
.pll_info
.max_input_pxl_clk_pll_frequency
;
1222 if (init_data
->min_override_input_pxl_clk_pll_freq_khz
!= 0)
1223 calc_pll_cs
->min_pll_input_freq_khz
=
1224 init_data
->min_override_input_pxl_clk_pll_freq_khz
;
1226 calc_pll_cs
->min_pll_input_freq_khz
=
1227 fw_info
.pll_info
.min_input_pxl_clk_pll_frequency
;
1229 calc_pll_cs
->min_pix_clock_pll_post_divider
=
1230 init_data
->min_pix_clk_pll_post_divider
;
1231 calc_pll_cs
->max_pix_clock_pll_post_divider
=
1232 init_data
->max_pix_clk_pll_post_divider
;
1233 calc_pll_cs
->min_pll_ref_divider
=
1234 init_data
->min_pll_ref_divider
;
1235 calc_pll_cs
->max_pll_ref_divider
=
1236 init_data
->max_pll_ref_divider
;
1238 if (init_data
->num_fract_fb_divider_decimal_point
== 0 ||
1239 init_data
->num_fract_fb_divider_decimal_point_precision
>
1240 init_data
->num_fract_fb_divider_decimal_point
) {
1241 dm_logger_write(calc_pll_cs
->ctx
->logger
, LOG_ERROR
,
1242 "The dec point num or precision is incorrect!");
1245 if (init_data
->num_fract_fb_divider_decimal_point_precision
== 0) {
1246 dm_logger_write(calc_pll_cs
->ctx
->logger
, LOG_ERROR
,
1247 "Incorrect fract feedback divider precision num!");
1251 calc_pll_cs
->fract_fb_divider_decimal_points_num
=
1252 init_data
->num_fract_fb_divider_decimal_point
;
1253 calc_pll_cs
->fract_fb_divider_precision
=
1254 init_data
->num_fract_fb_divider_decimal_point_precision
;
1255 calc_pll_cs
->fract_fb_divider_factor
= 1;
1256 for (i
= 0; i
< calc_pll_cs
->fract_fb_divider_decimal_points_num
; ++i
)
1257 calc_pll_cs
->fract_fb_divider_factor
*= 10;
1259 calc_pll_cs
->fract_fb_divider_precision_factor
= 1;
1262 i
< (calc_pll_cs
->fract_fb_divider_decimal_points_num
-
1263 calc_pll_cs
->fract_fb_divider_precision
);
1265 calc_pll_cs
->fract_fb_divider_precision_factor
*= 10;
1270 bool dce110_clk_src_construct(
1271 struct dce110_clk_src
*clk_src
,
1272 struct dc_context
*ctx
,
1273 struct dc_bios
*bios
,
1274 enum clock_source_id id
,
1275 const struct dce110_clk_src_regs
*regs
,
1276 const struct dce110_clk_src_shift
*cs_shift
,
1277 const struct dce110_clk_src_mask
*cs_mask
)
1279 struct dc_firmware_info fw_info
= { { 0 } };
1280 struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi
;
1281 struct calc_pll_clock_source_init_data calc_pll_cs_init_data
;
1283 clk_src
->base
.ctx
= ctx
;
1284 clk_src
->bios
= bios
;
1285 clk_src
->base
.id
= id
;
1286 clk_src
->base
.funcs
= &dce110_clk_src_funcs
;
1288 clk_src
->regs
= regs
;
1289 clk_src
->cs_shift
= cs_shift
;
1290 clk_src
->cs_mask
= cs_mask
;
1292 if (clk_src
->bios
->funcs
->get_firmware_info(
1293 clk_src
->bios
, &fw_info
) != BP_RESULT_OK
) {
1294 ASSERT_CRITICAL(false);
1295 goto unexpected_failure
;
1298 clk_src
->ext_clk_khz
=
1299 fw_info
.external_clock_source_frequency_for_dp
;
1301 switch (clk_src
->base
.ctx
->dce_version
) {
1302 case DCE_VERSION_8_0
:
1303 case DCE_VERSION_8_1
:
1304 case DCE_VERSION_8_3
:
1305 case DCE_VERSION_10_0
:
1306 case DCE_VERSION_11_0
:
1308 /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1309 calc_pll_cs_init_data
.bp
= bios
;
1310 calc_pll_cs_init_data
.min_pix_clk_pll_post_divider
= 1;
1311 calc_pll_cs_init_data
.max_pix_clk_pll_post_divider
=
1312 clk_src
->cs_mask
->PLL_POST_DIV_PIXCLK
;
1313 calc_pll_cs_init_data
.min_pll_ref_divider
= 1;
1314 calc_pll_cs_init_data
.max_pll_ref_divider
= clk_src
->cs_mask
->PLL_REF_DIV
;
1315 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1316 calc_pll_cs_init_data
.min_override_input_pxl_clk_pll_freq_khz
= 0;
1317 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1318 calc_pll_cs_init_data
.max_override_input_pxl_clk_pll_freq_khz
= 0;
1319 /*numberOfFractFBDividerDecimalPoints*/
1320 calc_pll_cs_init_data
.num_fract_fb_divider_decimal_point
=
1321 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1322 /*number of decimal point to round off for fractional feedback divider value*/
1323 calc_pll_cs_init_data
.num_fract_fb_divider_decimal_point_precision
=
1324 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1325 calc_pll_cs_init_data
.ctx
= ctx
;
1327 /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1328 calc_pll_cs_init_data_hdmi
.bp
= bios
;
1329 calc_pll_cs_init_data_hdmi
.min_pix_clk_pll_post_divider
= 1;
1330 calc_pll_cs_init_data_hdmi
.max_pix_clk_pll_post_divider
=
1331 clk_src
->cs_mask
->PLL_POST_DIV_PIXCLK
;
1332 calc_pll_cs_init_data_hdmi
.min_pll_ref_divider
= 1;
1333 calc_pll_cs_init_data_hdmi
.max_pll_ref_divider
= clk_src
->cs_mask
->PLL_REF_DIV
;
1334 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1335 calc_pll_cs_init_data_hdmi
.min_override_input_pxl_clk_pll_freq_khz
= 13500;
1336 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1337 calc_pll_cs_init_data_hdmi
.max_override_input_pxl_clk_pll_freq_khz
= 27000;
1338 /*numberOfFractFBDividerDecimalPoints*/
1339 calc_pll_cs_init_data_hdmi
.num_fract_fb_divider_decimal_point
=
1340 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1341 /*number of decimal point to round off for fractional feedback divider value*/
1342 calc_pll_cs_init_data_hdmi
.num_fract_fb_divider_decimal_point_precision
=
1343 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM
;
1344 calc_pll_cs_init_data_hdmi
.ctx
= ctx
;
1346 clk_src
->ref_freq_khz
= fw_info
.pll_info
.crystal_frequency
;
1348 if (clk_src
->base
.id
== CLOCK_SOURCE_ID_EXTERNAL
)
1351 /* PLL only from here on */
1352 ss_info_from_atombios_create(clk_src
);
1354 if (!calc_pll_max_vco_construct(
1356 &calc_pll_cs_init_data
)) {
1357 ASSERT_CRITICAL(false);
1358 goto unexpected_failure
;
1362 calc_pll_cs_init_data_hdmi
.
1363 min_override_input_pxl_clk_pll_freq_khz
= clk_src
->ref_freq_khz
/2;
1364 calc_pll_cs_init_data_hdmi
.
1365 max_override_input_pxl_clk_pll_freq_khz
= clk_src
->ref_freq_khz
;
1368 if (!calc_pll_max_vco_construct(
1369 &clk_src
->calc_pll_hdmi
, &calc_pll_cs_init_data_hdmi
)) {
1370 ASSERT_CRITICAL(false);
1371 goto unexpected_failure
;