Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dm_services.h"
0027 
0028 
0029 #include "dc_types.h"
0030 #include "core_types.h"
0031 
0032 #include "include/grph_object_id.h"
0033 #include "include/logger_interface.h"
0034 
0035 #include "dce_clock_source.h"
0036 #include "clk_mgr.h"
0037 
0038 #include "reg_helper.h"
0039 
0040 #define REG(reg)\
0041     (clk_src->regs->reg)
0042 
0043 #define CTX \
0044     clk_src->base.ctx
0045 
0046 #define DC_LOGGER_INIT()
0047 
0048 #undef FN
0049 #define FN(reg_name, field_name) \
0050     clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
0051 
0052 #define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
0053 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
0054 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF
0055 
0056 #define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
0057 
0058 static const struct spread_spectrum_data *get_ss_data_entry(
0059         struct dce110_clk_src *clk_src,
0060         enum signal_type signal,
0061         uint32_t pix_clk_khz)
0062 {
0063 
0064     uint32_t entrys_num;
0065     uint32_t i;
0066     struct spread_spectrum_data *ss_parm = NULL;
0067     struct spread_spectrum_data *ret = NULL;
0068 
0069     switch (signal) {
0070     case SIGNAL_TYPE_DVI_SINGLE_LINK:
0071     case SIGNAL_TYPE_DVI_DUAL_LINK:
0072         ss_parm = clk_src->dvi_ss_params;
0073         entrys_num = clk_src->dvi_ss_params_cnt;
0074         break;
0075 
0076     case SIGNAL_TYPE_HDMI_TYPE_A:
0077         ss_parm = clk_src->hdmi_ss_params;
0078         entrys_num = clk_src->hdmi_ss_params_cnt;
0079         break;
0080 
0081     case SIGNAL_TYPE_LVDS:
0082         ss_parm = clk_src->lvds_ss_params;
0083         entrys_num = clk_src->lvds_ss_params_cnt;
0084         break;
0085 
0086     case SIGNAL_TYPE_DISPLAY_PORT:
0087     case SIGNAL_TYPE_DISPLAY_PORT_MST:
0088     case SIGNAL_TYPE_EDP:
0089     case SIGNAL_TYPE_VIRTUAL:
0090         ss_parm = clk_src->dp_ss_params;
0091         entrys_num = clk_src->dp_ss_params_cnt;
0092         break;
0093 
0094     default:
0095         ss_parm = NULL;
0096         entrys_num = 0;
0097         break;
0098     }
0099 
0100     if (ss_parm == NULL)
0101         return ret;
0102 
0103     for (i = 0; i < entrys_num; ++i, ++ss_parm) {
0104         if (ss_parm->freq_range_khz >= pix_clk_khz) {
0105             ret = ss_parm;
0106             break;
0107         }
0108     }
0109 
0110     return ret;
0111 }
0112 
0113 /**
0114  * calculate_fb_and_fractional_fb_divider - Calculates feedback and fractional
0115  *                                          feedback dividers values
0116  *
0117  * @calc_pll_cs:        Pointer to clock source information
0118  * @target_pix_clk_100hz:   Desired frequency in 100 Hz
0119  * @ref_divider:            Reference divider (already known)
0120  * @post_divider:           Post Divider (already known)
0121  * @feedback_divider_param: Pointer where to store
0122  *              calculated feedback divider value
0123  * @fract_feedback_divider_param: Pointer where to store
0124  *              calculated fract feedback divider value
0125  *
0126  * return:
0127  * It fills the locations pointed by feedback_divider_param
0128  *                  and fract_feedback_divider_param
0129  * It returns   - true if feedback divider not 0
0130  *      - false should never happen)
0131  */
0132 static bool calculate_fb_and_fractional_fb_divider(
0133         struct calc_pll_clock_source *calc_pll_cs,
0134         uint32_t target_pix_clk_100hz,
0135         uint32_t ref_divider,
0136         uint32_t post_divider,
0137         uint32_t *feedback_divider_param,
0138         uint32_t *fract_feedback_divider_param)
0139 {
0140     uint64_t feedback_divider;
0141 
0142     feedback_divider =
0143         (uint64_t)target_pix_clk_100hz * ref_divider * post_divider;
0144     feedback_divider *= 10;
0145     /* additional factor, since we divide by 10 afterwards */
0146     feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
0147     feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz * 10ull);
0148 
0149 /*Round to the number of precision
0150  * The following code replace the old code (ullfeedbackDivider + 5)/10
0151  * for example if the difference between the number
0152  * of fractional feedback decimal point and the fractional FB Divider precision
0153  * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
0154 
0155     feedback_divider += 5ULL *
0156                 calc_pll_cs->fract_fb_divider_precision_factor;
0157     feedback_divider =
0158         div_u64(feedback_divider,
0159             calc_pll_cs->fract_fb_divider_precision_factor * 10);
0160     feedback_divider *= (uint64_t)
0161             (calc_pll_cs->fract_fb_divider_precision_factor);
0162 
0163     *feedback_divider_param =
0164         div_u64_rem(
0165             feedback_divider,
0166             calc_pll_cs->fract_fb_divider_factor,
0167             fract_feedback_divider_param);
0168 
0169     if (*feedback_divider_param != 0)
0170         return true;
0171     return false;
0172 }
0173 
0174 /**
0175  * calc_fb_divider_checking_tolerance - Calculates Feedback and
0176  *                                      Fractional Feedback divider values
0177  *                              for passed Reference and Post divider,
0178  *                                      checking for tolerance.
0179  * @calc_pll_cs:    Pointer to clock source information
0180  * @pll_settings:   Pointer to PLL settings
0181  * @ref_divider:    Reference divider (already known)
0182  * @post_divider:   Post Divider (already known)
0183  * @tolerance:      Tolerance for Calculated Pixel Clock to be within
0184  *
0185  * return:
0186  *  It fills the PLLSettings structure with PLL Dividers values
0187  *  if calculated values are within required tolerance
0188  *  It returns  - true if error is within tolerance
0189  *      - false if error is not within tolerance
0190  */
0191 static bool calc_fb_divider_checking_tolerance(
0192         struct calc_pll_clock_source *calc_pll_cs,
0193         struct pll_settings *pll_settings,
0194         uint32_t ref_divider,
0195         uint32_t post_divider,
0196         uint32_t tolerance)
0197 {
0198     uint32_t feedback_divider;
0199     uint32_t fract_feedback_divider;
0200     uint32_t actual_calculated_clock_100hz;
0201     uint32_t abs_err;
0202     uint64_t actual_calc_clk_100hz;
0203 
0204     calculate_fb_and_fractional_fb_divider(
0205             calc_pll_cs,
0206             pll_settings->adjusted_pix_clk_100hz,
0207             ref_divider,
0208             post_divider,
0209             &feedback_divider,
0210             &fract_feedback_divider);
0211 
0212     /*Actual calculated value*/
0213     actual_calc_clk_100hz = (uint64_t)feedback_divider *
0214                     calc_pll_cs->fract_fb_divider_factor +
0215                             fract_feedback_divider;
0216     actual_calc_clk_100hz *= calc_pll_cs->ref_freq_khz * 10;
0217     actual_calc_clk_100hz =
0218         div_u64(actual_calc_clk_100hz,
0219             ref_divider * post_divider *
0220                 calc_pll_cs->fract_fb_divider_factor);
0221 
0222     actual_calculated_clock_100hz = (uint32_t)(actual_calc_clk_100hz);
0223 
0224     abs_err = (actual_calculated_clock_100hz >
0225                     pll_settings->adjusted_pix_clk_100hz)
0226             ? actual_calculated_clock_100hz -
0227                     pll_settings->adjusted_pix_clk_100hz
0228             : pll_settings->adjusted_pix_clk_100hz -
0229                         actual_calculated_clock_100hz;
0230 
0231     if (abs_err <= tolerance) {
0232         /*found good values*/
0233         pll_settings->reference_freq = calc_pll_cs->ref_freq_khz;
0234         pll_settings->reference_divider = ref_divider;
0235         pll_settings->feedback_divider = feedback_divider;
0236         pll_settings->fract_feedback_divider = fract_feedback_divider;
0237         pll_settings->pix_clk_post_divider = post_divider;
0238         pll_settings->calculated_pix_clk_100hz =
0239             actual_calculated_clock_100hz;
0240         pll_settings->vco_freq =
0241             div_u64((u64)actual_calculated_clock_100hz * post_divider, 10);
0242         return true;
0243     }
0244     return false;
0245 }
0246 
0247 static bool calc_pll_dividers_in_range(
0248         struct calc_pll_clock_source *calc_pll_cs,
0249         struct pll_settings *pll_settings,
0250         uint32_t min_ref_divider,
0251         uint32_t max_ref_divider,
0252         uint32_t min_post_divider,
0253         uint32_t max_post_divider,
0254         uint32_t err_tolerance)
0255 {
0256     uint32_t ref_divider;
0257     uint32_t post_divider;
0258     uint32_t tolerance;
0259 
0260 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
0261  * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
0262     tolerance = (pll_settings->adjusted_pix_clk_100hz * err_tolerance) /
0263                                     100000;
0264     if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
0265         tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
0266 
0267     for (
0268             post_divider = max_post_divider;
0269             post_divider >= min_post_divider;
0270             --post_divider) {
0271         for (
0272                 ref_divider = min_ref_divider;
0273                 ref_divider <= max_ref_divider;
0274                 ++ref_divider) {
0275             if (calc_fb_divider_checking_tolerance(
0276                     calc_pll_cs,
0277                     pll_settings,
0278                     ref_divider,
0279                     post_divider,
0280                     tolerance)) {
0281                 return true;
0282             }
0283         }
0284     }
0285 
0286     return false;
0287 }
0288 
0289 static uint32_t calculate_pixel_clock_pll_dividers(
0290         struct calc_pll_clock_source *calc_pll_cs,
0291         struct pll_settings *pll_settings)
0292 {
0293     uint32_t err_tolerance;
0294     uint32_t min_post_divider;
0295     uint32_t max_post_divider;
0296     uint32_t min_ref_divider;
0297     uint32_t max_ref_divider;
0298 
0299     if (pll_settings->adjusted_pix_clk_100hz == 0) {
0300         DC_LOG_ERROR(
0301             "%s Bad requested pixel clock", __func__);
0302         return MAX_PLL_CALC_ERROR;
0303     }
0304 
0305 /* 1) Find Post divider ranges */
0306     if (pll_settings->pix_clk_post_divider) {
0307         min_post_divider = pll_settings->pix_clk_post_divider;
0308         max_post_divider = pll_settings->pix_clk_post_divider;
0309     } else {
0310         min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
0311         if (min_post_divider * pll_settings->adjusted_pix_clk_100hz <
0312                         calc_pll_cs->min_vco_khz * 10) {
0313             min_post_divider = calc_pll_cs->min_vco_khz * 10 /
0314                     pll_settings->adjusted_pix_clk_100hz;
0315             if ((min_post_divider *
0316                     pll_settings->adjusted_pix_clk_100hz) <
0317                         calc_pll_cs->min_vco_khz * 10)
0318                 min_post_divider++;
0319         }
0320 
0321         max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
0322         if (max_post_divider * pll_settings->adjusted_pix_clk_100hz
0323                 > calc_pll_cs->max_vco_khz * 10)
0324             max_post_divider = calc_pll_cs->max_vco_khz * 10 /
0325                     pll_settings->adjusted_pix_clk_100hz;
0326     }
0327 
0328 /* 2) Find Reference divider ranges
0329  * When SS is enabled, or for Display Port even without SS,
0330  * pll_settings->referenceDivider is not zero.
0331  * So calculate PPLL FB and fractional FB divider
0332  * using the passed reference divider*/
0333 
0334     if (pll_settings->reference_divider) {
0335         min_ref_divider = pll_settings->reference_divider;
0336         max_ref_divider = pll_settings->reference_divider;
0337     } else {
0338         min_ref_divider = ((calc_pll_cs->ref_freq_khz
0339                 / calc_pll_cs->max_pll_input_freq_khz)
0340                 > calc_pll_cs->min_pll_ref_divider)
0341             ? calc_pll_cs->ref_freq_khz
0342                     / calc_pll_cs->max_pll_input_freq_khz
0343             : calc_pll_cs->min_pll_ref_divider;
0344 
0345         max_ref_divider = ((calc_pll_cs->ref_freq_khz
0346                 / calc_pll_cs->min_pll_input_freq_khz)
0347                 < calc_pll_cs->max_pll_ref_divider)
0348             ? calc_pll_cs->ref_freq_khz /
0349                     calc_pll_cs->min_pll_input_freq_khz
0350             : calc_pll_cs->max_pll_ref_divider;
0351     }
0352 
0353 /* If some parameters are invalid we could have scenario when  "min">"max"
0354  * which produced endless loop later.
0355  * We should investigate why we get the wrong parameters.
0356  * But to follow the similar logic when "adjustedPixelClock" is set to be 0
0357  * it is better to return here than cause system hang/watchdog timeout later.
0358  *  ## SVS Wed 15 Jul 2009 */
0359 
0360     if (min_post_divider > max_post_divider) {
0361         DC_LOG_ERROR(
0362             "%s Post divider range is invalid", __func__);
0363         return MAX_PLL_CALC_ERROR;
0364     }
0365 
0366     if (min_ref_divider > max_ref_divider) {
0367         DC_LOG_ERROR(
0368             "%s Reference divider range is invalid", __func__);
0369         return MAX_PLL_CALC_ERROR;
0370     }
0371 
0372 /* 3) Try to find PLL dividers given ranges
0373  * starting with minimal error tolerance.
0374  * Increase error tolerance until PLL dividers found*/
0375     err_tolerance = MAX_PLL_CALC_ERROR;
0376 
0377     while (!calc_pll_dividers_in_range(
0378             calc_pll_cs,
0379             pll_settings,
0380             min_ref_divider,
0381             max_ref_divider,
0382             min_post_divider,
0383             max_post_divider,
0384             err_tolerance))
0385         err_tolerance += (err_tolerance > 10)
0386                 ? (err_tolerance / 10)
0387                 : 1;
0388 
0389     return err_tolerance;
0390 }
0391 
0392 static bool pll_adjust_pix_clk(
0393         struct dce110_clk_src *clk_src,
0394         struct pixel_clk_params *pix_clk_params,
0395         struct pll_settings *pll_settings)
0396 {
0397     uint32_t actual_pix_clk_100hz = 0;
0398     uint32_t requested_clk_100hz = 0;
0399     struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
0400                             0 };
0401     enum bp_result bp_result;
0402     switch (pix_clk_params->signal_type) {
0403     case SIGNAL_TYPE_HDMI_TYPE_A: {
0404         requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
0405         if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
0406             switch (pix_clk_params->color_depth) {
0407             case COLOR_DEPTH_101010:
0408                 requested_clk_100hz = (requested_clk_100hz * 5) >> 2;
0409                 break; /* x1.25*/
0410             case COLOR_DEPTH_121212:
0411                 requested_clk_100hz = (requested_clk_100hz * 6) >> 2;
0412                 break; /* x1.5*/
0413             case COLOR_DEPTH_161616:
0414                 requested_clk_100hz = requested_clk_100hz * 2;
0415                 break; /* x2.0*/
0416             default:
0417                 break;
0418             }
0419         }
0420         actual_pix_clk_100hz = requested_clk_100hz;
0421     }
0422         break;
0423 
0424     case SIGNAL_TYPE_DISPLAY_PORT:
0425     case SIGNAL_TYPE_DISPLAY_PORT_MST:
0426     case SIGNAL_TYPE_EDP:
0427         requested_clk_100hz = pix_clk_params->requested_sym_clk * 10;
0428         actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
0429         break;
0430 
0431     default:
0432         requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
0433         actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
0434         break;
0435     }
0436 
0437     bp_adjust_pixel_clock_params.pixel_clock = requested_clk_100hz / 10;
0438     bp_adjust_pixel_clock_params.
0439         encoder_object_id = pix_clk_params->encoder_object_id;
0440     bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
0441     bp_adjust_pixel_clock_params.
0442         ss_enable = pix_clk_params->flags.ENABLE_SS;
0443     bp_result = clk_src->bios->funcs->adjust_pixel_clock(
0444             clk_src->bios, &bp_adjust_pixel_clock_params);
0445     if (bp_result == BP_RESULT_OK) {
0446         pll_settings->actual_pix_clk_100hz = actual_pix_clk_100hz;
0447         pll_settings->adjusted_pix_clk_100hz =
0448             bp_adjust_pixel_clock_params.adjusted_pixel_clock * 10;
0449         pll_settings->reference_divider =
0450             bp_adjust_pixel_clock_params.reference_divider;
0451         pll_settings->pix_clk_post_divider =
0452             bp_adjust_pixel_clock_params.pixel_clock_post_divider;
0453 
0454         return true;
0455     }
0456 
0457     return false;
0458 }
0459 
0460 /*
0461  * Calculate PLL Dividers for given Clock Value.
0462  * First will call VBIOS Adjust Exec table to check if requested Pixel clock
0463  * will be Adjusted based on usage.
0464  * Then it will calculate PLL Dividers for this Adjusted clock using preferred
0465  * method (Maximum VCO frequency).
0466  *
0467  * \return
0468  *     Calculation error in units of 0.01%
0469  */
0470 
0471 static uint32_t dce110_get_pix_clk_dividers_helper (
0472         struct dce110_clk_src *clk_src,
0473         struct pll_settings *pll_settings,
0474         struct pixel_clk_params *pix_clk_params)
0475 {
0476     uint32_t field = 0;
0477     uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
0478     DC_LOGGER_INIT();
0479     /* Check if reference clock is external (not pcie/xtalin)
0480     * HW Dce80 spec:
0481     * 00 - PCIE_REFCLK, 01 - XTALIN,    02 - GENERICA,    03 - GENERICB
0482     * 04 - HSYNCA,      05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
0483     REG_GET(PLL_CNTL, PLL_REF_DIV_SRC, &field);
0484     pll_settings->use_external_clk = (field > 1);
0485 
0486     /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
0487      * (we do not care any more from SI for some older DP Sink which
0488      * does not report SS support, no known issues) */
0489     if ((pix_clk_params->flags.ENABLE_SS) ||
0490             (dc_is_dp_signal(pix_clk_params->signal_type))) {
0491 
0492         const struct spread_spectrum_data *ss_data = get_ss_data_entry(
0493                     clk_src,
0494                     pix_clk_params->signal_type,
0495                     pll_settings->adjusted_pix_clk_100hz / 10);
0496 
0497         if (NULL != ss_data)
0498             pll_settings->ss_percentage = ss_data->percentage;
0499     }
0500 
0501     /* Check VBIOS AdjustPixelClock Exec table */
0502     if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) {
0503         /* Should never happen, ASSERT and fill up values to be able
0504          * to continue. */
0505         DC_LOG_ERROR(
0506             "%s: Failed to adjust pixel clock!!", __func__);
0507         pll_settings->actual_pix_clk_100hz =
0508                 pix_clk_params->requested_pix_clk_100hz;
0509         pll_settings->adjusted_pix_clk_100hz =
0510                 pix_clk_params->requested_pix_clk_100hz;
0511 
0512         if (dc_is_dp_signal(pix_clk_params->signal_type))
0513             pll_settings->adjusted_pix_clk_100hz = 1000000;
0514     }
0515 
0516     /* Calculate Dividers */
0517     if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
0518         /*Calculate Dividers by HDMI object, no SS case or SS case */
0519         pll_calc_error =
0520             calculate_pixel_clock_pll_dividers(
0521                     &clk_src->calc_pll_hdmi,
0522                     pll_settings);
0523     else
0524         /*Calculate Dividers by default object, no SS case or SS case */
0525         pll_calc_error =
0526             calculate_pixel_clock_pll_dividers(
0527                     &clk_src->calc_pll,
0528                     pll_settings);
0529 
0530     return pll_calc_error;
0531 }
0532 
0533 static void dce112_get_pix_clk_dividers_helper (
0534         struct dce110_clk_src *clk_src,
0535         struct pll_settings *pll_settings,
0536         struct pixel_clk_params *pix_clk_params)
0537 {
0538     uint32_t actual_pixel_clock_100hz;
0539 
0540     actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz;
0541     /* Calculate Dividers */
0542     if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
0543         switch (pix_clk_params->color_depth) {
0544         case COLOR_DEPTH_101010:
0545             actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
0546             actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
0547             break;
0548         case COLOR_DEPTH_121212:
0549             actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
0550             actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
0551             break;
0552         case COLOR_DEPTH_161616:
0553             actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
0554             break;
0555         default:
0556             break;
0557         }
0558     }
0559     pll_settings->actual_pix_clk_100hz = actual_pixel_clock_100hz;
0560     pll_settings->adjusted_pix_clk_100hz = actual_pixel_clock_100hz;
0561     pll_settings->calculated_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
0562 }
0563 
0564 static uint32_t dce110_get_pix_clk_dividers(
0565         struct clock_source *cs,
0566         struct pixel_clk_params *pix_clk_params,
0567         struct pll_settings *pll_settings)
0568 {
0569     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
0570     uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
0571     DC_LOGGER_INIT();
0572 
0573     if (pix_clk_params == NULL || pll_settings == NULL
0574             || pix_clk_params->requested_pix_clk_100hz == 0) {
0575         DC_LOG_ERROR(
0576             "%s: Invalid parameters!!\n", __func__);
0577         return pll_calc_error;
0578     }
0579 
0580     memset(pll_settings, 0, sizeof(*pll_settings));
0581 
0582     if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
0583             cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
0584         pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
0585         pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
0586         pll_settings->actual_pix_clk_100hz =
0587                     pix_clk_params->requested_pix_clk_100hz;
0588         return 0;
0589     }
0590 
0591     pll_calc_error = dce110_get_pix_clk_dividers_helper(clk_src,
0592             pll_settings, pix_clk_params);
0593 
0594     return pll_calc_error;
0595 }
0596 
0597 static uint32_t dce112_get_pix_clk_dividers(
0598         struct clock_source *cs,
0599         struct pixel_clk_params *pix_clk_params,
0600         struct pll_settings *pll_settings)
0601 {
0602     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
0603     DC_LOGGER_INIT();
0604 
0605     if (pix_clk_params == NULL || pll_settings == NULL
0606             || pix_clk_params->requested_pix_clk_100hz == 0) {
0607         DC_LOG_ERROR(
0608             "%s: Invalid parameters!!\n", __func__);
0609         return -1;
0610     }
0611 
0612     memset(pll_settings, 0, sizeof(*pll_settings));
0613 
0614     if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
0615             cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
0616         pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
0617         pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
0618         pll_settings->actual_pix_clk_100hz =
0619                     pix_clk_params->requested_pix_clk_100hz;
0620         return -1;
0621     }
0622 
0623     dce112_get_pix_clk_dividers_helper(clk_src,
0624             pll_settings, pix_clk_params);
0625 
0626     return 0;
0627 }
0628 
0629 static bool disable_spread_spectrum(struct dce110_clk_src *clk_src)
0630 {
0631     enum bp_result result;
0632     struct bp_spread_spectrum_parameters bp_ss_params = {0};
0633 
0634     bp_ss_params.pll_id = clk_src->base.id;
0635 
0636     /*Call ASICControl to process ATOMBIOS Exec table*/
0637     result = clk_src->bios->funcs->enable_spread_spectrum_on_ppll(
0638             clk_src->bios,
0639             &bp_ss_params,
0640             false);
0641 
0642     return result == BP_RESULT_OK;
0643 }
0644 
0645 static bool calculate_ss(
0646         const struct pll_settings *pll_settings,
0647         const struct spread_spectrum_data *ss_data,
0648         struct delta_sigma_data *ds_data)
0649 {
0650     struct fixed31_32 fb_div;
0651     struct fixed31_32 ss_amount;
0652     struct fixed31_32 ss_nslip_amount;
0653     struct fixed31_32 ss_ds_frac_amount;
0654     struct fixed31_32 ss_step_size;
0655     struct fixed31_32 modulation_time;
0656 
0657     if (ds_data == NULL)
0658         return false;
0659     if (ss_data == NULL)
0660         return false;
0661     if (ss_data->percentage == 0)
0662         return false;
0663     if (pll_settings == NULL)
0664         return false;
0665 
0666     memset(ds_data, 0, sizeof(struct delta_sigma_data));
0667 
0668     /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
0669     /* 6 decimal point support in fractional feedback divider */
0670     fb_div  = dc_fixpt_from_fraction(
0671         pll_settings->fract_feedback_divider, 1000000);
0672     fb_div = dc_fixpt_add_int(fb_div, pll_settings->feedback_divider);
0673 
0674     ds_data->ds_frac_amount = 0;
0675     /*spreadSpectrumPercentage is in the unit of .01%,
0676      * so have to divided by 100 * 100*/
0677     ss_amount = dc_fixpt_mul(
0678         fb_div, dc_fixpt_from_fraction(ss_data->percentage,
0679                     100 * ss_data->percentage_divider));
0680     ds_data->feedback_amount = dc_fixpt_floor(ss_amount);
0681 
0682     ss_nslip_amount = dc_fixpt_sub(ss_amount,
0683         dc_fixpt_from_int(ds_data->feedback_amount));
0684     ss_nslip_amount = dc_fixpt_mul_int(ss_nslip_amount, 10);
0685     ds_data->nfrac_amount = dc_fixpt_floor(ss_nslip_amount);
0686 
0687     ss_ds_frac_amount = dc_fixpt_sub(ss_nslip_amount,
0688         dc_fixpt_from_int(ds_data->nfrac_amount));
0689     ss_ds_frac_amount = dc_fixpt_mul_int(ss_ds_frac_amount, 65536);
0690     ds_data->ds_frac_amount = dc_fixpt_floor(ss_ds_frac_amount);
0691 
0692     /* compute SS_STEP_SIZE_DSFRAC */
0693     modulation_time = dc_fixpt_from_fraction(
0694         pll_settings->reference_freq * 1000,
0695         pll_settings->reference_divider * ss_data->modulation_freq_hz);
0696 
0697     if (ss_data->flags.CENTER_SPREAD)
0698         modulation_time = dc_fixpt_div_int(modulation_time, 4);
0699     else
0700         modulation_time = dc_fixpt_div_int(modulation_time, 2);
0701 
0702     ss_step_size = dc_fixpt_div(ss_amount, modulation_time);
0703     /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
0704     ss_step_size = dc_fixpt_mul_int(ss_step_size, 65536 * 10);
0705     ds_data->ds_frac_size =  dc_fixpt_floor(ss_step_size);
0706 
0707     return true;
0708 }
0709 
0710 static bool enable_spread_spectrum(
0711         struct dce110_clk_src *clk_src,
0712         enum signal_type signal, struct pll_settings *pll_settings)
0713 {
0714     struct bp_spread_spectrum_parameters bp_params = {0};
0715     struct delta_sigma_data d_s_data;
0716     const struct spread_spectrum_data *ss_data = NULL;
0717 
0718     ss_data = get_ss_data_entry(
0719             clk_src,
0720             signal,
0721             pll_settings->calculated_pix_clk_100hz / 10);
0722 
0723 /* Pixel clock PLL has been programmed to generate desired pixel clock,
0724  * now enable SS on pixel clock */
0725 /* TODO is it OK to return true not doing anything ??*/
0726     if (ss_data != NULL && pll_settings->ss_percentage != 0) {
0727         if (calculate_ss(pll_settings, ss_data, &d_s_data)) {
0728             bp_params.ds.feedback_amount =
0729                     d_s_data.feedback_amount;
0730             bp_params.ds.nfrac_amount =
0731                     d_s_data.nfrac_amount;
0732             bp_params.ds.ds_frac_size = d_s_data.ds_frac_size;
0733             bp_params.ds_frac_amount =
0734                     d_s_data.ds_frac_amount;
0735             bp_params.flags.DS_TYPE = 1;
0736             bp_params.pll_id = clk_src->base.id;
0737             bp_params.percentage = ss_data->percentage;
0738             if (ss_data->flags.CENTER_SPREAD)
0739                 bp_params.flags.CENTER_SPREAD = 1;
0740             if (ss_data->flags.EXTERNAL_SS)
0741                 bp_params.flags.EXTERNAL_SS = 1;
0742 
0743             if (BP_RESULT_OK !=
0744                 clk_src->bios->funcs->
0745                     enable_spread_spectrum_on_ppll(
0746                             clk_src->bios,
0747                             &bp_params,
0748                             true))
0749                 return false;
0750         } else
0751             return false;
0752     }
0753     return true;
0754 }
0755 
0756 static void dce110_program_pixel_clk_resync(
0757         struct dce110_clk_src *clk_src,
0758         enum signal_type signal_type,
0759         enum dc_color_depth colordepth)
0760 {
0761     REG_UPDATE(RESYNC_CNTL,
0762             DCCG_DEEP_COLOR_CNTL1, 0);
0763     /*
0764      24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
0765      30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
0766      36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
0767      48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
0768      */
0769     if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
0770         return;
0771 
0772     switch (colordepth) {
0773     case COLOR_DEPTH_888:
0774         REG_UPDATE(RESYNC_CNTL,
0775                 DCCG_DEEP_COLOR_CNTL1, 0);
0776         break;
0777     case COLOR_DEPTH_101010:
0778         REG_UPDATE(RESYNC_CNTL,
0779                 DCCG_DEEP_COLOR_CNTL1, 1);
0780         break;
0781     case COLOR_DEPTH_121212:
0782         REG_UPDATE(RESYNC_CNTL,
0783                 DCCG_DEEP_COLOR_CNTL1, 2);
0784         break;
0785     case COLOR_DEPTH_161616:
0786         REG_UPDATE(RESYNC_CNTL,
0787                 DCCG_DEEP_COLOR_CNTL1, 3);
0788         break;
0789     default:
0790         break;
0791     }
0792 }
0793 
0794 static void dce112_program_pixel_clk_resync(
0795         struct dce110_clk_src *clk_src,
0796         enum signal_type signal_type,
0797         enum dc_color_depth colordepth,
0798         bool enable_ycbcr420)
0799 {
0800     uint32_t deep_color_cntl = 0;
0801     uint32_t double_rate_enable = 0;
0802 
0803     /*
0804      24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
0805      30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
0806      36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
0807      48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
0808      */
0809     if (signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
0810         double_rate_enable = enable_ycbcr420 ? 1 : 0;
0811 
0812         switch (colordepth) {
0813         case COLOR_DEPTH_888:
0814             deep_color_cntl = 0;
0815             break;
0816         case COLOR_DEPTH_101010:
0817             deep_color_cntl = 1;
0818             break;
0819         case COLOR_DEPTH_121212:
0820             deep_color_cntl = 2;
0821             break;
0822         case COLOR_DEPTH_161616:
0823             deep_color_cntl = 3;
0824             break;
0825         default:
0826             break;
0827         }
0828     }
0829 
0830     if (clk_src->cs_mask->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE)
0831         REG_UPDATE_2(PIXCLK_RESYNC_CNTL,
0832                 PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl,
0833                 PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, double_rate_enable);
0834     else
0835         REG_UPDATE(PIXCLK_RESYNC_CNTL,
0836                 PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl);
0837 
0838 }
0839 
0840 static bool dce110_program_pix_clk(
0841         struct clock_source *clock_source,
0842         struct pixel_clk_params *pix_clk_params,
0843         enum dp_link_encoding encoding,
0844         struct pll_settings *pll_settings)
0845 {
0846     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
0847     struct bp_pixel_clock_parameters bp_pc_params = {0};
0848 
0849     /* First disable SS
0850      * ATOMBIOS will enable by default SS on PLL for DP,
0851      * do not disable it here
0852      */
0853     if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL &&
0854             !dc_is_dp_signal(pix_clk_params->signal_type) &&
0855             clock_source->ctx->dce_version <= DCE_VERSION_11_0)
0856         disable_spread_spectrum(clk_src);
0857 
0858     /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
0859     bp_pc_params.controller_id = pix_clk_params->controller_id;
0860     bp_pc_params.pll_id = clock_source->id;
0861     bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
0862     bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
0863     bp_pc_params.signal_type = pix_clk_params->signal_type;
0864 
0865     bp_pc_params.reference_divider = pll_settings->reference_divider;
0866     bp_pc_params.feedback_divider = pll_settings->feedback_divider;
0867     bp_pc_params.fractional_feedback_divider =
0868             pll_settings->fract_feedback_divider;
0869     bp_pc_params.pixel_clock_post_divider =
0870             pll_settings->pix_clk_post_divider;
0871     bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
0872                     pll_settings->use_external_clk;
0873 
0874     switch (pix_clk_params->color_depth) {
0875     case COLOR_DEPTH_101010:
0876         bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_30;
0877         break;
0878     case COLOR_DEPTH_121212:
0879         bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_36;
0880         break;
0881     case COLOR_DEPTH_161616:
0882         bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_48;
0883         break;
0884     default:
0885         break;
0886     }
0887 
0888     if (clk_src->bios->funcs->set_pixel_clock(
0889             clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
0890         return false;
0891     /* Enable SS
0892      * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
0893      * based on HW display PLL team, SS control settings should be programmed
0894      * during PLL Reset, but they do not have effect
0895      * until SS_EN is asserted.*/
0896     if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL
0897             && !dc_is_dp_signal(pix_clk_params->signal_type)) {
0898 
0899         if (pix_clk_params->flags.ENABLE_SS)
0900             if (!enable_spread_spectrum(clk_src,
0901                             pix_clk_params->signal_type,
0902                             pll_settings))
0903                 return false;
0904 
0905         /* Resync deep color DTO */
0906         dce110_program_pixel_clk_resync(clk_src,
0907                     pix_clk_params->signal_type,
0908                     pix_clk_params->color_depth);
0909     }
0910 
0911     return true;
0912 }
0913 
0914 static bool dce112_program_pix_clk(
0915         struct clock_source *clock_source,
0916         struct pixel_clk_params *pix_clk_params,
0917         enum dp_link_encoding encoding,
0918         struct pll_settings *pll_settings)
0919 {
0920     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
0921     struct bp_pixel_clock_parameters bp_pc_params = {0};
0922 
0923     if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
0924         unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
0925         unsigned dp_dto_ref_100hz = 7000000;
0926         unsigned clock_100hz = pll_settings->actual_pix_clk_100hz;
0927 
0928         /* Set DTO values: phase = target clock, modulo = reference clock */
0929         REG_WRITE(PHASE[inst], clock_100hz);
0930         REG_WRITE(MODULO[inst], dp_dto_ref_100hz);
0931 
0932         /* Enable DTO */
0933         REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
0934         return true;
0935     }
0936     /* First disable SS
0937      * ATOMBIOS will enable by default SS on PLL for DP,
0938      * do not disable it here
0939      */
0940     if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL &&
0941             !dc_is_dp_signal(pix_clk_params->signal_type) &&
0942             clock_source->ctx->dce_version <= DCE_VERSION_11_0)
0943         disable_spread_spectrum(clk_src);
0944 
0945     /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
0946     bp_pc_params.controller_id = pix_clk_params->controller_id;
0947     bp_pc_params.pll_id = clock_source->id;
0948     bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
0949     bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
0950     bp_pc_params.signal_type = pix_clk_params->signal_type;
0951 
0952     if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
0953         bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
0954                         pll_settings->use_external_clk;
0955         bp_pc_params.flags.SET_XTALIN_REF_SRC =
0956                         !pll_settings->use_external_clk;
0957         if (pix_clk_params->flags.SUPPORT_YCBCR420) {
0958             bp_pc_params.flags.SUPPORT_YUV_420 = 1;
0959         }
0960     }
0961     if (clk_src->bios->funcs->set_pixel_clock(
0962             clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
0963         return false;
0964     /* Resync deep color DTO */
0965     if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
0966         dce112_program_pixel_clk_resync(clk_src,
0967                     pix_clk_params->signal_type,
0968                     pix_clk_params->color_depth,
0969                     pix_clk_params->flags.SUPPORT_YCBCR420);
0970 
0971     return true;
0972 }
0973 
0974 static bool dcn31_program_pix_clk(
0975         struct clock_source *clock_source,
0976         struct pixel_clk_params *pix_clk_params,
0977         enum dp_link_encoding encoding,
0978         struct pll_settings *pll_settings)
0979 {
0980     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
0981     unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
0982     unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
0983     const struct pixel_rate_range_table_entry *e =
0984             look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10);
0985     struct bp_pixel_clock_parameters bp_pc_params = {0};
0986     enum transmitter_color_depth bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
0987     // For these signal types Driver to program DP_DTO without calling VBIOS Command table
0988     if (dc_is_dp_signal(pix_clk_params->signal_type) || dc_is_virtual_signal(pix_clk_params->signal_type)) {
0989         if (e) {
0990             /* Set DTO values: phase = target clock, modulo = reference clock*/
0991             REG_WRITE(PHASE[inst], e->target_pixel_rate_khz * e->mult_factor);
0992             REG_WRITE(MODULO[inst], dp_dto_ref_khz * e->div_factor);
0993         } else {
0994             /* Set DTO values: phase = target clock, modulo = reference clock*/
0995             REG_WRITE(PHASE[inst], pll_settings->actual_pix_clk_100hz * 100);
0996             REG_WRITE(MODULO[inst], dp_dto_ref_khz * 1000);
0997         }
0998 #if defined(CONFIG_DRM_AMD_DC_DCN)
0999         /* Enable DTO */
1000         if (clk_src->cs_mask->PIPE0_DTO_SRC_SEL)
1001             if (encoding == DP_128b_132b_ENCODING)
1002                 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
1003                         DP_DTO0_ENABLE, 1,
1004                         PIPE0_DTO_SRC_SEL, 2);
1005             else
1006                 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
1007                         DP_DTO0_ENABLE, 1,
1008                         PIPE0_DTO_SRC_SEL, 1);
1009         else
1010             REG_UPDATE(PIXEL_RATE_CNTL[inst],
1011                     DP_DTO0_ENABLE, 1);
1012 #else
1013         REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
1014 #endif
1015     } else {
1016         if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
1017             unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
1018             unsigned dp_dto_ref_100hz = 7000000;
1019             unsigned clock_100hz = pll_settings->actual_pix_clk_100hz;
1020 
1021             /* Set DTO values: phase = target clock, modulo = reference clock */
1022             REG_WRITE(PHASE[inst], clock_100hz);
1023             REG_WRITE(MODULO[inst], dp_dto_ref_100hz);
1024 
1025             /* Enable DTO */
1026     #if defined(CONFIG_DRM_AMD_DC_DCN)
1027             if (clk_src->cs_mask->PIPE0_DTO_SRC_SEL)
1028                 REG_UPDATE_2(PIXEL_RATE_CNTL[inst],
1029                         DP_DTO0_ENABLE, 1,
1030                         PIPE0_DTO_SRC_SEL, 1);
1031             else
1032                 REG_UPDATE(PIXEL_RATE_CNTL[inst],
1033                         DP_DTO0_ENABLE, 1);
1034     #else
1035             REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
1036     #endif
1037             return true;
1038         }
1039 
1040 #if defined(CONFIG_DRM_AMD_DC_DCN)
1041         if (clk_src->cs_mask->PIPE0_DTO_SRC_SEL)
1042             REG_UPDATE(PIXEL_RATE_CNTL[inst],
1043                     PIPE0_DTO_SRC_SEL, 0);
1044 #endif
1045 
1046         /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
1047         bp_pc_params.controller_id = pix_clk_params->controller_id;
1048         bp_pc_params.pll_id = clock_source->id;
1049         bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
1050         bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
1051         bp_pc_params.signal_type = pix_clk_params->signal_type;
1052 
1053         // Make sure we send the correct color depth to DMUB for HDMI
1054         if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
1055             switch (pix_clk_params->color_depth) {
1056             case COLOR_DEPTH_888:
1057                 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1058                 break;
1059             case COLOR_DEPTH_101010:
1060                 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_30;
1061                 break;
1062             case COLOR_DEPTH_121212:
1063                 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_36;
1064                 break;
1065             case COLOR_DEPTH_161616:
1066                 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_48;
1067                 break;
1068             default:
1069                 bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
1070                 break;
1071             }
1072             bp_pc_params.color_depth = bp_pc_colour_depth;
1073         }
1074 
1075         if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
1076             bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
1077                             pll_settings->use_external_clk;
1078             bp_pc_params.flags.SET_XTALIN_REF_SRC =
1079                             !pll_settings->use_external_clk;
1080             if (pix_clk_params->flags.SUPPORT_YCBCR420) {
1081                 bp_pc_params.flags.SUPPORT_YUV_420 = 1;
1082             }
1083         }
1084         if (clk_src->bios->funcs->set_pixel_clock(
1085                 clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
1086             return false;
1087         /* Resync deep color DTO */
1088         if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
1089             dce112_program_pixel_clk_resync(clk_src,
1090                         pix_clk_params->signal_type,
1091                         pix_clk_params->color_depth,
1092                         pix_clk_params->flags.SUPPORT_YCBCR420);
1093     }
1094 
1095     return true;
1096 }
1097 
1098 static bool dce110_clock_source_power_down(
1099         struct clock_source *clk_src)
1100 {
1101     struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src);
1102     enum bp_result bp_result;
1103     struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
1104 
1105     if (clk_src->dp_clk_src)
1106         return true;
1107 
1108     /* If Pixel Clock is 0 it means Power Down Pll*/
1109     bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
1110     bp_pixel_clock_params.pll_id = clk_src->id;
1111     bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
1112 
1113     /*Call ASICControl to process ATOMBIOS Exec table*/
1114     bp_result = dce110_clk_src->bios->funcs->set_pixel_clock(
1115             dce110_clk_src->bios,
1116             &bp_pixel_clock_params);
1117 
1118     return bp_result == BP_RESULT_OK;
1119 }
1120 
1121 static bool get_pixel_clk_frequency_100hz(
1122         const struct clock_source *clock_source,
1123         unsigned int inst,
1124         unsigned int *pixel_clk_khz)
1125 {
1126     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1127     unsigned int clock_hz = 0;
1128     unsigned int modulo_hz = 0;
1129 
1130     if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
1131         clock_hz = REG_READ(PHASE[inst]);
1132 
1133         if (clock_source->ctx->dc->hwss.enable_vblanks_synchronization &&
1134             clock_source->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0) {
1135             /* NOTE: In case VBLANK syncronization is enabled, MODULO may
1136              * not be programmed equal to DPREFCLK
1137              */
1138             modulo_hz = REG_READ(MODULO[inst]);
1139             if (modulo_hz)
1140                 *pixel_clk_khz = div_u64((uint64_t)clock_hz*
1141                     clock_source->ctx->dc->clk_mgr->dprefclk_khz*10,
1142                     modulo_hz);
1143             else
1144                 *pixel_clk_khz = 0;
1145         } else {
1146             /* NOTE: There is agreement with VBIOS here that MODULO is
1147              * programmed equal to DPREFCLK, in which case PHASE will be
1148              * equivalent to pixel clock.
1149              */
1150             *pixel_clk_khz = clock_hz / 100;
1151         }
1152         return true;
1153     }
1154 
1155     return false;
1156 }
1157 
1158 /* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
1159 const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] = {
1160     // /1.001 rates
1161     {25170, 25180, 25200, 1000, 1001},  //25.2MHz   ->   25.17
1162     {59340, 59350, 59400, 1000, 1001},  //59.4Mhz   ->   59.340
1163     {74170, 74180, 74250, 1000, 1001},  //74.25Mhz  ->   74.1758
1164     {125870, 125880, 126000, 1000, 1001},   //126Mhz    ->  125.87
1165     {148350, 148360, 148500, 1000, 1001},   //148.5Mhz  ->  148.3516
1166     {167830, 167840, 168000, 1000, 1001},   //168Mhz    ->  167.83
1167     {222520, 222530, 222750, 1000, 1001},   //222.75Mhz ->  222.527
1168     {257140, 257150, 257400, 1000, 1001},   //257.4Mhz  ->  257.1429
1169     {296700, 296710, 297000, 1000, 1001},   //297Mhz    ->  296.7033
1170     {342850, 342860, 343200, 1000, 1001},   //343.2Mhz  ->  342.857
1171     {395600, 395610, 396000, 1000, 1001},   //396Mhz    ->  395.6
1172     {409090, 409100, 409500, 1000, 1001},   //409.5Mhz  ->  409.091
1173     {445050, 445060, 445500, 1000, 1001},   //445.5Mhz  ->  445.055
1174     {467530, 467540, 468000, 1000, 1001},   //468Mhz    ->  467.5325
1175     {519230, 519240, 519750, 1000, 1001},   //519.75Mhz ->  519.231
1176     {525970, 525980, 526500, 1000, 1001},   //526.5Mhz  ->  525.974
1177     {545450, 545460, 546000, 1000, 1001},   //546Mhz    ->  545.455
1178     {593400, 593410, 594000, 1000, 1001},   //594Mhz    ->  593.4066
1179     {623370, 623380, 624000, 1000, 1001},   //624Mhz    ->  623.377
1180     {692300, 692310, 693000, 1000, 1001},   //693Mhz    ->  692.308
1181     {701290, 701300, 702000, 1000, 1001},   //702Mhz    ->  701.2987
1182     {791200, 791210, 792000, 1000, 1001},   //792Mhz    ->  791.209
1183     {890100, 890110, 891000, 1000, 1001},   //891Mhz    ->  890.1099
1184     {1186810, 1186820, 1188000, 1000, 1001},//1188Mhz   -> 1186.8131
1185 
1186     // *1.001 rates
1187     {27020, 27030, 27000, 1001, 1000}, //27Mhz
1188     {54050, 54060, 54000, 1001, 1000}, //54Mhz
1189     {108100, 108110, 108000, 1001, 1000},//108Mhz
1190 };
1191 
1192 const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb(
1193         unsigned int pixel_rate_khz)
1194 {
1195     int i;
1196 
1197     for (i = 0; i < NUM_ELEMENTS(video_optimized_pixel_rates); i++) {
1198         const struct pixel_rate_range_table_entry *e = &video_optimized_pixel_rates[i];
1199 
1200         if (e->range_min_khz <= pixel_rate_khz && pixel_rate_khz <= e->range_max_khz) {
1201             return e;
1202         }
1203     }
1204 
1205     return NULL;
1206 }
1207 
1208 static bool dcn20_program_pix_clk(
1209         struct clock_source *clock_source,
1210         struct pixel_clk_params *pix_clk_params,
1211         enum dp_link_encoding encoding,
1212         struct pll_settings *pll_settings)
1213 {
1214     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1215     unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
1216 
1217     dce112_program_pix_clk(clock_source, pix_clk_params, encoding, pll_settings);
1218 
1219     if (clock_source->ctx->dc->hwss.enable_vblanks_synchronization &&
1220             clock_source->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0) {
1221         /* NOTE: In case VBLANK syncronization is enabled,
1222          * we need to set modulo to default DPREFCLK first
1223          * dce112_program_pix_clk does not set default DPREFCLK
1224          */
1225         REG_WRITE(MODULO[inst],
1226             clock_source->ctx->dc->clk_mgr->dprefclk_khz*1000);
1227     }
1228     return true;
1229 }
1230 
1231 static bool dcn20_override_dp_pix_clk(
1232         struct clock_source *clock_source,
1233         unsigned int inst,
1234         unsigned int pixel_clk,
1235         unsigned int ref_clk)
1236 {
1237     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1238 
1239     REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 0);
1240     REG_WRITE(PHASE[inst], pixel_clk);
1241     REG_WRITE(MODULO[inst], ref_clk);
1242     REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
1243     return true;
1244 }
1245 
1246 static const struct clock_source_funcs dcn20_clk_src_funcs = {
1247     .cs_power_down = dce110_clock_source_power_down,
1248     .program_pix_clk = dcn20_program_pix_clk,
1249     .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
1250     .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz,
1251     .override_dp_pix_clk = dcn20_override_dp_pix_clk
1252 };
1253 
1254 static bool dcn3_program_pix_clk(
1255         struct clock_source *clock_source,
1256         struct pixel_clk_params *pix_clk_params,
1257         enum dp_link_encoding encoding,
1258         struct pll_settings *pll_settings)
1259 {
1260     struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
1261     unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
1262     unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
1263     const struct pixel_rate_range_table_entry *e =
1264             look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10);
1265 
1266     // For these signal types Driver to program DP_DTO without calling VBIOS Command table
1267     if (dc_is_dp_signal(pix_clk_params->signal_type)) {
1268         if (e) {
1269             /* Set DTO values: phase = target clock, modulo = reference clock*/
1270             REG_WRITE(PHASE[inst], e->target_pixel_rate_khz * e->mult_factor);
1271             REG_WRITE(MODULO[inst], dp_dto_ref_khz * e->div_factor);
1272         } else {
1273             /* Set DTO values: phase = target clock, modulo = reference clock*/
1274             REG_WRITE(PHASE[inst], pll_settings->actual_pix_clk_100hz * 100);
1275             REG_WRITE(MODULO[inst], dp_dto_ref_khz * 1000);
1276         }
1277         REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
1278     } else
1279         // For other signal types(HDMI_TYPE_A, DVI) Driver still to call VBIOS Command table
1280         dce112_program_pix_clk(clock_source, pix_clk_params, encoding, pll_settings);
1281 
1282     return true;
1283 }
1284 
1285 static uint32_t dcn3_get_pix_clk_dividers(
1286         struct clock_source *cs,
1287         struct pixel_clk_params *pix_clk_params,
1288         struct pll_settings *pll_settings)
1289 {
1290     unsigned long long actual_pix_clk_100Hz = pix_clk_params ? pix_clk_params->requested_pix_clk_100hz : 0;
1291 
1292     DC_LOGGER_INIT();
1293 
1294     if (pix_clk_params == NULL || pll_settings == NULL
1295             || pix_clk_params->requested_pix_clk_100hz == 0) {
1296         DC_LOG_ERROR(
1297             "%s: Invalid parameters!!\n", __func__);
1298         return -1;
1299     }
1300 
1301     memset(pll_settings, 0, sizeof(*pll_settings));
1302     /* Adjust for HDMI Type A deep color */
1303     if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
1304         switch (pix_clk_params->color_depth) {
1305         case COLOR_DEPTH_101010:
1306             actual_pix_clk_100Hz = (actual_pix_clk_100Hz * 5) >> 2;
1307             break;
1308         case COLOR_DEPTH_121212:
1309             actual_pix_clk_100Hz = (actual_pix_clk_100Hz * 6) >> 2;
1310             break;
1311         case COLOR_DEPTH_161616:
1312             actual_pix_clk_100Hz = actual_pix_clk_100Hz * 2;
1313             break;
1314         default:
1315             break;
1316         }
1317     }
1318     pll_settings->actual_pix_clk_100hz = (unsigned int) actual_pix_clk_100Hz;
1319     pll_settings->adjusted_pix_clk_100hz = (unsigned int) actual_pix_clk_100Hz;
1320     pll_settings->calculated_pix_clk_100hz = (unsigned int) actual_pix_clk_100Hz;
1321 
1322     return 0;
1323 }
1324 
1325 static const struct clock_source_funcs dcn3_clk_src_funcs = {
1326     .cs_power_down = dce110_clock_source_power_down,
1327     .program_pix_clk = dcn3_program_pix_clk,
1328     .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
1329     .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1330 };
1331 
1332 static const struct clock_source_funcs dcn31_clk_src_funcs = {
1333     .cs_power_down = dce110_clock_source_power_down,
1334     .program_pix_clk = dcn31_program_pix_clk,
1335     .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
1336     .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1337 };
1338 
1339 /*****************************************/
1340 /* Constructor                           */
1341 /*****************************************/
1342 
1343 static const struct clock_source_funcs dce112_clk_src_funcs = {
1344     .cs_power_down = dce110_clock_source_power_down,
1345     .program_pix_clk = dce112_program_pix_clk,
1346     .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
1347     .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1348 };
1349 static const struct clock_source_funcs dce110_clk_src_funcs = {
1350     .cs_power_down = dce110_clock_source_power_down,
1351     .program_pix_clk = dce110_program_pix_clk,
1352     .get_pix_clk_dividers = dce110_get_pix_clk_dividers,
1353     .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1354 };
1355 
1356 
1357 static void get_ss_info_from_atombios(
1358         struct dce110_clk_src *clk_src,
1359         enum as_signal_type as_signal,
1360         struct spread_spectrum_data *spread_spectrum_data[],
1361         uint32_t *ss_entries_num)
1362 {
1363     enum bp_result bp_result = BP_RESULT_FAILURE;
1364     struct spread_spectrum_info *ss_info;
1365     struct spread_spectrum_data *ss_data;
1366     struct spread_spectrum_info *ss_info_cur;
1367     struct spread_spectrum_data *ss_data_cur;
1368     uint32_t i;
1369     DC_LOGGER_INIT();
1370     if (ss_entries_num == NULL) {
1371         DC_LOG_SYNC(
1372             "Invalid entry !!!\n");
1373         return;
1374     }
1375     if (spread_spectrum_data == NULL) {
1376         DC_LOG_SYNC(
1377             "Invalid array pointer!!!\n");
1378         return;
1379     }
1380 
1381     spread_spectrum_data[0] = NULL;
1382     *ss_entries_num = 0;
1383 
1384     *ss_entries_num = clk_src->bios->funcs->get_ss_entry_number(
1385             clk_src->bios,
1386             as_signal);
1387 
1388     if (*ss_entries_num == 0)
1389         return;
1390 
1391     ss_info = kcalloc(*ss_entries_num,
1392               sizeof(struct spread_spectrum_info),
1393               GFP_KERNEL);
1394     ss_info_cur = ss_info;
1395     if (ss_info == NULL)
1396         return;
1397 
1398     ss_data = kcalloc(*ss_entries_num,
1399               sizeof(struct spread_spectrum_data),
1400               GFP_KERNEL);
1401     if (ss_data == NULL)
1402         goto out_free_info;
1403 
1404     for (i = 0, ss_info_cur = ss_info;
1405         i < (*ss_entries_num);
1406         ++i, ++ss_info_cur) {
1407 
1408         bp_result = clk_src->bios->funcs->get_spread_spectrum_info(
1409                 clk_src->bios,
1410                 as_signal,
1411                 i,
1412                 ss_info_cur);
1413 
1414         if (bp_result != BP_RESULT_OK)
1415             goto out_free_data;
1416     }
1417 
1418     for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data;
1419         i < (*ss_entries_num);
1420         ++i, ++ss_info_cur, ++ss_data_cur) {
1421 
1422         if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) {
1423             DC_LOG_SYNC(
1424                 "Invalid ATOMBIOS SS Table!!!\n");
1425             goto out_free_data;
1426         }
1427 
1428         /* for HDMI check SS percentage,
1429          * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1430         if (as_signal == AS_SIGNAL_TYPE_HDMI
1431                 && ss_info_cur->spread_spectrum_percentage > 6){
1432             /* invalid input, do nothing */
1433             DC_LOG_SYNC(
1434                 "Invalid SS percentage ");
1435             DC_LOG_SYNC(
1436                 "for HDMI in ATOMBIOS info Table!!!\n");
1437             continue;
1438         }
1439         if (ss_info_cur->spread_percentage_divider == 1000) {
1440             /* Keep previous precision from ATOMBIOS for these
1441             * in case new precision set by ATOMBIOS for these
1442             * (otherwise all code in DCE specific classes
1443             * for all previous ASICs would need
1444             * to be updated for SS calculations,
1445             * Audio SS compensation and DP DTO SS compensation
1446             * which assumes fixed SS percentage Divider = 100)*/
1447             ss_info_cur->spread_spectrum_percentage /= 10;
1448             ss_info_cur->spread_percentage_divider = 100;
1449         }
1450 
1451         ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range;
1452         ss_data_cur->percentage =
1453                 ss_info_cur->spread_spectrum_percentage;
1454         ss_data_cur->percentage_divider =
1455                 ss_info_cur->spread_percentage_divider;
1456         ss_data_cur->modulation_freq_hz =
1457                 ss_info_cur->spread_spectrum_range;
1458 
1459         if (ss_info_cur->type.CENTER_MODE)
1460             ss_data_cur->flags.CENTER_SPREAD = 1;
1461 
1462         if (ss_info_cur->type.EXTERNAL)
1463             ss_data_cur->flags.EXTERNAL_SS = 1;
1464 
1465     }
1466 
1467     *spread_spectrum_data = ss_data;
1468     kfree(ss_info);
1469     return;
1470 
1471 out_free_data:
1472     kfree(ss_data);
1473     *ss_entries_num = 0;
1474 out_free_info:
1475     kfree(ss_info);
1476 }
1477 
1478 static void ss_info_from_atombios_create(
1479     struct dce110_clk_src *clk_src)
1480 {
1481     get_ss_info_from_atombios(
1482         clk_src,
1483         AS_SIGNAL_TYPE_DISPLAY_PORT,
1484         &clk_src->dp_ss_params,
1485         &clk_src->dp_ss_params_cnt);
1486     get_ss_info_from_atombios(
1487         clk_src,
1488         AS_SIGNAL_TYPE_HDMI,
1489         &clk_src->hdmi_ss_params,
1490         &clk_src->hdmi_ss_params_cnt);
1491     get_ss_info_from_atombios(
1492         clk_src,
1493         AS_SIGNAL_TYPE_DVI,
1494         &clk_src->dvi_ss_params,
1495         &clk_src->dvi_ss_params_cnt);
1496     get_ss_info_from_atombios(
1497         clk_src,
1498         AS_SIGNAL_TYPE_LVDS,
1499         &clk_src->lvds_ss_params,
1500         &clk_src->lvds_ss_params_cnt);
1501 }
1502 
1503 static bool calc_pll_max_vco_construct(
1504             struct calc_pll_clock_source *calc_pll_cs,
1505             struct calc_pll_clock_source_init_data *init_data)
1506 {
1507     uint32_t i;
1508     struct dc_firmware_info *fw_info;
1509     if (calc_pll_cs == NULL ||
1510             init_data == NULL ||
1511             init_data->bp == NULL)
1512         return false;
1513 
1514     if (!init_data->bp->fw_info_valid)
1515         return false;
1516 
1517     fw_info = &init_data->bp->fw_info;
1518     calc_pll_cs->ctx = init_data->ctx;
1519     calc_pll_cs->ref_freq_khz = fw_info->pll_info.crystal_frequency;
1520     calc_pll_cs->min_vco_khz =
1521             fw_info->pll_info.min_output_pxl_clk_pll_frequency;
1522     calc_pll_cs->max_vco_khz =
1523             fw_info->pll_info.max_output_pxl_clk_pll_frequency;
1524 
1525     if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0)
1526         calc_pll_cs->max_pll_input_freq_khz =
1527             init_data->max_override_input_pxl_clk_pll_freq_khz;
1528     else
1529         calc_pll_cs->max_pll_input_freq_khz =
1530             fw_info->pll_info.max_input_pxl_clk_pll_frequency;
1531 
1532     if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0)
1533         calc_pll_cs->min_pll_input_freq_khz =
1534             init_data->min_override_input_pxl_clk_pll_freq_khz;
1535     else
1536         calc_pll_cs->min_pll_input_freq_khz =
1537             fw_info->pll_info.min_input_pxl_clk_pll_frequency;
1538 
1539     calc_pll_cs->min_pix_clock_pll_post_divider =
1540             init_data->min_pix_clk_pll_post_divider;
1541     calc_pll_cs->max_pix_clock_pll_post_divider =
1542             init_data->max_pix_clk_pll_post_divider;
1543     calc_pll_cs->min_pll_ref_divider =
1544             init_data->min_pll_ref_divider;
1545     calc_pll_cs->max_pll_ref_divider =
1546             init_data->max_pll_ref_divider;
1547 
1548     if (init_data->num_fract_fb_divider_decimal_point == 0 ||
1549         init_data->num_fract_fb_divider_decimal_point_precision >
1550                 init_data->num_fract_fb_divider_decimal_point) {
1551         DC_LOG_ERROR(
1552             "The dec point num or precision is incorrect!");
1553         return false;
1554     }
1555     if (init_data->num_fract_fb_divider_decimal_point_precision == 0) {
1556         DC_LOG_ERROR(
1557             "Incorrect fract feedback divider precision num!");
1558         return false;
1559     }
1560 
1561     calc_pll_cs->fract_fb_divider_decimal_points_num =
1562                 init_data->num_fract_fb_divider_decimal_point;
1563     calc_pll_cs->fract_fb_divider_precision =
1564             init_data->num_fract_fb_divider_decimal_point_precision;
1565     calc_pll_cs->fract_fb_divider_factor = 1;
1566     for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i)
1567         calc_pll_cs->fract_fb_divider_factor *= 10;
1568 
1569     calc_pll_cs->fract_fb_divider_precision_factor = 1;
1570     for (
1571         i = 0;
1572         i < (calc_pll_cs->fract_fb_divider_decimal_points_num -
1573                 calc_pll_cs->fract_fb_divider_precision);
1574         ++i)
1575         calc_pll_cs->fract_fb_divider_precision_factor *= 10;
1576 
1577     return true;
1578 }
1579 
1580 bool dce110_clk_src_construct(
1581     struct dce110_clk_src *clk_src,
1582     struct dc_context *ctx,
1583     struct dc_bios *bios,
1584     enum clock_source_id id,
1585     const struct dce110_clk_src_regs *regs,
1586     const struct dce110_clk_src_shift *cs_shift,
1587     const struct dce110_clk_src_mask *cs_mask)
1588 {
1589     struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi;
1590     struct calc_pll_clock_source_init_data calc_pll_cs_init_data;
1591 
1592     clk_src->base.ctx = ctx;
1593     clk_src->bios = bios;
1594     clk_src->base.id = id;
1595     clk_src->base.funcs = &dce110_clk_src_funcs;
1596 
1597     clk_src->regs = regs;
1598     clk_src->cs_shift = cs_shift;
1599     clk_src->cs_mask = cs_mask;
1600 
1601     if (!clk_src->bios->fw_info_valid) {
1602         ASSERT_CRITICAL(false);
1603         goto unexpected_failure;
1604     }
1605 
1606     clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp;
1607 
1608     /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1609     calc_pll_cs_init_data.bp = bios;
1610     calc_pll_cs_init_data.min_pix_clk_pll_post_divider = 1;
1611     calc_pll_cs_init_data.max_pix_clk_pll_post_divider =
1612             clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1613     calc_pll_cs_init_data.min_pll_ref_divider = 1;
1614     calc_pll_cs_init_data.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV;
1615     /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1616     calc_pll_cs_init_data.min_override_input_pxl_clk_pll_freq_khz = 0;
1617     /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1618     calc_pll_cs_init_data.max_override_input_pxl_clk_pll_freq_khz = 0;
1619     /*numberOfFractFBDividerDecimalPoints*/
1620     calc_pll_cs_init_data.num_fract_fb_divider_decimal_point =
1621             FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1622     /*number of decimal point to round off for fractional feedback divider value*/
1623     calc_pll_cs_init_data.num_fract_fb_divider_decimal_point_precision =
1624             FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1625     calc_pll_cs_init_data.ctx = ctx;
1626 
1627     /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1628     calc_pll_cs_init_data_hdmi.bp = bios;
1629     calc_pll_cs_init_data_hdmi.min_pix_clk_pll_post_divider = 1;
1630     calc_pll_cs_init_data_hdmi.max_pix_clk_pll_post_divider =
1631             clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1632     calc_pll_cs_init_data_hdmi.min_pll_ref_divider = 1;
1633     calc_pll_cs_init_data_hdmi.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV;
1634     /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1635     calc_pll_cs_init_data_hdmi.min_override_input_pxl_clk_pll_freq_khz = 13500;
1636     /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1637     calc_pll_cs_init_data_hdmi.max_override_input_pxl_clk_pll_freq_khz = 27000;
1638     /*numberOfFractFBDividerDecimalPoints*/
1639     calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point =
1640             FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1641     /*number of decimal point to round off for fractional feedback divider value*/
1642     calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point_precision =
1643             FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1644     calc_pll_cs_init_data_hdmi.ctx = ctx;
1645 
1646     clk_src->ref_freq_khz = clk_src->bios->fw_info.pll_info.crystal_frequency;
1647 
1648     if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL)
1649         return true;
1650 
1651     /* PLL only from here on */
1652     ss_info_from_atombios_create(clk_src);
1653 
1654     if (!calc_pll_max_vco_construct(
1655             &clk_src->calc_pll,
1656             &calc_pll_cs_init_data)) {
1657         ASSERT_CRITICAL(false);
1658         goto unexpected_failure;
1659     }
1660 
1661 
1662     calc_pll_cs_init_data_hdmi.
1663             min_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz/2;
1664     calc_pll_cs_init_data_hdmi.
1665             max_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz;
1666 
1667 
1668     if (!calc_pll_max_vco_construct(
1669             &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
1670         ASSERT_CRITICAL(false);
1671         goto unexpected_failure;
1672     }
1673 
1674     return true;
1675 
1676 unexpected_failure:
1677     return false;
1678 }
1679 
1680 bool dce112_clk_src_construct(
1681     struct dce110_clk_src *clk_src,
1682     struct dc_context *ctx,
1683     struct dc_bios *bios,
1684     enum clock_source_id id,
1685     const struct dce110_clk_src_regs *regs,
1686     const struct dce110_clk_src_shift *cs_shift,
1687     const struct dce110_clk_src_mask *cs_mask)
1688 {
1689     clk_src->base.ctx = ctx;
1690     clk_src->bios = bios;
1691     clk_src->base.id = id;
1692     clk_src->base.funcs = &dce112_clk_src_funcs;
1693 
1694     clk_src->regs = regs;
1695     clk_src->cs_shift = cs_shift;
1696     clk_src->cs_mask = cs_mask;
1697 
1698     if (!clk_src->bios->fw_info_valid) {
1699         ASSERT_CRITICAL(false);
1700         return false;
1701     }
1702 
1703     clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp;
1704 
1705     return true;
1706 }
1707 
1708 bool dcn20_clk_src_construct(
1709     struct dce110_clk_src *clk_src,
1710     struct dc_context *ctx,
1711     struct dc_bios *bios,
1712     enum clock_source_id id,
1713     const struct dce110_clk_src_regs *regs,
1714     const struct dce110_clk_src_shift *cs_shift,
1715     const struct dce110_clk_src_mask *cs_mask)
1716 {
1717     bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1718 
1719     clk_src->base.funcs = &dcn20_clk_src_funcs;
1720 
1721     return ret;
1722 }
1723 
1724 bool dcn3_clk_src_construct(
1725     struct dce110_clk_src *clk_src,
1726     struct dc_context *ctx,
1727     struct dc_bios *bios,
1728     enum clock_source_id id,
1729     const struct dce110_clk_src_regs *regs,
1730     const struct dce110_clk_src_shift *cs_shift,
1731     const struct dce110_clk_src_mask *cs_mask)
1732 {
1733     bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1734 
1735     clk_src->base.funcs = &dcn3_clk_src_funcs;
1736 
1737     return ret;
1738 }
1739 
1740 bool dcn31_clk_src_construct(
1741     struct dce110_clk_src *clk_src,
1742     struct dc_context *ctx,
1743     struct dc_bios *bios,
1744     enum clock_source_id id,
1745     const struct dce110_clk_src_regs *regs,
1746     const struct dce110_clk_src_shift *cs_shift,
1747     const struct dce110_clk_src_mask *cs_mask)
1748 {
1749     bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1750 
1751     clk_src->base.funcs = &dcn31_clk_src_funcs;
1752 
1753     return ret;
1754 }
1755 
1756 bool dcn301_clk_src_construct(
1757     struct dce110_clk_src *clk_src,
1758     struct dc_context *ctx,
1759     struct dc_bios *bios,
1760     enum clock_source_id id,
1761     const struct dce110_clk_src_regs *regs,
1762     const struct dce110_clk_src_shift *cs_shift,
1763     const struct dce110_clk_src_mask *cs_mask)
1764 {
1765     bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1766 
1767     clk_src->base.funcs = &dcn3_clk_src_funcs;
1768 
1769     return ret;
1770 }