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