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