xref: /dragonfly/sys/dev/drm/amd/display/dc/dce/dce_clock_source.c (revision b843c749addef9340ee7d4e250b09fdd492602a1)
1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "dm_services.h"
27 
28 
29 #include "dc_types.h"
30 #include "core_types.h"
31 
32 #include "include/grph_object_id.h"
33 #include "include/logger_interface.h"
34 
35 #include "dce_clock_source.h"
36 
37 #include "reg_helper.h"
38 
39 #define REG(reg)\
40           (clk_src->regs->reg)
41 
42 #define CTX \
43           clk_src->base.ctx
44 
45 #define DC_LOGGER_INIT()
46 
47 #undef FN
48 #define FN(reg_name, field_name) \
49           clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
50 
51 #define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
52 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
53 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF
54 
get_ss_data_entry(struct dce110_clk_src * clk_src,enum signal_type signal,uint32_t pix_clk_khz)55 static const struct spread_spectrum_data *get_ss_data_entry(
56                     struct dce110_clk_src *clk_src,
57                     enum signal_type signal,
58                     uint32_t pix_clk_khz)
59 {
60 
61           uint32_t entrys_num;
62           uint32_t i;
63           struct spread_spectrum_data *ss_parm = NULL;
64           struct spread_spectrum_data *ret = NULL;
65 
66           switch (signal) {
67           case SIGNAL_TYPE_DVI_SINGLE_LINK:
68           case SIGNAL_TYPE_DVI_DUAL_LINK:
69                     ss_parm = clk_src->dvi_ss_params;
70                     entrys_num = clk_src->dvi_ss_params_cnt;
71                     break;
72 
73           case SIGNAL_TYPE_HDMI_TYPE_A:
74                     ss_parm = clk_src->hdmi_ss_params;
75                     entrys_num = clk_src->hdmi_ss_params_cnt;
76                     break;
77 
78           case SIGNAL_TYPE_DISPLAY_PORT:
79           case SIGNAL_TYPE_DISPLAY_PORT_MST:
80           case SIGNAL_TYPE_EDP:
81           case SIGNAL_TYPE_VIRTUAL:
82                     ss_parm = clk_src->dp_ss_params;
83                     entrys_num = clk_src->dp_ss_params_cnt;
84                     break;
85 
86           default:
87                     ss_parm = NULL;
88                     entrys_num = 0;
89                     break;
90           }
91 
92           if (ss_parm == NULL)
93                     return ret;
94 
95           for (i = 0; i < entrys_num; ++i, ++ss_parm) {
96                     if (ss_parm->freq_range_khz >= pix_clk_khz) {
97                               ret = ss_parm;
98                               break;
99                     }
100           }
101 
102           return ret;
103 }
104 
105 /**
106 * Function: calculate_fb_and_fractional_fb_divider
107 *
108 * * DESCRIPTION: Calculates feedback and fractional feedback dividers values
109 *
110 *PARAMETERS:
111 * targetPixelClock             Desired frequency in 10 KHz
112 * ref_divider                  Reference divider (already known)
113 * postDivider                  Post Divider (already known)
114 * feedback_divider_param       Pointer where to store
115 *                                                 calculated feedback divider value
116 * fract_feedback_divider_param Pointer where to store
117 *                                                 calculated fract feedback divider value
118 *
119 *RETURNS:
120 * It fills the locations pointed by feedback_divider_param
121 *                                                 and fract_feedback_divider_param
122 * It returns        - true if feedback divider not 0
123 *                   - false should never happen)
124 */
calculate_fb_and_fractional_fb_divider(struct calc_pll_clock_source * calc_pll_cs,uint32_t target_pix_clk_khz,uint32_t ref_divider,uint32_t post_divider,uint32_t * feedback_divider_param,uint32_t * fract_feedback_divider_param)125 static bool calculate_fb_and_fractional_fb_divider(
126                     struct calc_pll_clock_source *calc_pll_cs,
127                     uint32_t target_pix_clk_khz,
128                     uint32_t ref_divider,
129                     uint32_t post_divider,
130                     uint32_t *feedback_divider_param,
131                     uint32_t *fract_feedback_divider_param)
132 {
133           uint64_t feedback_divider;
134 
135           feedback_divider =
136                     (uint64_t)target_pix_clk_khz * ref_divider * post_divider;
137           feedback_divider *= 10;
138           /* additional factor, since we divide by 10 afterwards */
139           feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
140           feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz);
141 
142 /*Round to the number of precision
143  * The following code replace the old code (ullfeedbackDivider + 5)/10
144  * for example if the difference between the number
145  * of fractional feedback decimal point and the fractional FB Divider precision
146  * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
147 
148           feedback_divider += 5ULL *
149                                   calc_pll_cs->fract_fb_divider_precision_factor;
150           feedback_divider =
151                     div_u64(feedback_divider,
152                               calc_pll_cs->fract_fb_divider_precision_factor * 10);
153           feedback_divider *= (uint64_t)
154                               (calc_pll_cs->fract_fb_divider_precision_factor);
155 
156           *feedback_divider_param =
157                     div_u64_rem(
158                               feedback_divider,
159                               calc_pll_cs->fract_fb_divider_factor,
160                               fract_feedback_divider_param);
161 
162           if (*feedback_divider_param != 0)
163                     return true;
164           return false;
165 }
166 
167 /**
168 *calc_fb_divider_checking_tolerance
169 *
170 *DESCRIPTION: Calculates Feedback and Fractional Feedback divider values
171 *                   for passed Reference and Post divider, checking for tolerance.
172 *PARAMETERS:
173 * pll_settings                Pointer to structure
174 * ref_divider                 Reference divider (already known)
175 * postDivider                 Post Divider (already known)
176 * tolerance                   Tolerance for Calculated Pixel Clock to be within
177 *
178 *RETURNS:
179 * It fills the PLLSettings structure with PLL Dividers values
180 * if calculated values are within required tolerance
181 * It returns        - true if eror is within tolerance
182 *                   - false if eror is not within tolerance
183 */
calc_fb_divider_checking_tolerance(struct calc_pll_clock_source * calc_pll_cs,struct pll_settings * pll_settings,uint32_t ref_divider,uint32_t post_divider,uint32_t tolerance)184 static bool calc_fb_divider_checking_tolerance(
185                     struct calc_pll_clock_source *calc_pll_cs,
186                     struct pll_settings *pll_settings,
187                     uint32_t ref_divider,
188                     uint32_t post_divider,
189                     uint32_t tolerance)
190 {
191           uint32_t feedback_divider;
192           uint32_t fract_feedback_divider;
193           uint32_t actual_calculated_clock_khz;
194           uint32_t abs_err;
195           uint64_t actual_calc_clk_khz;
196 
197           calculate_fb_and_fractional_fb_divider(
198                               calc_pll_cs,
199                               pll_settings->adjusted_pix_clk,
200                               ref_divider,
201                               post_divider,
202                               &feedback_divider,
203                               &fract_feedback_divider);
204 
205           /*Actual calculated value*/
206           actual_calc_clk_khz = (uint64_t)feedback_divider *
207                                                   calc_pll_cs->fract_fb_divider_factor +
208                                                                       fract_feedback_divider;
209           actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz;
210           actual_calc_clk_khz =
211                     div_u64(actual_calc_clk_khz,
212                               ref_divider * post_divider *
213                                         calc_pll_cs->fract_fb_divider_factor);
214 
215           actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz);
216 
217           abs_err = (actual_calculated_clock_khz >
218                                                   pll_settings->adjusted_pix_clk)
219                               ? actual_calculated_clock_khz -
220                                                   pll_settings->adjusted_pix_clk
221                               : pll_settings->adjusted_pix_clk -
222                                                             actual_calculated_clock_khz;
223 
224           if (abs_err <= tolerance) {
225                     /*found good values*/
226                     pll_settings->reference_freq = calc_pll_cs->ref_freq_khz;
227                     pll_settings->reference_divider = ref_divider;
228                     pll_settings->feedback_divider = feedback_divider;
229                     pll_settings->fract_feedback_divider = fract_feedback_divider;
230                     pll_settings->pix_clk_post_divider = post_divider;
231                     pll_settings->calculated_pix_clk =
232                               actual_calculated_clock_khz;
233                     pll_settings->vco_freq =
234                               actual_calculated_clock_khz * post_divider;
235                     return true;
236           }
237           return false;
238 }
239 
calc_pll_dividers_in_range(struct calc_pll_clock_source * calc_pll_cs,struct pll_settings * pll_settings,uint32_t min_ref_divider,uint32_t max_ref_divider,uint32_t min_post_divider,uint32_t max_post_divider,uint32_t err_tolerance)240 static bool calc_pll_dividers_in_range(
241                     struct calc_pll_clock_source *calc_pll_cs,
242                     struct pll_settings *pll_settings,
243                     uint32_t min_ref_divider,
244                     uint32_t max_ref_divider,
245                     uint32_t min_post_divider,
246                     uint32_t max_post_divider,
247                     uint32_t err_tolerance)
248 {
249           uint32_t ref_divider;
250           uint32_t post_divider;
251           uint32_t tolerance;
252 
253 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
254  * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
255           tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) /
256                                                                                           10000;
257           if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
258                     tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
259 
260           for (
261                               post_divider = max_post_divider;
262                               post_divider >= min_post_divider;
263                               --post_divider) {
264                     for (
265                                         ref_divider = min_ref_divider;
266                                         ref_divider <= max_ref_divider;
267                                         ++ref_divider) {
268                               if (calc_fb_divider_checking_tolerance(
269                                                   calc_pll_cs,
270                                                   pll_settings,
271                                                   ref_divider,
272                                                   post_divider,
273                                                   tolerance)) {
274                                         return true;
275                               }
276                     }
277           }
278 
279           return false;
280 }
281 
calculate_pixel_clock_pll_dividers(struct calc_pll_clock_source * calc_pll_cs,struct pll_settings * pll_settings)282 static uint32_t calculate_pixel_clock_pll_dividers(
283                     struct calc_pll_clock_source *calc_pll_cs,
284                     struct pll_settings *pll_settings)
285 {
286           uint32_t err_tolerance;
287           uint32_t min_post_divider;
288           uint32_t max_post_divider;
289           uint32_t min_ref_divider;
290           uint32_t max_ref_divider;
291 
292           if (pll_settings->adjusted_pix_clk == 0) {
293                     DC_LOG_ERROR(
294                               "%s Bad requested pixel clock", __func__);
295                     return MAX_PLL_CALC_ERROR;
296           }
297 
298 /* 1) Find Post divider ranges */
299           if (pll_settings->pix_clk_post_divider) {
300                     min_post_divider = pll_settings->pix_clk_post_divider;
301                     max_post_divider = pll_settings->pix_clk_post_divider;
302           } else {
303                     min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
304                     if (min_post_divider * pll_settings->adjusted_pix_clk <
305                                                             calc_pll_cs->min_vco_khz) {
306                               min_post_divider = calc_pll_cs->min_vco_khz /
307                                                   pll_settings->adjusted_pix_clk;
308                               if ((min_post_divider *
309                                                   pll_settings->adjusted_pix_clk) <
310                                                             calc_pll_cs->min_vco_khz)
311                                         min_post_divider++;
312                     }
313 
314                     max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
315                     if (max_post_divider * pll_settings->adjusted_pix_clk
316                                         > calc_pll_cs->max_vco_khz)
317                               max_post_divider = calc_pll_cs->max_vco_khz /
318                                                   pll_settings->adjusted_pix_clk;
319           }
320 
321 /* 2) Find Reference divider ranges
322  * When SS is enabled, or for Display Port even without SS,
323  * pll_settings->referenceDivider is not zero.
324  * So calculate PPLL FB and fractional FB divider
325  * using the passed reference divider*/
326 
327           if (pll_settings->reference_divider) {
328                     min_ref_divider = pll_settings->reference_divider;
329                     max_ref_divider = pll_settings->reference_divider;
330           } else {
331                     min_ref_divider = ((calc_pll_cs->ref_freq_khz
332                                         / calc_pll_cs->max_pll_input_freq_khz)
333                                         > calc_pll_cs->min_pll_ref_divider)
334                               ? calc_pll_cs->ref_freq_khz
335                                                   / calc_pll_cs->max_pll_input_freq_khz
336                               : calc_pll_cs->min_pll_ref_divider;
337 
338                     max_ref_divider = ((calc_pll_cs->ref_freq_khz
339                                         / calc_pll_cs->min_pll_input_freq_khz)
340                                         < calc_pll_cs->max_pll_ref_divider)
341                               ? calc_pll_cs->ref_freq_khz /
342                                                   calc_pll_cs->min_pll_input_freq_khz
343                               : calc_pll_cs->max_pll_ref_divider;
344           }
345 
346 /* If some parameters are invalid we could have scenario when  "min">"max"
347  * which produced endless loop later.
348  * We should investigate why we get the wrong parameters.
349  * But to follow the similar logic when "adjustedPixelClock" is set to be 0
350  * it is better to return here than cause system hang/watchdog timeout later.
351  *  ## SVS Wed 15 Jul 2009 */
352 
353           if (min_post_divider > max_post_divider) {
354                     DC_LOG_ERROR(
355                               "%s Post divider range is invalid", __func__);
356                     return MAX_PLL_CALC_ERROR;
357           }
358 
359           if (min_ref_divider > max_ref_divider) {
360                     DC_LOG_ERROR(
361                               "%s Reference divider range is invalid", __func__);
362                     return MAX_PLL_CALC_ERROR;
363           }
364 
365 /* 3) Try to find PLL dividers given ranges
366  * starting with minimal error tolerance.
367  * Increase error tolerance until PLL dividers found*/
368           err_tolerance = MAX_PLL_CALC_ERROR;
369 
370           while (!calc_pll_dividers_in_range(
371                               calc_pll_cs,
372                               pll_settings,
373                               min_ref_divider,
374                               max_ref_divider,
375                               min_post_divider,
376                               max_post_divider,
377                               err_tolerance))
378                     err_tolerance += (err_tolerance > 10)
379                                         ? (err_tolerance / 10)
380                                         : 1;
381 
382           return err_tolerance;
383 }
384 
pll_adjust_pix_clk(struct dce110_clk_src * clk_src,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)385 static bool pll_adjust_pix_clk(
386                     struct dce110_clk_src *clk_src,
387                     struct pixel_clk_params *pix_clk_params,
388                     struct pll_settings *pll_settings)
389 {
390           uint32_t actual_pix_clk_khz = 0;
391           uint32_t requested_clk_khz = 0;
392           struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
393                                                                       0 };
394           enum bp_result bp_result;
395           switch (pix_clk_params->signal_type) {
396           case SIGNAL_TYPE_HDMI_TYPE_A: {
397                     requested_clk_khz = pix_clk_params->requested_pix_clk;
398                     if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
399                               switch (pix_clk_params->color_depth) {
400                               case COLOR_DEPTH_101010:
401                                         requested_clk_khz = (requested_clk_khz * 5) >> 2;
402                                         break; /* x1.25*/
403                               case COLOR_DEPTH_121212:
404                                         requested_clk_khz = (requested_clk_khz * 6) >> 2;
405                                         break; /* x1.5*/
406                               case COLOR_DEPTH_161616:
407                                         requested_clk_khz = requested_clk_khz * 2;
408                                         break; /* x2.0*/
409                               default:
410                                         break;
411                               }
412                     }
413                     actual_pix_clk_khz = requested_clk_khz;
414           }
415                     break;
416 
417           case SIGNAL_TYPE_DISPLAY_PORT:
418           case SIGNAL_TYPE_DISPLAY_PORT_MST:
419           case SIGNAL_TYPE_EDP:
420                     requested_clk_khz = pix_clk_params->requested_sym_clk;
421                     actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
422                     break;
423 
424           default:
425                     requested_clk_khz = pix_clk_params->requested_pix_clk;
426                     actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
427                     break;
428           }
429 
430           bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz;
431           bp_adjust_pixel_clock_params.
432                     encoder_object_id = pix_clk_params->encoder_object_id;
433           bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
434           bp_adjust_pixel_clock_params.
435                     ss_enable = pix_clk_params->flags.ENABLE_SS;
436           bp_result = clk_src->bios->funcs->adjust_pixel_clock(
437                               clk_src->bios, &bp_adjust_pixel_clock_params);
438           if (bp_result == BP_RESULT_OK) {
439                     pll_settings->actual_pix_clk = actual_pix_clk_khz;
440                     pll_settings->adjusted_pix_clk =
441                               bp_adjust_pixel_clock_params.adjusted_pixel_clock;
442                     pll_settings->reference_divider =
443                               bp_adjust_pixel_clock_params.reference_divider;
444                     pll_settings->pix_clk_post_divider =
445                               bp_adjust_pixel_clock_params.pixel_clock_post_divider;
446 
447                     return true;
448           }
449 
450           return false;
451 }
452 
453 /**
454  * Calculate PLL Dividers for given Clock Value.
455  * First will call VBIOS Adjust Exec table to check if requested Pixel clock
456  * will be Adjusted based on usage.
457  * Then it will calculate PLL Dividers for this Adjusted clock using preferred
458  * method (Maximum VCO frequency).
459  *
460  * \return
461  *     Calculation error in units of 0.01%
462  */
463 
dce110_get_pix_clk_dividers_helper(struct dce110_clk_src * clk_src,struct pll_settings * pll_settings,struct pixel_clk_params * pix_clk_params)464 static uint32_t dce110_get_pix_clk_dividers_helper (
465                     struct dce110_clk_src *clk_src,
466                     struct pll_settings *pll_settings,
467                     struct pixel_clk_params *pix_clk_params)
468 {
469           uint32_t field = 0;
470           uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
471           DC_LOGGER_INIT();
472           /* Check if reference clock is external (not pcie/xtalin)
473           * HW Dce80 spec:
474           * 00 - PCIE_REFCLK, 01 - XTALIN,    02 - GENERICA,    03 - GENERICB
475           * 04 - HSYNCA,      05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
476           REG_GET(PLL_CNTL, PLL_REF_DIV_SRC, &field);
477           pll_settings->use_external_clk = (field > 1);
478 
479           /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
480            * (we do not care any more from SI for some older DP Sink which
481            * does not report SS support, no known issues) */
482           if ((pix_clk_params->flags.ENABLE_SS) ||
483                               (dc_is_dp_signal(pix_clk_params->signal_type))) {
484 
485                     const struct spread_spectrum_data *ss_data = get_ss_data_entry(
486                                                   clk_src,
487                                                   pix_clk_params->signal_type,
488                                                   pll_settings->adjusted_pix_clk);
489 
490                     if (NULL != ss_data)
491                               pll_settings->ss_percentage = ss_data->percentage;
492           }
493 
494           /* Check VBIOS AdjustPixelClock Exec table */
495           if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) {
496                     /* Should never happen, ASSERT and fill up values to be able
497                      * to continue. */
498                     DC_LOG_ERROR(
499                               "%s: Failed to adjust pixel clock!!", __func__);
500                     pll_settings->actual_pix_clk =
501                                         pix_clk_params->requested_pix_clk;
502                     pll_settings->adjusted_pix_clk =
503                                         pix_clk_params->requested_pix_clk;
504 
505                     if (dc_is_dp_signal(pix_clk_params->signal_type))
506                               pll_settings->adjusted_pix_clk = 100000;
507           }
508 
509           /* Calculate Dividers */
510           if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
511                     /*Calculate Dividers by HDMI object, no SS case or SS case */
512                     pll_calc_error =
513                               calculate_pixel_clock_pll_dividers(
514                                                   &clk_src->calc_pll_hdmi,
515                                                   pll_settings);
516           else
517                     /*Calculate Dividers by default object, no SS case or SS case */
518                     pll_calc_error =
519                               calculate_pixel_clock_pll_dividers(
520                                                   &clk_src->calc_pll,
521                                                   pll_settings);
522 
523           return pll_calc_error;
524 }
525 
dce112_get_pix_clk_dividers_helper(struct dce110_clk_src * clk_src,struct pll_settings * pll_settings,struct pixel_clk_params * pix_clk_params)526 static void dce112_get_pix_clk_dividers_helper (
527                     struct dce110_clk_src *clk_src,
528                     struct pll_settings *pll_settings,
529                     struct pixel_clk_params *pix_clk_params)
530 {
531           uint32_t actualPixelClockInKHz;
532 
533           actualPixelClockInKHz = pix_clk_params->requested_pix_clk;
534           /* Calculate Dividers */
535           if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
536                     switch (pix_clk_params->color_depth) {
537                     case COLOR_DEPTH_101010:
538                               actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2;
539                               break;
540                     case COLOR_DEPTH_121212:
541                               actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2;
542                               break;
543                     case COLOR_DEPTH_161616:
544                               actualPixelClockInKHz = actualPixelClockInKHz * 2;
545                               break;
546                     default:
547                               break;
548                     }
549           }
550           pll_settings->actual_pix_clk = actualPixelClockInKHz;
551           pll_settings->adjusted_pix_clk = actualPixelClockInKHz;
552           pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk;
553 }
554 
dce110_get_pix_clk_dividers(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)555 static uint32_t dce110_get_pix_clk_dividers(
556                     struct clock_source *cs,
557                     struct pixel_clk_params *pix_clk_params,
558                     struct pll_settings *pll_settings)
559 {
560           struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
561           uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
562           DC_LOGGER_INIT();
563 
564           if (pix_clk_params == NULL || pll_settings == NULL
565                               || pix_clk_params->requested_pix_clk == 0) {
566                     DC_LOG_ERROR(
567                               "%s: Invalid parameters!!\n", __func__);
568                     return pll_calc_error;
569           }
570 
571           memset(pll_settings, 0, sizeof(*pll_settings));
572 
573           if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
574                               cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
575                     pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
576                     pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
577                     pll_settings->actual_pix_clk =
578                                                   pix_clk_params->requested_pix_clk;
579                     return 0;
580           }
581 
582           switch (cs->ctx->dce_version) {
583           case DCE_VERSION_8_0:
584           case DCE_VERSION_8_1:
585           case DCE_VERSION_8_3:
586           case DCE_VERSION_10_0:
587           case DCE_VERSION_11_0:
588                     pll_calc_error =
589                               dce110_get_pix_clk_dividers_helper(clk_src,
590                               pll_settings, pix_clk_params);
591                     break;
592           case DCE_VERSION_11_2:
593           case DCE_VERSION_11_22:
594           case DCE_VERSION_12_0:
595 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
596           case DCN_VERSION_1_0:
597 #endif
598 
599                     dce112_get_pix_clk_dividers_helper(clk_src,
600                                         pll_settings, pix_clk_params);
601                     break;
602           default:
603                     break;
604           }
605 
606           return pll_calc_error;
607 }
608 
dce110_get_pll_pixel_rate_in_hz(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)609 static uint32_t dce110_get_pll_pixel_rate_in_hz(
610           struct clock_source *cs,
611           struct pixel_clk_params *pix_clk_params,
612           struct pll_settings *pll_settings)
613 {
614           uint32_t inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
615           struct dc *dc_core = cs->ctx->dc;
616           struct dc_state *context = dc_core->current_state;
617           struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[inst];
618 
619           /* This function need separate to different DCE version, before separate, just use pixel clock */
620           return pipe_ctx->stream->phy_pix_clk;
621 
622 }
623 
dce110_get_dp_pixel_rate_from_combo_phy_pll(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)624 static uint32_t dce110_get_dp_pixel_rate_from_combo_phy_pll(
625           struct clock_source *cs,
626           struct pixel_clk_params *pix_clk_params,
627           struct pll_settings *pll_settings)
628 {
629           uint32_t inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
630           struct dc *dc_core = cs->ctx->dc;
631           struct dc_state *context = dc_core->current_state;
632           struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[inst];
633 
634           /* This function need separate to different DCE version, before separate, just use pixel clock */
635           return pipe_ctx->stream->phy_pix_clk;
636 }
637 
dce110_get_d_to_pixel_rate_in_hz(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)638 static uint32_t dce110_get_d_to_pixel_rate_in_hz(
639           struct clock_source *cs,
640           struct pixel_clk_params *pix_clk_params,
641           struct pll_settings *pll_settings)
642 {
643           uint32_t inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
644           struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
645           int dto_enabled = 0;
646           struct fixed31_32 pix_rate;
647 
648           REG_GET(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, &dto_enabled);
649 
650           if (dto_enabled) {
651                     uint32_t phase = 0;
652                     uint32_t modulo = 0;
653                     REG_GET(PHASE[inst], DP_DTO0_PHASE, &phase);
654                     REG_GET(MODULO[inst], DP_DTO0_MODULO, &modulo);
655 
656                     if (modulo == 0) {
657                               return 0;
658                     }
659 
660                     pix_rate = dc_fixpt_from_int(clk_src->ref_freq_khz);
661                     pix_rate = dc_fixpt_mul_int(pix_rate, 1000);
662                     pix_rate = dc_fixpt_mul_int(pix_rate, phase);
663                     pix_rate = dc_fixpt_div_int(pix_rate, modulo);
664 
665                     return dc_fixpt_round(pix_rate);
666           } else {
667                     return dce110_get_dp_pixel_rate_from_combo_phy_pll(cs, pix_clk_params, pll_settings);
668           }
669 }
670 
dce110_get_pix_rate_in_hz(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)671 static uint32_t dce110_get_pix_rate_in_hz(
672           struct clock_source *cs,
673           struct pixel_clk_params *pix_clk_params,
674           struct pll_settings *pll_settings)
675 {
676           uint32_t pix_rate = 0;
677           switch (pix_clk_params->signal_type) {
678           case      SIGNAL_TYPE_DISPLAY_PORT:
679           case      SIGNAL_TYPE_DISPLAY_PORT_MST:
680           case      SIGNAL_TYPE_EDP:
681           case      SIGNAL_TYPE_VIRTUAL:
682                     pix_rate = dce110_get_d_to_pixel_rate_in_hz(cs, pix_clk_params, pll_settings);
683                     break;
684           case      SIGNAL_TYPE_HDMI_TYPE_A:
685           default:
686                     pix_rate = dce110_get_pll_pixel_rate_in_hz(cs, pix_clk_params, pll_settings);
687                     break;
688           }
689 
690           return pix_rate;
691 }
692 
disable_spread_spectrum(struct dce110_clk_src * clk_src)693 static bool disable_spread_spectrum(struct dce110_clk_src *clk_src)
694 {
695           enum bp_result result;
696           struct bp_spread_spectrum_parameters bp_ss_params = {0};
697 
698           bp_ss_params.pll_id = clk_src->base.id;
699 
700           /*Call ASICControl to process ATOMBIOS Exec table*/
701           result = clk_src->bios->funcs->enable_spread_spectrum_on_ppll(
702                               clk_src->bios,
703                               &bp_ss_params,
704                               false);
705 
706           return result == BP_RESULT_OK;
707 }
708 
calculate_ss(const struct pll_settings * pll_settings,const struct spread_spectrum_data * ss_data,struct delta_sigma_data * ds_data)709 static bool calculate_ss(
710                     const struct pll_settings *pll_settings,
711                     const struct spread_spectrum_data *ss_data,
712                     struct delta_sigma_data *ds_data)
713 {
714           struct fixed31_32 fb_div;
715           struct fixed31_32 ss_amount;
716           struct fixed31_32 ss_nslip_amount;
717           struct fixed31_32 ss_ds_frac_amount;
718           struct fixed31_32 ss_step_size;
719           struct fixed31_32 modulation_time;
720 
721           if (ds_data == NULL)
722                     return false;
723           if (ss_data == NULL)
724                     return false;
725           if (ss_data->percentage == 0)
726                     return false;
727           if (pll_settings == NULL)
728                     return false;
729 
730           memset(ds_data, 0, sizeof(struct delta_sigma_data));
731 
732           /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
733           /* 6 decimal point support in fractional feedback divider */
734           fb_div  = dc_fixpt_from_fraction(
735                     pll_settings->fract_feedback_divider, 1000000);
736           fb_div = dc_fixpt_add_int(fb_div, pll_settings->feedback_divider);
737 
738           ds_data->ds_frac_amount = 0;
739           /*spreadSpectrumPercentage is in the unit of .01%,
740            * so have to divided by 100 * 100*/
741           ss_amount = dc_fixpt_mul(
742                     fb_div, dc_fixpt_from_fraction(ss_data->percentage,
743                                                   100 * ss_data->percentage_divider));
744           ds_data->feedback_amount = dc_fixpt_floor(ss_amount);
745 
746           ss_nslip_amount = dc_fixpt_sub(ss_amount,
747                     dc_fixpt_from_int(ds_data->feedback_amount));
748           ss_nslip_amount = dc_fixpt_mul_int(ss_nslip_amount, 10);
749           ds_data->nfrac_amount = dc_fixpt_floor(ss_nslip_amount);
750 
751           ss_ds_frac_amount = dc_fixpt_sub(ss_nslip_amount,
752                     dc_fixpt_from_int(ds_data->nfrac_amount));
753           ss_ds_frac_amount = dc_fixpt_mul_int(ss_ds_frac_amount, 65536);
754           ds_data->ds_frac_amount = dc_fixpt_floor(ss_ds_frac_amount);
755 
756           /* compute SS_STEP_SIZE_DSFRAC */
757           modulation_time = dc_fixpt_from_fraction(
758                     pll_settings->reference_freq * 1000,
759                     pll_settings->reference_divider * ss_data->modulation_freq_hz);
760 
761           if (ss_data->flags.CENTER_SPREAD)
762                     modulation_time = dc_fixpt_div_int(modulation_time, 4);
763           else
764                     modulation_time = dc_fixpt_div_int(modulation_time, 2);
765 
766           ss_step_size = dc_fixpt_div(ss_amount, modulation_time);
767           /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
768           ss_step_size = dc_fixpt_mul_int(ss_step_size, 65536 * 10);
769           ds_data->ds_frac_size =  dc_fixpt_floor(ss_step_size);
770 
771           return true;
772 }
773 
enable_spread_spectrum(struct dce110_clk_src * clk_src,enum signal_type signal,struct pll_settings * pll_settings)774 static bool enable_spread_spectrum(
775                     struct dce110_clk_src *clk_src,
776                     enum signal_type signal, struct pll_settings *pll_settings)
777 {
778           struct bp_spread_spectrum_parameters bp_params = {0};
779           struct delta_sigma_data d_s_data;
780           const struct spread_spectrum_data *ss_data = NULL;
781 
782           ss_data = get_ss_data_entry(
783                               clk_src,
784                               signal,
785                               pll_settings->calculated_pix_clk);
786 
787 /* Pixel clock PLL has been programmed to generate desired pixel clock,
788  * now enable SS on pixel clock */
789 /* TODO is it OK to return true not doing anything ??*/
790           if (ss_data != NULL && pll_settings->ss_percentage != 0) {
791                     if (calculate_ss(pll_settings, ss_data, &d_s_data)) {
792                               bp_params.ds.feedback_amount =
793                                                   d_s_data.feedback_amount;
794                               bp_params.ds.nfrac_amount =
795                                                   d_s_data.nfrac_amount;
796                               bp_params.ds.ds_frac_size = d_s_data.ds_frac_size;
797                               bp_params.ds_frac_amount =
798                                                   d_s_data.ds_frac_amount;
799                               bp_params.flags.DS_TYPE = 1;
800                               bp_params.pll_id = clk_src->base.id;
801                               bp_params.percentage = ss_data->percentage;
802                               if (ss_data->flags.CENTER_SPREAD)
803                                         bp_params.flags.CENTER_SPREAD = 1;
804                               if (ss_data->flags.EXTERNAL_SS)
805                                         bp_params.flags.EXTERNAL_SS = 1;
806 
807                               if (BP_RESULT_OK !=
808                                         clk_src->bios->funcs->
809                                                   enable_spread_spectrum_on_ppll(
810                                                                       clk_src->bios,
811                                                                       &bp_params,
812                                                                       true))
813                                         return false;
814                     } else
815                               return false;
816           }
817           return true;
818 }
819 
dce110_program_pixel_clk_resync(struct dce110_clk_src * clk_src,enum signal_type signal_type,enum dc_color_depth colordepth)820 static void dce110_program_pixel_clk_resync(
821                     struct dce110_clk_src *clk_src,
822                     enum signal_type signal_type,
823                     enum dc_color_depth colordepth)
824 {
825           REG_UPDATE(RESYNC_CNTL,
826                               DCCG_DEEP_COLOR_CNTL1, 0);
827           /*
828            24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
829            30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
830            36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
831            48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
832            */
833           if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
834                     return;
835 
836           switch (colordepth) {
837           case COLOR_DEPTH_888:
838                     REG_UPDATE(RESYNC_CNTL,
839                                         DCCG_DEEP_COLOR_CNTL1, 0);
840                     break;
841           case COLOR_DEPTH_101010:
842                     REG_UPDATE(RESYNC_CNTL,
843                                         DCCG_DEEP_COLOR_CNTL1, 1);
844                     break;
845           case COLOR_DEPTH_121212:
846                     REG_UPDATE(RESYNC_CNTL,
847                                         DCCG_DEEP_COLOR_CNTL1, 2);
848                     break;
849           case COLOR_DEPTH_161616:
850                     REG_UPDATE(RESYNC_CNTL,
851                                         DCCG_DEEP_COLOR_CNTL1, 3);
852                     break;
853           default:
854                     break;
855           }
856 }
857 
dce112_program_pixel_clk_resync(struct dce110_clk_src * clk_src,enum signal_type signal_type,enum dc_color_depth colordepth,bool enable_ycbcr420)858 static void dce112_program_pixel_clk_resync(
859                     struct dce110_clk_src *clk_src,
860                     enum signal_type signal_type,
861                     enum dc_color_depth colordepth,
862                     bool enable_ycbcr420)
863 {
864           uint32_t deep_color_cntl = 0;
865           uint32_t double_rate_enable = 0;
866 
867           /*
868            24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
869            30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
870            36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
871            48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
872            */
873           if (signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
874                     double_rate_enable = enable_ycbcr420 ? 1 : 0;
875 
876                     switch (colordepth) {
877                     case COLOR_DEPTH_888:
878                               deep_color_cntl = 0;
879                               break;
880                     case COLOR_DEPTH_101010:
881                               deep_color_cntl = 1;
882                               break;
883                     case COLOR_DEPTH_121212:
884                               deep_color_cntl = 2;
885                               break;
886                     case COLOR_DEPTH_161616:
887                               deep_color_cntl = 3;
888                               break;
889                     default:
890                               break;
891                     }
892           }
893 
894           if (clk_src->cs_mask->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE)
895                     REG_UPDATE_2(PIXCLK_RESYNC_CNTL,
896                                         PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl,
897                                         PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, double_rate_enable);
898           else
899                     REG_UPDATE(PIXCLK_RESYNC_CNTL,
900                                         PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl);
901 
902 }
903 
dce110_program_pix_clk(struct clock_source * clock_source,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)904 static bool dce110_program_pix_clk(
905                     struct clock_source *clock_source,
906                     struct pixel_clk_params *pix_clk_params,
907                     struct pll_settings *pll_settings)
908 {
909           struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
910           struct bp_pixel_clock_parameters bp_pc_params = {0};
911 
912 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
913           if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
914                     unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
915                     unsigned dp_dto_ref_kHz = 700000;
916                     unsigned clock_kHz = pll_settings->actual_pix_clk;
917 
918                     /* Set DTO values: phase = target clock, modulo = reference clock */
919                     REG_WRITE(PHASE[inst], clock_kHz);
920                     REG_WRITE(MODULO[inst], dp_dto_ref_kHz);
921 
922                     /* Enable DTO */
923                     REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
924                     return true;
925           }
926 #endif
927           /* First disable SS
928            * ATOMBIOS will enable by default SS on PLL for DP,
929            * do not disable it here
930            */
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);
935 
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 = pll_settings->actual_pix_clk;
940           bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
941           bp_pc_params.signal_type = pix_clk_params->signal_type;
942 
943           switch (clock_source->ctx->dce_version) {
944           case DCE_VERSION_8_0:
945           case DCE_VERSION_8_1:
946           case DCE_VERSION_8_3:
947           case DCE_VERSION_10_0:
948           case DCE_VERSION_11_0:
949                     bp_pc_params.reference_divider = pll_settings->reference_divider;
950                     bp_pc_params.feedback_divider = pll_settings->feedback_divider;
951                     bp_pc_params.fractional_feedback_divider =
952                                         pll_settings->fract_feedback_divider;
953                     bp_pc_params.pixel_clock_post_divider =
954                                         pll_settings->pix_clk_post_divider;
955                     bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
956                                                             pll_settings->use_external_clk;
957 
958                     if (clk_src->bios->funcs->set_pixel_clock(
959                                         clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
960                               return false;
961                     /* Enable SS
962                      * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
963                      * based on HW display PLL team, SS control settings should be programmed
964                      * during PLL Reset, but they do not have effect
965                      * until SS_EN is asserted.*/
966                     if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL
967                                         && !dc_is_dp_signal(pix_clk_params->signal_type)) {
968 
969                               if (pix_clk_params->flags.ENABLE_SS)
970                                         if (!enable_spread_spectrum(clk_src,
971                                                                                 pix_clk_params->signal_type,
972                                                                                 pll_settings))
973                                                   return false;
974 
975                               /* Resync deep color DTO */
976                               dce110_program_pixel_clk_resync(clk_src,
977                                                             pix_clk_params->signal_type,
978                                                             pix_clk_params->color_depth);
979                     }
980 
981                     break;
982           case DCE_VERSION_11_2:
983           case DCE_VERSION_11_22:
984           case DCE_VERSION_12_0:
985 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
986           case DCN_VERSION_1_0:
987 #endif
988 
989                     if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
990                               bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
991                                                                       pll_settings->use_external_clk;
992                               bp_pc_params.flags.SET_XTALIN_REF_SRC =
993                                                                       !pll_settings->use_external_clk;
994                               if (pix_clk_params->flags.SUPPORT_YCBCR420) {
995                                         bp_pc_params.flags.SUPPORT_YUV_420 = 1;
996                               }
997                     }
998                     if (clk_src->bios->funcs->set_pixel_clock(
999                                         clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
1000                               return false;
1001                     /* Resync deep color DTO */
1002                     if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
1003                               dce112_program_pixel_clk_resync(clk_src,
1004                                                             pix_clk_params->signal_type,
1005                                                             pix_clk_params->color_depth,
1006                                                             pix_clk_params->flags.SUPPORT_YCBCR420);
1007                     break;
1008           default:
1009                     break;
1010           }
1011 
1012           return true;
1013 }
1014 
dce110_clock_source_power_down(struct clock_source * clk_src)1015 static bool dce110_clock_source_power_down(
1016                     struct clock_source *clk_src)
1017 {
1018           struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src);
1019           enum bp_result bp_result;
1020           struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
1021 
1022           if (clk_src->dp_clk_src)
1023                     return true;
1024 
1025           /* If Pixel Clock is 0 it means Power Down Pll*/
1026           bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
1027           bp_pixel_clock_params.pll_id = clk_src->id;
1028           bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
1029 
1030           /*Call ASICControl to process ATOMBIOS Exec table*/
1031           bp_result = dce110_clk_src->bios->funcs->set_pixel_clock(
1032                               dce110_clk_src->bios,
1033                               &bp_pixel_clock_params);
1034 
1035           return bp_result == BP_RESULT_OK;
1036 }
1037 
1038 /*****************************************/
1039 /* Constructor                           */
1040 /*****************************************/
1041 static const struct clock_source_funcs dce110_clk_src_funcs = {
1042           .cs_power_down = dce110_clock_source_power_down,
1043           .program_pix_clk = dce110_program_pix_clk,
1044           .get_pix_clk_dividers = dce110_get_pix_clk_dividers,
1045           .get_pix_rate_in_hz = dce110_get_pix_rate_in_hz
1046 };
1047 
get_ss_info_from_atombios(struct dce110_clk_src * clk_src,enum as_signal_type as_signal,struct spread_spectrum_data * spread_spectrum_data[],uint32_t * ss_entries_num)1048 static void get_ss_info_from_atombios(
1049                     struct dce110_clk_src *clk_src,
1050                     enum as_signal_type as_signal,
1051                     struct spread_spectrum_data *spread_spectrum_data[],
1052                     uint32_t *ss_entries_num)
1053 {
1054           enum bp_result bp_result = BP_RESULT_FAILURE;
1055           struct spread_spectrum_info *ss_info;
1056           struct spread_spectrum_data *ss_data;
1057           struct spread_spectrum_info *ss_info_cur;
1058           struct spread_spectrum_data *ss_data_cur;
1059           uint32_t i;
1060           DC_LOGGER_INIT();
1061           if (ss_entries_num == NULL) {
1062                     DC_LOG_SYNC(
1063                               "Invalid entry !!!\n");
1064                     return;
1065           }
1066           if (spread_spectrum_data == NULL) {
1067                     DC_LOG_SYNC(
1068                               "Invalid array pointer!!!\n");
1069                     return;
1070           }
1071 
1072           spread_spectrum_data[0] = NULL;
1073           *ss_entries_num = 0;
1074 
1075           *ss_entries_num = clk_src->bios->funcs->get_ss_entry_number(
1076                               clk_src->bios,
1077                               as_signal);
1078 
1079           if (*ss_entries_num == 0)
1080                     return;
1081 
1082           ss_info = kcalloc(*ss_entries_num,
1083                                 sizeof(struct spread_spectrum_info),
1084                                 GFP_KERNEL);
1085           ss_info_cur = ss_info;
1086           if (ss_info == NULL)
1087                     return;
1088 
1089           ss_data = kcalloc(*ss_entries_num,
1090                                 sizeof(struct spread_spectrum_data),
1091                                 GFP_KERNEL);
1092           if (ss_data == NULL)
1093                     goto out_free_info;
1094 
1095           for (i = 0, ss_info_cur = ss_info;
1096                     i < (*ss_entries_num);
1097                     ++i, ++ss_info_cur) {
1098 
1099                     bp_result = clk_src->bios->funcs->get_spread_spectrum_info(
1100                                         clk_src->bios,
1101                                         as_signal,
1102                                         i,
1103                                         ss_info_cur);
1104 
1105                     if (bp_result != BP_RESULT_OK)
1106                               goto out_free_data;
1107           }
1108 
1109           for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data;
1110                     i < (*ss_entries_num);
1111                     ++i, ++ss_info_cur, ++ss_data_cur) {
1112 
1113                     if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) {
1114                               DC_LOG_SYNC(
1115                                         "Invalid ATOMBIOS SS Table!!!\n");
1116                               goto out_free_data;
1117                     }
1118 
1119                     /* for HDMI check SS percentage,
1120                      * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1121                     if (as_signal == AS_SIGNAL_TYPE_HDMI
1122                                         && ss_info_cur->spread_spectrum_percentage > 6){
1123                               /* invalid input, do nothing */
1124                               DC_LOG_SYNC(
1125                                         "Invalid SS percentage ");
1126                               DC_LOG_SYNC(
1127                                         "for HDMI in ATOMBIOS info Table!!!\n");
1128                               continue;
1129                     }
1130                     if (ss_info_cur->spread_percentage_divider == 1000) {
1131                               /* Keep previous precision from ATOMBIOS for these
1132                               * in case new precision set by ATOMBIOS for these
1133                               * (otherwise all code in DCE specific classes
1134                               * for all previous ASICs would need
1135                               * to be updated for SS calculations,
1136                               * Audio SS compensation and DP DTO SS compensation
1137                               * which assumes fixed SS percentage Divider = 100)*/
1138                               ss_info_cur->spread_spectrum_percentage /= 10;
1139                               ss_info_cur->spread_percentage_divider = 100;
1140                     }
1141 
1142                     ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range;
1143                     ss_data_cur->percentage =
1144                                         ss_info_cur->spread_spectrum_percentage;
1145                     ss_data_cur->percentage_divider =
1146                                         ss_info_cur->spread_percentage_divider;
1147                     ss_data_cur->modulation_freq_hz =
1148                                         ss_info_cur->spread_spectrum_range;
1149 
1150                     if (ss_info_cur->type.CENTER_MODE)
1151                               ss_data_cur->flags.CENTER_SPREAD = 1;
1152 
1153                     if (ss_info_cur->type.EXTERNAL)
1154                               ss_data_cur->flags.EXTERNAL_SS = 1;
1155 
1156           }
1157 
1158           *spread_spectrum_data = ss_data;
1159           kfree(ss_info);
1160           return;
1161 
1162 out_free_data:
1163           kfree(ss_data);
1164           *ss_entries_num = 0;
1165 out_free_info:
1166           kfree(ss_info);
1167 }
1168 
ss_info_from_atombios_create(struct dce110_clk_src * clk_src)1169 static void ss_info_from_atombios_create(
1170           struct dce110_clk_src *clk_src)
1171 {
1172           get_ss_info_from_atombios(
1173                     clk_src,
1174                     AS_SIGNAL_TYPE_DISPLAY_PORT,
1175                     &clk_src->dp_ss_params,
1176                     &clk_src->dp_ss_params_cnt);
1177           get_ss_info_from_atombios(
1178                     clk_src,
1179                     AS_SIGNAL_TYPE_HDMI,
1180                     &clk_src->hdmi_ss_params,
1181                     &clk_src->hdmi_ss_params_cnt);
1182           get_ss_info_from_atombios(
1183                     clk_src,
1184                     AS_SIGNAL_TYPE_DVI,
1185                     &clk_src->dvi_ss_params,
1186                     &clk_src->dvi_ss_params_cnt);
1187 }
1188 
calc_pll_max_vco_construct(struct calc_pll_clock_source * calc_pll_cs,struct calc_pll_clock_source_init_data * init_data)1189 static bool calc_pll_max_vco_construct(
1190                               struct calc_pll_clock_source *calc_pll_cs,
1191                               struct calc_pll_clock_source_init_data *init_data)
1192 {
1193           uint32_t i;
1194           struct dc_firmware_info fw_info = { { 0 } };
1195           if (calc_pll_cs == NULL ||
1196                               init_data == NULL ||
1197                               init_data->bp == NULL)
1198                     return false;
1199 
1200           if (init_data->bp->funcs->get_firmware_info(
1201                                         init_data->bp,
1202                                         &fw_info) != BP_RESULT_OK)
1203                     return false;
1204 
1205           calc_pll_cs->ctx = init_data->ctx;
1206           calc_pll_cs->ref_freq_khz = fw_info.pll_info.crystal_frequency;
1207           calc_pll_cs->min_vco_khz =
1208                               fw_info.pll_info.min_output_pxl_clk_pll_frequency;
1209           calc_pll_cs->max_vco_khz =
1210                               fw_info.pll_info.max_output_pxl_clk_pll_frequency;
1211 
1212           if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0)
1213                     calc_pll_cs->max_pll_input_freq_khz =
1214                               init_data->max_override_input_pxl_clk_pll_freq_khz;
1215           else
1216                     calc_pll_cs->max_pll_input_freq_khz =
1217                               fw_info.pll_info.max_input_pxl_clk_pll_frequency;
1218 
1219           if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0)
1220                     calc_pll_cs->min_pll_input_freq_khz =
1221                               init_data->min_override_input_pxl_clk_pll_freq_khz;
1222           else
1223                     calc_pll_cs->min_pll_input_freq_khz =
1224                               fw_info.pll_info.min_input_pxl_clk_pll_frequency;
1225 
1226           calc_pll_cs->min_pix_clock_pll_post_divider =
1227                               init_data->min_pix_clk_pll_post_divider;
1228           calc_pll_cs->max_pix_clock_pll_post_divider =
1229                               init_data->max_pix_clk_pll_post_divider;
1230           calc_pll_cs->min_pll_ref_divider =
1231                               init_data->min_pll_ref_divider;
1232           calc_pll_cs->max_pll_ref_divider =
1233                               init_data->max_pll_ref_divider;
1234 
1235           if (init_data->num_fract_fb_divider_decimal_point == 0 ||
1236                     init_data->num_fract_fb_divider_decimal_point_precision >
1237                                         init_data->num_fract_fb_divider_decimal_point) {
1238                     DC_LOG_ERROR(
1239                               "The dec point num or precision is incorrect!");
1240                     return false;
1241           }
1242           if (init_data->num_fract_fb_divider_decimal_point_precision == 0) {
1243                     DC_LOG_ERROR(
1244                               "Incorrect fract feedback divider precision num!");
1245                     return false;
1246           }
1247 
1248           calc_pll_cs->fract_fb_divider_decimal_points_num =
1249                                         init_data->num_fract_fb_divider_decimal_point;
1250           calc_pll_cs->fract_fb_divider_precision =
1251                               init_data->num_fract_fb_divider_decimal_point_precision;
1252           calc_pll_cs->fract_fb_divider_factor = 1;
1253           for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i)
1254                     calc_pll_cs->fract_fb_divider_factor *= 10;
1255 
1256           calc_pll_cs->fract_fb_divider_precision_factor = 1;
1257           for (
1258                     i = 0;
1259                     i < (calc_pll_cs->fract_fb_divider_decimal_points_num -
1260                                         calc_pll_cs->fract_fb_divider_precision);
1261                     ++i)
1262                     calc_pll_cs->fract_fb_divider_precision_factor *= 10;
1263 
1264           return true;
1265 }
1266 
dce110_clk_src_construct(struct dce110_clk_src * clk_src,struct dc_context * ctx,struct dc_bios * bios,enum clock_source_id id,const struct dce110_clk_src_regs * regs,const struct dce110_clk_src_shift * cs_shift,const struct dce110_clk_src_mask * cs_mask)1267 bool dce110_clk_src_construct(
1268           struct dce110_clk_src *clk_src,
1269           struct dc_context *ctx,
1270           struct dc_bios *bios,
1271           enum clock_source_id id,
1272           const struct dce110_clk_src_regs *regs,
1273           const struct dce110_clk_src_shift *cs_shift,
1274           const struct dce110_clk_src_mask *cs_mask)
1275 {
1276           struct dc_firmware_info fw_info = { { 0 } };
1277           struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi;
1278           struct calc_pll_clock_source_init_data calc_pll_cs_init_data;
1279 
1280           clk_src->base.ctx = ctx;
1281           clk_src->bios = bios;
1282           clk_src->base.id = id;
1283           clk_src->base.funcs = &dce110_clk_src_funcs;
1284 
1285           clk_src->regs = regs;
1286           clk_src->cs_shift = cs_shift;
1287           clk_src->cs_mask = cs_mask;
1288 
1289           if (clk_src->bios->funcs->get_firmware_info(
1290                               clk_src->bios, &fw_info) != BP_RESULT_OK) {
1291                     ASSERT_CRITICAL(false);
1292                     goto unexpected_failure;
1293           }
1294 
1295           clk_src->ext_clk_khz =
1296                               fw_info.external_clock_source_frequency_for_dp;
1297 
1298           switch (clk_src->base.ctx->dce_version) {
1299           case DCE_VERSION_8_0:
1300           case DCE_VERSION_8_1:
1301           case DCE_VERSION_8_3:
1302           case DCE_VERSION_10_0:
1303           case DCE_VERSION_11_0:
1304 
1305                     /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1306                     calc_pll_cs_init_data.bp = bios;
1307                     calc_pll_cs_init_data.min_pix_clk_pll_post_divider = 1;
1308                     calc_pll_cs_init_data.max_pix_clk_pll_post_divider =
1309                                         clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1310                     calc_pll_cs_init_data.min_pll_ref_divider =       1;
1311                     calc_pll_cs_init_data.max_pll_ref_divider =       clk_src->cs_mask->PLL_REF_DIV;
1312                     /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1313                     calc_pll_cs_init_data.min_override_input_pxl_clk_pll_freq_khz =       0;
1314                     /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1315                     calc_pll_cs_init_data.max_override_input_pxl_clk_pll_freq_khz =       0;
1316                     /*numberOfFractFBDividerDecimalPoints*/
1317                     calc_pll_cs_init_data.num_fract_fb_divider_decimal_point =
1318                                         FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1319                     /*number of decimal point to round off for fractional feedback divider value*/
1320                     calc_pll_cs_init_data.num_fract_fb_divider_decimal_point_precision =
1321                                         FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1322                     calc_pll_cs_init_data.ctx =   ctx;
1323 
1324                     /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1325                     calc_pll_cs_init_data_hdmi.bp = bios;
1326                     calc_pll_cs_init_data_hdmi.min_pix_clk_pll_post_divider = 1;
1327                     calc_pll_cs_init_data_hdmi.max_pix_clk_pll_post_divider =
1328                                         clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1329                     calc_pll_cs_init_data_hdmi.min_pll_ref_divider = 1;
1330                     calc_pll_cs_init_data_hdmi.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV;
1331                     /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1332                     calc_pll_cs_init_data_hdmi.min_override_input_pxl_clk_pll_freq_khz = 13500;
1333                     /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1334                     calc_pll_cs_init_data_hdmi.max_override_input_pxl_clk_pll_freq_khz = 27000;
1335                     /*numberOfFractFBDividerDecimalPoints*/
1336                     calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point =
1337                                         FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1338                     /*number of decimal point to round off for fractional feedback divider value*/
1339                     calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point_precision =
1340                                         FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1341                     calc_pll_cs_init_data_hdmi.ctx = ctx;
1342 
1343                     clk_src->ref_freq_khz = fw_info.pll_info.crystal_frequency;
1344 
1345                     if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL)
1346                               return true;
1347 
1348                     /* PLL only from here on */
1349                     ss_info_from_atombios_create(clk_src);
1350 
1351                     if (!calc_pll_max_vco_construct(
1352                                         &clk_src->calc_pll,
1353                                         &calc_pll_cs_init_data)) {
1354                               ASSERT_CRITICAL(false);
1355                               goto unexpected_failure;
1356                     }
1357 
1358 
1359                     calc_pll_cs_init_data_hdmi.
1360                                         min_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz/2;
1361                     calc_pll_cs_init_data_hdmi.
1362                                         max_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz;
1363 
1364 
1365                     if (!calc_pll_max_vco_construct(
1366                                         &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
1367                               ASSERT_CRITICAL(false);
1368                               goto unexpected_failure;
1369                     }
1370                     break;
1371           default:
1372                     break;
1373           }
1374 
1375           return true;
1376 
1377 unexpected_failure:
1378           return false;
1379 }
1380 
1381