linux/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012-16 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 "dce_clocks.h"
  27#include "dm_services.h"
  28#include "reg_helper.h"
  29#include "fixed32_32.h"
  30#include "bios_parser_interface.h"
  31#include "dc.h"
  32#include "dmcu.h"
  33#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
  34#include "dcn_calcs.h"
  35#endif
  36#include "core_types.h"
  37
  38
  39#define TO_DCE_CLOCKS(clocks)\
  40        container_of(clocks, struct dce_disp_clk, base)
  41
  42#define REG(reg) \
  43        (clk_dce->regs->reg)
  44
  45#undef FN
  46#define FN(reg_name, field_name) \
  47        clk_dce->clk_shift->field_name, clk_dce->clk_mask->field_name
  48
  49#define CTX \
  50        clk_dce->base.ctx
  51
  52/* Max clock values for each state indexed by "enum clocks_state": */
  53static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
  54/* ClocksStateInvalid - should not be used */
  55{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
  56/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
  57{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
  58/* ClocksStateLow */
  59{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
  60/* ClocksStateNominal */
  61{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
  62/* ClocksStatePerformance */
  63{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
  64
  65static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
  66/*ClocksStateInvalid - should not be used*/
  67{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
  68/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
  69{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
  70/*ClocksStateLow*/
  71{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
  72/*ClocksStateNominal*/
  73{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
  74/*ClocksStatePerformance*/
  75{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
  76
  77static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
  78/*ClocksStateInvalid - should not be used*/
  79{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
  80/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
  81{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
  82/*ClocksStateLow*/
  83{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
  84/*ClocksStateNominal*/
  85{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
  86/*ClocksStatePerformance*/
  87{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
  88
  89static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
  90/*ClocksStateInvalid - should not be used*/
  91{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
  92/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
  93{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
  94/*ClocksStateLow*/
  95{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
  96/*ClocksStateNominal*/
  97{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
  98/*ClocksStatePerformance*/
  99{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
 100
 101/* Starting point for each divider range.*/
 102enum dce_divider_range_start {
 103        DIVIDER_RANGE_01_START = 200, /* 2.00*/
 104        DIVIDER_RANGE_02_START = 1600, /* 16.00*/
 105        DIVIDER_RANGE_03_START = 3200, /* 32.00*/
 106        DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/
 107};
 108
 109/* Ranges for divider identifiers (Divider ID or DID)
 110 mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/
 111enum dce_divider_id_register_setting {
 112        DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08,
 113        DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40,
 114        DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60,
 115        DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80
 116};
 117
 118/* Step size between each divider within a range.
 119 Incrementing the DENTIST_DISPCLK_WDIVIDER by one
 120 will increment the divider by this much.*/
 121enum dce_divider_range_step_size {
 122        DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/
 123        DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/
 124        DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */
 125};
 126
 127static bool dce_divider_range_construct(
 128        struct dce_divider_range *div_range,
 129        int range_start,
 130        int range_step,
 131        int did_min,
 132        int did_max)
 133{
 134        div_range->div_range_start = range_start;
 135        div_range->div_range_step = range_step;
 136        div_range->did_min = did_min;
 137        div_range->did_max = did_max;
 138
 139        if (div_range->div_range_step == 0) {
 140                div_range->div_range_step = 1;
 141                /*div_range_step cannot be zero*/
 142                BREAK_TO_DEBUGGER();
 143        }
 144        /* Calculate this based on the other inputs.*/
 145        /* See DividerRange.h for explanation of */
 146        /* the relationship between divider id (DID) and a divider.*/
 147        /* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/
 148        /* Maximum divider identified in this range =
 149         * (Number of Divider IDs)*Step size between dividers
 150         *  + The start of this range.*/
 151        div_range->div_range_end = (did_max - did_min) * range_step
 152                + range_start;
 153        return true;
 154}
 155
 156static int dce_divider_range_calc_divider(
 157        struct dce_divider_range *div_range,
 158        int did)
 159{
 160        /* Is this DID within our range?*/
 161        if ((did < div_range->did_min) || (did >= div_range->did_max))
 162                return INVALID_DIVIDER;
 163
 164        return ((did - div_range->did_min) * div_range->div_range_step)
 165                        + div_range->div_range_start;
 166
 167}
 168
 169static int dce_divider_range_get_divider(
 170        struct dce_divider_range *div_range,
 171        int ranges_num,
 172        int did)
 173{
 174        int div = INVALID_DIVIDER;
 175        int i;
 176
 177        for (i = 0; i < ranges_num; i++) {
 178                /* Calculate divider with given divider ID*/
 179                div = dce_divider_range_calc_divider(&div_range[i], did);
 180                /* Found a valid return divider*/
 181                if (div != INVALID_DIVIDER)
 182                        break;
 183        }
 184        return div;
 185}
 186
 187static int dce_clocks_get_dp_ref_freq(struct display_clock *clk)
 188{
 189        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
 190        int dprefclk_wdivider;
 191        int dprefclk_src_sel;
 192        int dp_ref_clk_khz = 600000;
 193        int target_div = INVALID_DIVIDER;
 194
 195        /* ASSERT DP Reference Clock source is from DFS*/
 196        REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
 197        ASSERT(dprefclk_src_sel == 0);
 198
 199        /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
 200         * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
 201        REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
 202
 203        /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
 204        target_div = dce_divider_range_get_divider(
 205                        clk_dce->divider_ranges,
 206                        DIVIDER_RANGE_MAX,
 207                        dprefclk_wdivider);
 208
 209        if (target_div != INVALID_DIVIDER) {
 210                /* Calculate the current DFS clock, in kHz.*/
 211                dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR
 212                        * clk_dce->dentist_vco_freq_khz) / target_div;
 213        }
 214
 215        /* SW will adjust DP REF Clock average value for all purposes
 216         * (DP DTO / DP Audio DTO and DP GTC)
 217         if clock is spread for all cases:
 218         -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
 219         calculations for DS_INCR/DS_MODULO (this is planned to be default case)
 220         -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
 221         calculations (not planned to be used, but average clock should still
 222         be valid)
 223         -if SS enabled on DP Ref clock and HW de-spreading disabled
 224         (should not be case with CIK) then SW should program all rates
 225         generated according to average value (case as with previous ASICs)
 226          */
 227        if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) {
 228                struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
 229                                dal_fixed32_32_from_fraction(
 230                                                clk_dce->dprefclk_ss_percentage,
 231                                                clk_dce->dprefclk_ss_divider), 200);
 232                struct fixed32_32 adj_dp_ref_clk_khz;
 233
 234                ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
 235                                                                ss_percentage);
 236                adj_dp_ref_clk_khz =
 237                        dal_fixed32_32_mul_int(
 238                                ss_percentage,
 239                                dp_ref_clk_khz);
 240                dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
 241        }
 242
 243        return dp_ref_clk_khz;
 244}
 245
 246/* TODO: This is DCN DPREFCLK: it could be program by DENTIST by VBIOS
 247 * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit
 248 * clock implementation
 249 */
 250static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk)
 251{
 252        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
 253        int dp_ref_clk_khz = 600000;
 254
 255        if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) {
 256                struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
 257                                dal_fixed32_32_from_fraction(
 258                                                clk_dce->dprefclk_ss_percentage,
 259                                                clk_dce->dprefclk_ss_divider), 200);
 260                struct fixed32_32 adj_dp_ref_clk_khz;
 261
 262                ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
 263                                                                ss_percentage);
 264                adj_dp_ref_clk_khz =
 265                        dal_fixed32_32_mul_int(
 266                                ss_percentage,
 267                                dp_ref_clk_khz);
 268                dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
 269        }
 270
 271        return dp_ref_clk_khz;
 272}
 273static enum dm_pp_clocks_state dce_get_required_clocks_state(
 274        struct display_clock *clk,
 275        struct state_dependent_clocks *req_clocks)
 276{
 277        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
 278        int i;
 279        enum dm_pp_clocks_state low_req_clk;
 280
 281        /* Iterate from highest supported to lowest valid state, and update
 282         * lowest RequiredState with the lowest state that satisfies
 283         * all required clocks
 284         */
 285        for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
 286                if (req_clocks->display_clk_khz >
 287                                clk_dce->max_clks_by_state[i].display_clk_khz
 288                        || req_clocks->pixel_clk_khz >
 289                                clk_dce->max_clks_by_state[i].pixel_clk_khz)
 290                        break;
 291
 292        low_req_clk = i + 1;
 293        if (low_req_clk > clk->max_clks_state) {
 294                dm_logger_write(clk->ctx->logger, LOG_WARNING,
 295                                "%s: clocks unsupported", __func__);
 296                low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
 297        }
 298
 299        return low_req_clk;
 300}
 301
 302static bool dce_clock_set_min_clocks_state(
 303        struct display_clock *clk,
 304        enum dm_pp_clocks_state clocks_state)
 305{
 306        struct dm_pp_power_level_change_request level_change_req = {
 307                        clocks_state };
 308
 309        if (clocks_state > clk->max_clks_state) {
 310                /*Requested state exceeds max supported state.*/
 311                dm_logger_write(clk->ctx->logger, LOG_WARNING,
 312                                "Requested state exceeds max supported state");
 313                return false;
 314        } else if (clocks_state == clk->cur_min_clks_state) {
 315                /*if we're trying to set the same state, we can just return
 316                 * since nothing needs to be done*/
 317                return true;
 318        }
 319
 320        /* get max clock state from PPLIB */
 321        if (dm_pp_apply_power_level_change_request(clk->ctx, &level_change_req))
 322                clk->cur_min_clks_state = clocks_state;
 323
 324        return true;
 325}
 326
 327static int dce_set_clock(
 328        struct display_clock *clk,
 329        int requested_clk_khz)
 330{
 331        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
 332        struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
 333        struct dc_bios *bp = clk->ctx->dc_bios;
 334        int actual_clock = requested_clk_khz;
 335
 336        /* Make sure requested clock isn't lower than minimum threshold*/
 337        if (requested_clk_khz > 0)
 338                requested_clk_khz = max(requested_clk_khz,
 339                                clk_dce->dentist_vco_freq_khz / 64);
 340
 341        /* Prepare to program display clock*/
 342        pxl_clk_params.target_pixel_clock = requested_clk_khz;
 343        pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
 344
 345        bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
 346
 347        if (clk_dce->dfs_bypass_enabled) {
 348
 349                /* Cache the fixed display clock*/
 350                clk_dce->dfs_bypass_disp_clk =
 351                        pxl_clk_params.dfs_bypass_display_clock;
 352                actual_clock = pxl_clk_params.dfs_bypass_display_clock;
 353        }
 354
 355        /* from power down, we need mark the clock state as ClocksStateNominal
 356         * from HWReset, so when resume we will call pplib voltage regulator.*/
 357        if (requested_clk_khz == 0)
 358                clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
 359        return actual_clock;
 360}
 361
 362static int dce_psr_set_clock(
 363        struct display_clock *clk,
 364        int requested_clk_khz)
 365{
 366        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
 367        struct dc_context *ctx = clk_dce->base.ctx;
 368        struct dc *core_dc = ctx->dc;
 369        struct dmcu *dmcu = core_dc->res_pool->dmcu;
 370        int actual_clk_khz = requested_clk_khz;
 371
 372        actual_clk_khz = dce_set_clock(clk, requested_clk_khz);
 373
 374        dmcu->funcs->set_psr_wait_loop(dmcu, actual_clk_khz / 1000 / 7);
 375        return actual_clk_khz;
 376}
 377
 378static int dce112_set_clock(
 379        struct display_clock *clk,
 380        int requested_clk_khz)
 381{
 382        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
 383        struct bp_set_dce_clock_parameters dce_clk_params;
 384        struct dc_bios *bp = clk->ctx->dc_bios;
 385        struct dc *core_dc = clk->ctx->dc;
 386        struct dmcu *dmcu = core_dc->res_pool->dmcu;
 387        int actual_clock = requested_clk_khz;
 388        /* Prepare to program display clock*/
 389        memset(&dce_clk_params, 0, sizeof(dce_clk_params));
 390
 391        /* Make sure requested clock isn't lower than minimum threshold*/
 392        if (requested_clk_khz > 0)
 393                requested_clk_khz = max(requested_clk_khz,
 394                                clk_dce->dentist_vco_freq_khz / 62);
 395
 396        dce_clk_params.target_clock_frequency = requested_clk_khz;
 397        dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
 398        dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
 399
 400        bp->funcs->set_dce_clock(bp, &dce_clk_params);
 401        actual_clock = dce_clk_params.target_clock_frequency;
 402
 403        /* from power down, we need mark the clock state as ClocksStateNominal
 404         * from HWReset, so when resume we will call pplib voltage regulator.*/
 405        if (requested_clk_khz == 0)
 406                clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
 407
 408        /*Program DP ref Clock*/
 409        /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
 410        dce_clk_params.target_clock_frequency = 0;
 411        dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
 412        dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
 413                        (dce_clk_params.pll_id ==
 414                                        CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
 415
 416        bp->funcs->set_dce_clock(bp, &dce_clk_params);
 417
 418        if (clk_dce->dfs_bypass_disp_clk != actual_clock)
 419                dmcu->funcs->set_psr_wait_loop(dmcu,
 420                                actual_clock / 1000 / 7);
 421        clk_dce->dfs_bypass_disp_clk = actual_clock;
 422        return actual_clock;
 423}
 424
 425static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce)
 426{
 427        struct dc_debug *debug = &clk_dce->base.ctx->dc->debug;
 428        struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
 429        struct integrated_info info = { { { 0 } } };
 430        struct dc_firmware_info fw_info = { { 0 } };
 431        int i;
 432
 433        if (bp->integrated_info)
 434                info = *bp->integrated_info;
 435
 436        clk_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
 437        if (clk_dce->dentist_vco_freq_khz == 0) {
 438                bp->funcs->get_firmware_info(bp, &fw_info);
 439                clk_dce->dentist_vco_freq_khz =
 440                        fw_info.smu_gpu_pll_output_freq;
 441                if (clk_dce->dentist_vco_freq_khz == 0)
 442                        clk_dce->dentist_vco_freq_khz = 3600000;
 443        }
 444
 445        /*update the maximum display clock for each power state*/
 446        for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
 447                enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
 448
 449                switch (i) {
 450                case 0:
 451                        clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
 452                        break;
 453
 454                case 1:
 455                        clk_state = DM_PP_CLOCKS_STATE_LOW;
 456                        break;
 457
 458                case 2:
 459                        clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
 460                        break;
 461
 462                case 3:
 463                        clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
 464                        break;
 465
 466                default:
 467                        clk_state = DM_PP_CLOCKS_STATE_INVALID;
 468                        break;
 469                }
 470
 471                /*Do not allow bad VBIOS/SBIOS to override with invalid values,
 472                 * check for > 100MHz*/
 473                if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
 474                        clk_dce->max_clks_by_state[clk_state].display_clk_khz =
 475                                info.disp_clk_voltage[i].max_supported_clk;
 476        }
 477
 478        if (!debug->disable_dfs_bypass && bp->integrated_info)
 479                if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
 480                        clk_dce->dfs_bypass_enabled = true;
 481
 482        clk_dce->use_max_disp_clk = debug->max_disp_clk;
 483}
 484
 485static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce)
 486{
 487        struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
 488        int ss_info_num = bp->funcs->get_ss_entry_number(
 489                        bp, AS_SIGNAL_TYPE_GPU_PLL);
 490
 491        if (ss_info_num) {
 492                struct spread_spectrum_info info = { { 0 } };
 493                enum bp_result result = bp->funcs->get_spread_spectrum_info(
 494                                bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
 495
 496                /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
 497                 * even if SS not enabled and in that case
 498                 * SSInfo.spreadSpectrumPercentage !=0 would be sign
 499                 * that SS is enabled
 500                 */
 501                if (result == BP_RESULT_OK &&
 502                                info.spread_spectrum_percentage != 0) {
 503                        clk_dce->ss_on_dprefclk = true;
 504                        clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
 505
 506                        if (info.type.CENTER_MODE == 0) {
 507                                /* TODO: Currently for DP Reference clock we
 508                                 * need only SS percentage for
 509                                 * downspread */
 510                                clk_dce->dprefclk_ss_percentage =
 511                                                info.spread_spectrum_percentage;
 512                        }
 513
 514                        return;
 515                }
 516
 517                result = bp->funcs->get_spread_spectrum_info(
 518                                bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
 519
 520                /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
 521                 * even if SS not enabled and in that case
 522                 * SSInfo.spreadSpectrumPercentage !=0 would be sign
 523                 * that SS is enabled
 524                 */
 525                if (result == BP_RESULT_OK &&
 526                                info.spread_spectrum_percentage != 0) {
 527                        clk_dce->ss_on_dprefclk = true;
 528                        clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
 529
 530                        if (info.type.CENTER_MODE == 0) {
 531                                /* Currently for DP Reference clock we
 532                                 * need only SS percentage for
 533                                 * downspread */
 534                                clk_dce->dprefclk_ss_percentage =
 535                                                info.spread_spectrum_percentage;
 536                        }
 537                }
 538        }
 539}
 540
 541static bool dce_apply_clock_voltage_request(
 542        struct display_clock *clk,
 543        enum dm_pp_clock_type clocks_type,
 544        int clocks_in_khz,
 545        bool pre_mode_set,
 546        bool update_dp_phyclk)
 547{
 548        bool send_request = false;
 549        struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
 550
 551        switch (clocks_type) {
 552        case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
 553        case DM_PP_CLOCK_TYPE_PIXELCLK:
 554        case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK:
 555                break;
 556        default:
 557                BREAK_TO_DEBUGGER();
 558                return false;
 559        }
 560
 561        clock_voltage_req.clk_type = clocks_type;
 562        clock_voltage_req.clocks_in_khz = clocks_in_khz;
 563
 564        /* to pplib */
 565        if (pre_mode_set) {
 566                switch (clocks_type) {
 567                case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
 568                        if (clocks_in_khz > clk->cur_clocks_value.dispclk_in_khz) {
 569                                clk->cur_clocks_value.dispclk_notify_pplib_done = true;
 570                                send_request = true;
 571                        } else
 572                                clk->cur_clocks_value.dispclk_notify_pplib_done = false;
 573                        /* no matter incrase or decrase clock, update current clock value */
 574                        clk->cur_clocks_value.dispclk_in_khz = clocks_in_khz;
 575                        break;
 576                case DM_PP_CLOCK_TYPE_PIXELCLK:
 577                        if (clocks_in_khz > clk->cur_clocks_value.max_pixelclk_in_khz) {
 578                                clk->cur_clocks_value.pixelclk_notify_pplib_done = true;
 579                                send_request = true;
 580                        } else
 581                                clk->cur_clocks_value.pixelclk_notify_pplib_done = false;
 582                        /* no matter incrase or decrase clock, update current clock value */
 583                        clk->cur_clocks_value.max_pixelclk_in_khz = clocks_in_khz;
 584                        break;
 585                case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK:
 586                        if (clocks_in_khz > clk->cur_clocks_value.max_non_dp_phyclk_in_khz) {
 587                                clk->cur_clocks_value.phyclk_notigy_pplib_done = true;
 588                                send_request = true;
 589                        } else
 590                                clk->cur_clocks_value.phyclk_notigy_pplib_done = false;
 591                        /* no matter incrase or decrase clock, update current clock value */
 592                        clk->cur_clocks_value.max_non_dp_phyclk_in_khz = clocks_in_khz;
 593                        break;
 594                default:
 595                        ASSERT(0);
 596                        break;
 597                }
 598
 599        } else {
 600                switch (clocks_type) {
 601                case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
 602                        if (!clk->cur_clocks_value.dispclk_notify_pplib_done)
 603                                send_request = true;
 604                        break;
 605                case DM_PP_CLOCK_TYPE_PIXELCLK:
 606                        if (!clk->cur_clocks_value.pixelclk_notify_pplib_done)
 607                                send_request = true;
 608                        break;
 609                case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK:
 610                        if (!clk->cur_clocks_value.phyclk_notigy_pplib_done)
 611                                send_request = true;
 612                        break;
 613                default:
 614                        ASSERT(0);
 615                        break;
 616                }
 617        }
 618        if (send_request) {
 619#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
 620                if (clk->ctx->dce_version >= DCN_VERSION_1_0) {
 621                        struct dc *core_dc = clk->ctx->dc;
 622                        /*use dcfclk request voltage*/
 623                        clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
 624                        clock_voltage_req.clocks_in_khz =
 625                                dcn_find_dcfclk_suits_all(core_dc, &clk->cur_clocks_value);
 626                }
 627#endif
 628                dm_pp_apply_clock_for_voltage_request(
 629                        clk->ctx, &clock_voltage_req);
 630        }
 631        if (update_dp_phyclk && (clocks_in_khz >
 632        clk->cur_clocks_value.max_dp_phyclk_in_khz))
 633                clk->cur_clocks_value.max_dp_phyclk_in_khz = clocks_in_khz;
 634
 635        return true;
 636}
 637
 638
 639static const struct display_clock_funcs dce120_funcs = {
 640        .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround,
 641        .apply_clock_voltage_request = dce_apply_clock_voltage_request,
 642        .set_clock = dce112_set_clock
 643};
 644
 645static const struct display_clock_funcs dce112_funcs = {
 646        .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq,
 647        .get_required_clocks_state = dce_get_required_clocks_state,
 648        .set_min_clocks_state = dce_clock_set_min_clocks_state,
 649        .set_clock = dce112_set_clock
 650};
 651
 652static const struct display_clock_funcs dce110_funcs = {
 653        .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq,
 654        .get_required_clocks_state = dce_get_required_clocks_state,
 655        .set_min_clocks_state = dce_clock_set_min_clocks_state,
 656        .set_clock = dce_psr_set_clock
 657};
 658
 659static const struct display_clock_funcs dce_funcs = {
 660        .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq,
 661        .get_required_clocks_state = dce_get_required_clocks_state,
 662        .set_min_clocks_state = dce_clock_set_min_clocks_state,
 663        .set_clock = dce_set_clock
 664};
 665
 666static void dce_disp_clk_construct(
 667        struct dce_disp_clk *clk_dce,
 668        struct dc_context *ctx,
 669        const struct dce_disp_clk_registers *regs,
 670        const struct dce_disp_clk_shift *clk_shift,
 671        const struct dce_disp_clk_mask *clk_mask)
 672{
 673        struct display_clock *base = &clk_dce->base;
 674
 675        base->ctx = ctx;
 676        base->funcs = &dce_funcs;
 677
 678        clk_dce->regs = regs;
 679        clk_dce->clk_shift = clk_shift;
 680        clk_dce->clk_mask = clk_mask;
 681
 682        clk_dce->dfs_bypass_disp_clk = 0;
 683
 684        clk_dce->dprefclk_ss_percentage = 0;
 685        clk_dce->dprefclk_ss_divider = 1000;
 686        clk_dce->ss_on_dprefclk = false;
 687
 688        base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
 689        base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
 690
 691        dce_clock_read_integrated_info(clk_dce);
 692        dce_clock_read_ss_info(clk_dce);
 693
 694        dce_divider_range_construct(
 695                &clk_dce->divider_ranges[DIVIDER_RANGE_01],
 696                DIVIDER_RANGE_01_START,
 697                DIVIDER_RANGE_01_STEP_SIZE,
 698                DIVIDER_RANGE_01_BASE_DIVIDER_ID,
 699                DIVIDER_RANGE_02_BASE_DIVIDER_ID);
 700        dce_divider_range_construct(
 701                &clk_dce->divider_ranges[DIVIDER_RANGE_02],
 702                DIVIDER_RANGE_02_START,
 703                DIVIDER_RANGE_02_STEP_SIZE,
 704                DIVIDER_RANGE_02_BASE_DIVIDER_ID,
 705                DIVIDER_RANGE_03_BASE_DIVIDER_ID);
 706        dce_divider_range_construct(
 707                &clk_dce->divider_ranges[DIVIDER_RANGE_03],
 708                DIVIDER_RANGE_03_START,
 709                DIVIDER_RANGE_03_STEP_SIZE,
 710                DIVIDER_RANGE_03_BASE_DIVIDER_ID,
 711                DIVIDER_RANGE_MAX_DIVIDER_ID);
 712}
 713
 714struct display_clock *dce_disp_clk_create(
 715        struct dc_context *ctx,
 716        const struct dce_disp_clk_registers *regs,
 717        const struct dce_disp_clk_shift *clk_shift,
 718        const struct dce_disp_clk_mask *clk_mask)
 719{
 720        struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
 721
 722        if (clk_dce == NULL) {
 723                BREAK_TO_DEBUGGER();
 724                return NULL;
 725        }
 726
 727        memcpy(clk_dce->max_clks_by_state,
 728                dce80_max_clks_by_state,
 729                sizeof(dce80_max_clks_by_state));
 730
 731        dce_disp_clk_construct(
 732                clk_dce, ctx, regs, clk_shift, clk_mask);
 733
 734        return &clk_dce->base;
 735}
 736
 737struct display_clock *dce110_disp_clk_create(
 738        struct dc_context *ctx,
 739        const struct dce_disp_clk_registers *regs,
 740        const struct dce_disp_clk_shift *clk_shift,
 741        const struct dce_disp_clk_mask *clk_mask)
 742{
 743        struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
 744
 745        if (clk_dce == NULL) {
 746                BREAK_TO_DEBUGGER();
 747                return NULL;
 748        }
 749
 750        memcpy(clk_dce->max_clks_by_state,
 751                dce110_max_clks_by_state,
 752                sizeof(dce110_max_clks_by_state));
 753
 754        dce_disp_clk_construct(
 755                clk_dce, ctx, regs, clk_shift, clk_mask);
 756
 757        clk_dce->base.funcs = &dce110_funcs;
 758
 759        return &clk_dce->base;
 760}
 761
 762struct display_clock *dce112_disp_clk_create(
 763        struct dc_context *ctx,
 764        const struct dce_disp_clk_registers *regs,
 765        const struct dce_disp_clk_shift *clk_shift,
 766        const struct dce_disp_clk_mask *clk_mask)
 767{
 768        struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
 769
 770        if (clk_dce == NULL) {
 771                BREAK_TO_DEBUGGER();
 772                return NULL;
 773        }
 774
 775        memcpy(clk_dce->max_clks_by_state,
 776                dce112_max_clks_by_state,
 777                sizeof(dce112_max_clks_by_state));
 778
 779        dce_disp_clk_construct(
 780                clk_dce, ctx, regs, clk_shift, clk_mask);
 781
 782        clk_dce->base.funcs = &dce112_funcs;
 783
 784        return &clk_dce->base;
 785}
 786
 787struct display_clock *dce120_disp_clk_create(struct dc_context *ctx)
 788{
 789        struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
 790        struct dm_pp_clock_levels_with_voltage clk_level_info = {0};
 791
 792        if (clk_dce == NULL) {
 793                BREAK_TO_DEBUGGER();
 794                return NULL;
 795        }
 796
 797        memcpy(clk_dce->max_clks_by_state,
 798                dce120_max_clks_by_state,
 799                sizeof(dce120_max_clks_by_state));
 800
 801        dce_disp_clk_construct(
 802                clk_dce, ctx, NULL, NULL, NULL);
 803
 804        clk_dce->base.funcs = &dce120_funcs;
 805
 806        /* new in dce120 */
 807        if (!ctx->dc->debug.disable_pplib_clock_request  &&
 808                        dm_pp_get_clock_levels_by_type_with_voltage(
 809                        ctx, DM_PP_CLOCK_TYPE_DISPLAY_CLK, &clk_level_info)
 810                                                && clk_level_info.num_levels)
 811                clk_dce->max_displ_clk_in_khz =
 812                        clk_level_info.data[clk_level_info.num_levels - 1].clocks_in_khz;
 813        else
 814                clk_dce->max_displ_clk_in_khz = 1133000;
 815
 816        return &clk_dce->base;
 817}
 818
 819void dce_disp_clk_destroy(struct display_clock **disp_clk)
 820{
 821        struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(*disp_clk);
 822
 823        kfree(clk_dce);
 824        *disp_clk = NULL;
 825}
 826