diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0040-drm-amd-display-consolidate-dce8-11.2-display-clock-.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0040-drm-amd-display-consolidate-dce8-11.2-display-clock-.patch | 2394 |
1 files changed, 2394 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0040-drm-amd-display-consolidate-dce8-11.2-display-clock-.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0040-drm-amd-display-consolidate-dce8-11.2-display-clock-.patch new file mode 100644 index 00000000..784bf005 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0040-drm-amd-display-consolidate-dce8-11.2-display-clock-.patch @@ -0,0 +1,2394 @@ +From fcb5b31058fdc3bbba78871d8311e7e9c8272c1b Mon Sep 17 00:00:00 2001 +From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> +Date: Thu, 1 Dec 2016 18:13:25 -0500 +Subject: [PATCH 0040/4131] drm/amd/display: consolidate dce8-11.2 display + clock code + +Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> +Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> +Acked-by: Harry Wentland <Harry.Wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/display/dc/dce/Makefile | 3 +- + drivers/gpu/drm/amd/display/dc/dce/dce_audio.c | 4 +- + drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 519 +++++++++++++++++++++ + drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h | 133 ++++++ + .../drm/amd/display/dc/dce100/dce100_resource.c | 22 +- + .../drm/amd/display/dc/dce110/dce110_resource.c | 24 +- + .../drm/amd/display/dc/dce112/dce112_resource.c | 28 +- + .../gpu/drm/amd/display/dc/dce80/dce80_resource.c | 70 +-- + drivers/gpu/drm/amd/display/dc/dm_services_types.h | 18 +- + drivers/gpu/drm/amd/display/dc/gpu/Makefile | 15 - + .../display/dc/gpu/dce110/display_clock_dce110.c | 516 -------------------- + .../display/dc/gpu/dce110/display_clock_dce110.h | 50 -- + .../display/dc/gpu/dce112/display_clock_dce112.c | 152 ------ + .../display/dc/gpu/dce112/display_clock_dce112.h | 14 - + .../amd/display/dc/gpu/dce80/display_clock_dce80.c | 430 ----------------- + .../amd/display/dc/gpu/dce80/display_clock_dce80.h | 54 --- + .../amd/display/include/display_clock_interface.h | 15 +- + 17 files changed, 747 insertions(+), 1320 deletions(-) + create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c + create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h + delete mode 100644 drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.c + delete mode 100644 drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.h + delete mode 100644 drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.c + delete mode 100644 drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.h + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile b/drivers/gpu/drm/amd/display/dc/dce/Makefile +index bfca381..6add597 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile +@@ -6,7 +6,8 @@ + # offset/shift/mask stored in dce_hw struct + + DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \ +-dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o ++dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \ ++dce_clocks.o + + + AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE)) +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +index dc44053..2749c8f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +@@ -888,7 +888,9 @@ static const struct audio_funcs funcs = { + + void dce_aud_destroy(struct audio **audio) + { +- dm_free(*audio); ++ struct dce_audio *aud = DCE_AUD(*audio); ++ ++ dm_free(aud); + *audio = NULL; + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +new file mode 100644 +index 0000000..bc1a46b +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +@@ -0,0 +1,519 @@ ++/* ++ * Copyright 2012-16 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include "dce_clocks.h" ++#include "dm_services.h" ++#include "reg_helper.h" ++#include "fixed32_32.h" ++#include "bios_parser_interface.h" ++#include "dc.h" ++ ++ ++#define REG(reg) \ ++ (clk_dce->regs->reg) ++ ++#undef FN ++#define FN(reg_name, field_name) \ ++ clk_dce->clk_shift->field_name, clk_dce->clk_mask->field_name ++ ++#define CTX \ ++ clk_dce->base.ctx ++ ++/* Starting point for each divider range.*/ ++enum divider_range_start { ++ DIVIDER_RANGE_01_START = 200, /* 2.00*/ ++ DIVIDER_RANGE_02_START = 1600, /* 16.00*/ ++ DIVIDER_RANGE_03_START = 3200, /* 32.00*/ ++ DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ ++}; ++ ++/* Ranges for divider identifiers (Divider ID or DID) ++ mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/ ++enum divider_id_register_setting { ++ DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08, ++ DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40, ++ DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60, ++ DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80 ++}; ++ ++/* Step size between each divider within a range. ++ Incrementing the DENTIST_DISPCLK_WDIVIDER by one ++ will increment the divider by this much.*/ ++enum divider_range_step_size { ++ DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/ ++ DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/ ++ DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */ ++}; ++ ++ ++static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) ++{ ++ struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); ++ int dprefclk_wdivider; ++ int dprefclk_src_sel; ++ int dp_ref_clk_khz = 600000; ++ int target_div = INVALID_DIVIDER; ++ ++ /* ASSERT DP Reference Clock source is from DFS*/ ++ REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel); ++ ASSERT(dprefclk_src_sel == 0); ++ ++ /* Read the mmDENTIST_DISPCLK_CNTL to get the currently ++ * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ ++ REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); ++ ++ /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ ++ target_div = dal_divider_range_get_divider( ++ clk_dce->divider_ranges, ++ DIVIDER_RANGE_MAX, ++ dprefclk_wdivider); ++ ++ if (target_div != INVALID_DIVIDER) { ++ /* Calculate the current DFS clock, in kHz.*/ ++ dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR ++ * clk_dce->dentist_vco_freq_khz) / target_div; ++ } ++ ++ /* SW will adjust DP REF Clock average value for all purposes ++ * (DP DTO / DP Audio DTO and DP GTC) ++ if clock is spread for all cases: ++ -if SS enabled on DP Ref clock and HW de-spreading enabled with SW ++ calculations for DS_INCR/DS_MODULO (this is planned to be default case) ++ -if SS enabled on DP Ref clock and HW de-spreading enabled with HW ++ calculations (not planned to be used, but average clock should still ++ be valid) ++ -if SS enabled on DP Ref clock and HW de-spreading disabled ++ (should not be case with CIK) then SW should program all rates ++ generated according to average value (case as with previous ASICs) ++ */ ++ if (clk_dce->ss_on_gpu_pll && clk_dce->gpu_pll_ss_divider != 0) { ++ struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( ++ dal_fixed32_32_from_fraction( ++ clk_dce->gpu_pll_ss_percentage, ++ clk_dce->gpu_pll_ss_divider), 200); ++ struct fixed32_32 adj_dp_ref_clk_khz; ++ ++ ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, ++ ss_percentage); ++ adj_dp_ref_clk_khz = ++ dal_fixed32_32_mul_int( ++ ss_percentage, ++ dp_ref_clk_khz); ++ dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); ++ } ++ ++ return dp_ref_clk_khz; ++} ++ ++static enum dm_pp_clocks_state dce_get_required_clocks_state( ++ struct display_clock *clk, ++ struct state_dependent_clocks *req_clocks) ++{ ++ struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); ++ int i; ++ enum dm_pp_clocks_state low_req_clk; ++ ++ /* Iterate from highest supported to lowest valid state, and update ++ * lowest RequiredState with the lowest state that satisfies ++ * all required clocks ++ */ ++ for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--) ++ if (req_clocks->display_clk_khz > ++ clk_dce->max_clks_by_state[i].display_clk_khz ++ || req_clocks->pixel_clk_khz > ++ clk_dce->max_clks_by_state[i].pixel_clk_khz) ++ break; ++ ++ low_req_clk = i + 1; ++ if (low_req_clk > clk->max_clks_state) { ++ dm_logger_write(clk->ctx->logger, LOG_WARNING, ++ "%s: clocks unsupported", __func__); ++ low_req_clk = DM_PP_CLOCKS_STATE_INVALID; ++ } ++ ++ return low_req_clk; ++} ++ ++static bool dce_clock_set_min_clocks_state( ++ struct display_clock *clk, ++ enum dm_pp_clocks_state clocks_state) ++{ ++ struct dm_pp_power_level_change_request level_change_req = { ++ clocks_state }; ++ ++ if (clocks_state > clk->max_clks_state) { ++ /*Requested state exceeds max supported state.*/ ++ dm_logger_write(clk->ctx->logger, LOG_WARNING, ++ "Requested state exceeds max supported state"); ++ return false; ++ } else if (clocks_state == clk->cur_min_clks_state) { ++ /*if we're trying to set the same state, we can just return ++ * since nothing needs to be done*/ ++ return true; ++ } ++ ++ /* get max clock state from PPLIB */ ++ if (dm_pp_apply_power_level_change_request(clk->ctx, &level_change_req)) ++ clk->cur_min_clks_state = clocks_state; ++ ++ return true; ++} ++ ++static void dce_set_clock( ++ struct display_clock *clk, ++ uint32_t requested_clk_khz) ++{ ++ struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); ++ struct bp_pixel_clock_parameters pxl_clk_params = { 0 }; ++ struct dc_bios *bp = clk->ctx->dc_bios; ++ ++ /* Make sure requested clock isn't lower than minimum threshold*/ ++ if (requested_clk_khz > 0) ++ requested_clk_khz = dm_max(requested_clk_khz, ++ clk_dce->dentist_vco_freq_khz / 64); ++ ++ /* Prepare to program display clock*/ ++ pxl_clk_params.target_pixel_clock = requested_clk_khz; ++ pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS; ++ ++ bp->funcs->program_display_engine_pll(bp, &pxl_clk_params); ++ ++ if (clk_dce->dfs_bypass_enabled) { ++ ++ /* Cache the fixed display clock*/ ++ clk_dce->dfs_bypass_disp_clk = ++ pxl_clk_params.dfs_bypass_display_clock; ++ } ++ ++ /* from power down, we need mark the clock state as ClocksStateNominal ++ * from HWReset, so when resume we will call pplib voltage regulator.*/ ++ if (requested_clk_khz == 0) ++ clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; ++} ++ ++#define PSR_SET_WAITLOOP 0x31 ++ ++union dce110_dmcu_psr_config_data_wait_loop_reg1 { ++ struct { ++ unsigned int wait_loop:16; /* [15:0] */ ++ unsigned int reserved:16; /* [31:16] */ ++ } bits; ++ unsigned int u32; ++}; ++ ++static void dce_psr_wait_loop( ++ struct dce_disp_clk *clk_dce, unsigned int display_clk_khz) ++{ ++ struct dc_context *ctx = clk_dce->base.ctx; ++ union dce110_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1; ++ ++ /* waitDMCUReadyForCmd */ ++ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 100); ++ ++ masterCmdData1.u32 = 0; ++ masterCmdData1.bits.wait_loop = display_clk_khz / 1000 / 7; ++ dm_write_reg(ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32); ++ ++ /* setDMCUParam_Cmd */ ++ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP); ++ ++ /* notifyDMCUMsg */ ++ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); ++} ++ ++static void dce_psr_set_clock( ++ struct display_clock *clk, ++ uint32_t requested_clk_khz) ++{ ++ struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); ++ ++ dce_set_clock(clk, requested_clk_khz); ++ dce_psr_wait_loop(clk_dce, requested_clk_khz); ++} ++ ++static void polaris_set_clock( ++ struct display_clock *clk, ++ uint32_t requested_clk_khz) ++{ ++ struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); ++ struct bp_set_dce_clock_parameters dce_clk_params; ++ struct dc_bios *bp = clk->ctx->dc_bios; ++ ++ /* Prepare to program display clock*/ ++ memset(&dce_clk_params, 0, sizeof(dce_clk_params)); ++ ++ /* Make sure requested clock isn't lower than minimum threshold*/ ++ if (requested_clk_khz > 0) ++ requested_clk_khz = dm_max(requested_clk_khz, ++ clk_dce->dentist_vco_freq_khz / 64); ++ ++ dce_clk_params.target_clock_frequency = requested_clk_khz; ++ dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS; ++ dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK; ++ ++ bp->funcs->set_dce_clock(bp, &dce_clk_params); ++ ++ /* from power down, we need mark the clock state as ClocksStateNominal ++ * from HWReset, so when resume we will call pplib voltage regulator.*/ ++ if (requested_clk_khz == 0) ++ clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; ++ ++ /*Program DP ref Clock*/ ++ /*VBIOS will determine DPREFCLK frequency, so we don't set it*/ ++ dce_clk_params.target_clock_frequency = 0; ++ dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK; ++ dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = 0; ++ ++ bp->funcs->set_dce_clock(bp, &dce_clk_params); ++} ++ ++static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) ++{ ++ struct dc_debug *debug = &clk_dce->base.ctx->dc->debug; ++ struct dc_bios *bp = clk_dce->base.ctx->dc_bios; ++ struct integrated_info info = { 0 }; ++ struct firmware_info fw_info = { 0 }; ++ int i; ++ ++ if (bp->integrated_info) ++ info = *bp->integrated_info; ++ ++ clk_dce->dentist_vco_freq_khz = info.dentist_vco_freq; ++ if (clk_dce->dentist_vco_freq_khz == 0) { ++ bp->funcs->get_firmware_info(bp, &fw_info); ++ clk_dce->dentist_vco_freq_khz = ++ fw_info.smu_gpu_pll_output_freq; ++ if (clk_dce->dentist_vco_freq_khz == 0) ++ clk_dce->dentist_vco_freq_khz = 3600000; ++ } ++ ++ /*update the maximum display clock for each power state*/ ++ for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { ++ enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID; ++ ++ switch (i) { ++ case 0: ++ clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW; ++ break; ++ ++ case 1: ++ clk_state = DM_PP_CLOCKS_STATE_LOW; ++ break; ++ ++ case 2: ++ clk_state = DM_PP_CLOCKS_STATE_NOMINAL; ++ break; ++ ++ case 3: ++ clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE; ++ break; ++ ++ default: ++ clk_state = DM_PP_CLOCKS_STATE_INVALID; ++ break; ++ } ++ ++ /*Do not allow bad VBIOS/SBIOS to override with invalid values, ++ * check for > 100MHz*/ ++ if (info.disp_clk_voltage[i].max_supported_clk >= 100000) ++ clk_dce->max_clks_by_state[clk_state].display_clk_khz = ++ info.disp_clk_voltage[i].max_supported_clk; ++ } ++ ++ if (!debug->disable_dfs_bypass) ++ if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) ++ clk_dce->dfs_bypass_enabled = true; ++ ++ clk_dce->use_max_disp_clk = debug->max_disp_clk; ++} ++ ++static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) ++{ ++ struct dc_bios *bp = clk_dce->base.ctx->dc_bios; ++ int ss_info_num = bp->funcs->get_ss_entry_number( ++ bp, AS_SIGNAL_TYPE_GPU_PLL); ++ ++ if (ss_info_num) { ++ struct spread_spectrum_info info = { 0 }; ++ enum bp_result result = bp->funcs->get_spread_spectrum_info( ++ bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info); ++ ++ /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS ++ * even if SS not enabled and in that case ++ * SSInfo.spreadSpectrumPercentage !=0 would be sign ++ * that SS is enabled ++ */ ++ if (result == BP_RESULT_OK && ++ info.spread_spectrum_percentage != 0) { ++ clk_dce->ss_on_gpu_pll = true; ++ clk_dce->gpu_pll_ss_divider = info.spread_percentage_divider; ++ ++ if (info.type.CENTER_MODE == 0) { ++ /* Currently for DP Reference clock we ++ * need only SS percentage for ++ * downspread */ ++ clk_dce->gpu_pll_ss_percentage = ++ info.spread_spectrum_percentage; ++ } ++ } ++ ++ } ++} ++ ++static const struct display_clock_funcs dce112_funcs = { ++ .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, ++ .get_required_clocks_state = dce_get_required_clocks_state, ++ .set_min_clocks_state = dce_clock_set_min_clocks_state, ++ .set_clock = polaris_set_clock ++}; ++ ++static const struct display_clock_funcs dce110_funcs = { ++ .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, ++ .get_required_clocks_state = dce_get_required_clocks_state, ++ .set_min_clocks_state = dce_clock_set_min_clocks_state, ++ .set_clock = dce_psr_set_clock ++}; ++ ++static const struct display_clock_funcs dce_funcs = { ++ .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, ++ .get_required_clocks_state = dce_get_required_clocks_state, ++ .set_min_clocks_state = dce_clock_set_min_clocks_state, ++ .set_clock = dce_set_clock ++}; ++ ++static void dce_disp_clk_construct( ++ struct dce_disp_clk *clk_dce, ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask) ++{ ++ struct display_clock *base = &clk_dce->base; ++ ++ base->ctx = ctx; ++ base->funcs = &dce_funcs; ++ ++ clk_dce->regs = regs; ++ clk_dce->clk_shift = clk_shift; ++ clk_dce->clk_mask = clk_mask; ++ ++ clk_dce->dfs_bypass_disp_clk = 0; ++ clk_dce->gpu_pll_ss_percentage = 0; ++ clk_dce->gpu_pll_ss_divider = 1000; ++ clk_dce->ss_on_gpu_pll = false; ++ base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; ++ base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID; ++ ++ dce_clock_read_integrated_info(clk_dce); ++ dce_clock_read_ss_info(clk_dce); ++ ++ dal_divider_range_construct( ++ &clk_dce->divider_ranges[DIVIDER_RANGE_01], ++ DIVIDER_RANGE_01_START, ++ DIVIDER_RANGE_01_STEP_SIZE, ++ DIVIDER_RANGE_01_BASE_DIVIDER_ID, ++ DIVIDER_RANGE_02_BASE_DIVIDER_ID); ++ dal_divider_range_construct( ++ &clk_dce->divider_ranges[DIVIDER_RANGE_02], ++ DIVIDER_RANGE_02_START, ++ DIVIDER_RANGE_02_STEP_SIZE, ++ DIVIDER_RANGE_02_BASE_DIVIDER_ID, ++ DIVIDER_RANGE_03_BASE_DIVIDER_ID); ++ dal_divider_range_construct( ++ &clk_dce->divider_ranges[DIVIDER_RANGE_03], ++ DIVIDER_RANGE_03_START, ++ DIVIDER_RANGE_03_STEP_SIZE, ++ DIVIDER_RANGE_03_BASE_DIVIDER_ID, ++ DIVIDER_RANGE_MAX_DIVIDER_ID); ++} ++ ++struct display_clock *dce_disp_clk_create( ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask) ++{ ++ struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce)); ++ ++ if (clk_dce == NULL) { ++ BREAK_TO_DEBUGGER(); ++ return NULL; ++ } ++ ++ dce_disp_clk_construct( ++ clk_dce, ctx, regs, clk_shift, clk_mask); ++ ++ return &clk_dce->base; ++} ++ ++struct display_clock *dce110_disp_clk_create( ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask) ++{ ++ struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce)); ++ ++ if (clk_dce == NULL) { ++ BREAK_TO_DEBUGGER(); ++ return NULL; ++ } ++ ++ dce_disp_clk_construct( ++ clk_dce, ctx, regs, clk_shift, clk_mask); ++ ++ clk_dce->base.funcs = &dce110_funcs; ++ ++ return &clk_dce->base; ++} ++ ++struct display_clock *dce112_disp_clk_create( ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask) ++{ ++ struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce)); ++ ++ if (clk_dce == NULL) { ++ BREAK_TO_DEBUGGER(); ++ return NULL; ++ } ++ ++ dce_disp_clk_construct( ++ clk_dce, ctx, regs, clk_shift, clk_mask); ++ ++ clk_dce->base.funcs = &dce112_funcs; ++ ++ return &clk_dce->base; ++} ++ ++void dce_disp_clk_destroy(struct display_clock **disp_clk) ++{ ++ struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(*disp_clk); ++ ++ dm_free(clk_dce); ++ *disp_clk = NULL; ++} +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +new file mode 100644 +index 0000000..e3b2374 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +@@ -0,0 +1,133 @@ ++/* ++ * Copyright 2012-16 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++ ++#ifndef _DCE_CLOCKS_H_ ++#define _DCE_CLOCKS_H_ ++ ++#include "display_clock_interface.h" ++#include "../gpu/divider_range.h" ++ ++ ++#define TO_DCE_CLOCKS(clocks)\ ++ container_of(clocks, struct dce_disp_clk, base) ++ ++#define CLK_COMMON_REG_LIST_DCE_BASE() \ ++ .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \ ++ .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL, \ ++ .MASTER_COMM_DATA_REG1 = mmMASTER_COMM_DATA_REG1, \ ++ .MASTER_COMM_CMD_REG = mmMASTER_COMM_CMD_REG, \ ++ .MASTER_COMM_CNTL_REG = mmMASTER_COMM_CNTL_REG ++ ++#define CLK_SF(reg_name, field_name, post_fix)\ ++ .field_name = reg_name ## __ ## field_name ## post_fix ++ ++#define CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) \ ++ CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \ ++ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh), \ ++ CLK_SF(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, mask_sh), \ ++ CLK_SF(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, mask_sh) ++ ++ ++#define CLK_REG_FIELD_LIST(type) \ ++ type DPREFCLK_SRC_SEL; \ ++ type DENTIST_DPREFCLK_WDIVIDER; \ ++ type MASTER_COMM_CMD_REG_BYTE0; \ ++ type MASTER_COMM_INTERRUPT ++ ++struct dce_disp_clk_shift { ++ CLK_REG_FIELD_LIST(uint8_t); ++}; ++ ++struct dce_disp_clk_mask { ++ CLK_REG_FIELD_LIST(uint32_t); ++}; ++ ++struct dce_disp_clk_registers { ++ uint32_t DPREFCLK_CNTL; ++ uint32_t DENTIST_DISPCLK_CNTL; ++ uint32_t MASTER_COMM_DATA_REG1; ++ uint32_t MASTER_COMM_CMD_REG; ++ uint32_t MASTER_COMM_CNTL_REG; ++}; ++ ++/* Array identifiers and count for the divider ranges.*/ ++enum divider_range_count { ++ DIVIDER_RANGE_01 = 0, ++ DIVIDER_RANGE_02, ++ DIVIDER_RANGE_03, ++ DIVIDER_RANGE_MAX /* == 3*/ ++}; ++ ++struct dce_disp_clk { ++ struct display_clock base; ++ const struct dce_disp_clk_registers *regs; ++ const struct dce_disp_clk_shift *clk_shift; ++ const struct dce_disp_clk_mask *clk_mask; ++ ++ struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; ++ struct divider_range divider_ranges[DIVIDER_RANGE_MAX]; ++ ++ bool use_max_disp_clk; ++ uint32_t dentist_vco_freq_khz; ++ ++ /* Cache the status of DFS-bypass feature*/ ++ bool dfs_bypass_enabled; ++ /* Cache the display clock returned by VBIOS if DFS-bypass is enabled. ++ * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */ ++ uint32_t dfs_bypass_disp_clk; ++ ++ /* Flag for Enabled SS on GPU PLL */ ++ bool ss_on_gpu_pll; ++ /* GPU PLL SS percentage (if down-spread enabled) */ ++ uint32_t gpu_pll_ss_percentage; ++ /* GPU PLL SS percentage Divider (100 or 1000) */ ++ uint32_t gpu_pll_ss_divider; ++ ++ ++}; ++ ++ ++struct display_clock *dce_disp_clk_create( ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask); ++ ++struct display_clock *dce110_disp_clk_create( ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask); ++ ++struct display_clock *dce112_disp_clk_create( ++ struct dc_context *ctx, ++ const struct dce_disp_clk_registers *regs, ++ const struct dce_disp_clk_shift *clk_shift, ++ const struct dce_disp_clk_mask *clk_mask); ++ ++void dce_disp_clk_destroy(struct display_clock **disp_clk); ++ ++#endif /* _DCE_CLOCKS_H_ */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +index 5716ce1..c97416f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +@@ -40,6 +40,7 @@ + #include "dce110/dce110_ipp.h" + #include "dce/dce_transform.h" + #include "dce110/dce110_opp.h" ++#include "dce/dce_clocks.h" + #include "dce/dce_clock_source.h" + #include "dce/dce_audio.h" + #include "dce/dce_hwseq.h" +@@ -200,6 +201,18 @@ static const struct dce110_ipp_reg_offsets dce100_ipp_reg_offsets[] = { + .reg_name = mm ## block ## id ## _ ## reg_name + + ++static const struct dce_disp_clk_registers disp_clk_regs = { ++ CLK_COMMON_REG_LIST_DCE_BASE() ++}; ++ ++static const struct dce_disp_clk_shift disp_clk_shift = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) ++}; ++ ++static const struct dce_disp_clk_mask disp_clk_mask = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) ++}; ++ + #define transform_regs(id)\ + [id] = {\ + XFM_COMMON_REG_LIST_DCE100(id)\ +@@ -717,9 +730,7 @@ static void destruct(struct dce110_resource_pool *pool) + } + + if (pool->base.display_clock != NULL) +- pool->base.display_clock->funcs->destroy( +- &pool->base.display_clock); +- pool->base.display_clock = NULL; ++ dce_disp_clk_destroy(&pool->base.display_clock); + + if (pool->base.irqs != NULL) + dal_irq_service_destroy(&pool->base.irqs); +@@ -970,7 +981,10 @@ static bool construct( + } + } + +- pool->base.display_clock = dal_display_clock_dce110_create(ctx); ++ pool->base.display_clock = dce_disp_clk_create(ctx, ++ &disp_clk_regs, ++ &disp_clk_shift, ++ &disp_clk_mask); + if (pool->base.display_clock == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +index 8682c8b..fa601f7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +@@ -45,6 +45,7 @@ + #include "dce110/dce110_transform_v.h" + #include "dce110/dce110_opp.h" + #include "dce110/dce110_opp_v.h" ++#include "dce/dce_clocks.h" + #include "dce/dce_clock_source.h" + #include "dce/dce_hwseq.h" + #include "dce110/dce110_hw_sequencer.h" +@@ -187,6 +188,17 @@ static const struct dce110_ipp_reg_offsets dce110_ipp_reg_offsets[] = { + #define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + ++static const struct dce_disp_clk_registers disp_clk_regs = { ++ CLK_COMMON_REG_LIST_DCE_BASE() ++}; ++ ++static const struct dce_disp_clk_shift disp_clk_shift = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) ++}; ++ ++static const struct dce_disp_clk_mask disp_clk_mask = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) ++}; + + #define transform_regs(id)\ + [id] = {\ +@@ -699,11 +711,8 @@ static void destruct(struct dce110_resource_pool *pool) + } + } + +- if (pool->base.display_clock != NULL) { +- pool->base.display_clock->funcs->destroy( +- &pool->base.display_clock); +- pool->base.display_clock = NULL; +- } ++ if (pool->base.display_clock != NULL) ++ dce_disp_clk_destroy(&pool->base.display_clock); + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); +@@ -1261,7 +1270,10 @@ static bool construct( + } + } + +- pool->base.display_clock = dal_display_clock_dce110_create(ctx); ++ pool->base.display_clock = dce110_disp_clk_create(ctx, ++ &disp_clk_regs, ++ &disp_clk_shift, ++ &disp_clk_mask); + if (pool->base.display_clock == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); +diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +index c50a215..3a47830 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +@@ -41,6 +41,7 @@ + #include "dce/dce_audio.h" + #include "dce112/dce112_opp.h" + #include "dce110/dce110_ipp.h" ++#include "dce/dce_clocks.h" + #include "dce/dce_clock_source.h" + + #include "dce/dce_hwseq.h" +@@ -204,6 +205,19 @@ static const struct dce110_ipp_reg_offsets ipp_reg_offsets[] = { + #define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + ++ ++static const struct dce_disp_clk_registers disp_clk_regs = { ++ CLK_COMMON_REG_LIST_DCE_BASE() ++}; ++ ++static const struct dce_disp_clk_shift disp_clk_shift = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) ++}; ++ ++static const struct dce_disp_clk_mask disp_clk_mask = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) ++}; ++ + #define transform_regs(id)\ + [id] = {\ + XFM_COMMON_REG_LIST_DCE110(id)\ +@@ -733,11 +747,8 @@ static void destruct(struct dce110_resource_pool *pool) + } + } + +- if (pool->base.display_clock != NULL) { +- pool->base.display_clock->funcs->destroy( +- &pool->base.display_clock); +- pool->base.display_clock = NULL; +- } ++ if (pool->base.display_clock != NULL) ++ dce_disp_clk_destroy(&pool->base.display_clock); + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); +@@ -1299,9 +1310,10 @@ static bool construct( + } + } + +- pool->base.display_clock = dal_display_clock_dce112_create( +- ctx); +- ++ pool->base.display_clock = dce112_disp_clk_create(ctx, ++ &disp_clk_regs, ++ &disp_clk_shift, ++ &disp_clk_mask); + if (pool->base.display_clock == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); +diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +index 1d2a31e..517d42d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +@@ -45,6 +45,7 @@ + #include "dce/dce_transform.h" + #include "dce80/dce80_opp.h" + #include "dce110/dce110_ipp.h" ++#include "dce/dce_clocks.h" + #include "dce/dce_clock_source.h" + #include "dce/dce_audio.h" + #include "dce/dce_hwseq.h" +@@ -215,6 +216,19 @@ static const struct dce110_ipp_reg_offsets ipp_reg_offsets[] = { + #define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + ++ ++static const struct dce_disp_clk_registers disp_clk_regs = { ++ CLK_COMMON_REG_LIST_DCE_BASE() ++}; ++ ++static const struct dce_disp_clk_shift disp_clk_shift = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) ++}; ++ ++static const struct dce_disp_clk_mask disp_clk_mask = { ++ CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) ++}; ++ + #define transform_regs(id)\ + [id] = {\ + XFM_COMMON_REG_LIST_DCE_BASE(id)\ +@@ -656,11 +670,8 @@ static void destruct(struct dce110_resource_pool *pool) + } + } + +- if (pool->base.display_clock != NULL) { +- pool->base.display_clock->funcs->destroy( +- &pool->base.display_clock); +- pool->base.display_clock = NULL; +- } ++ if (pool->base.display_clock != NULL) ++ dce_disp_clk_destroy(&pool->base.display_clock); + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); +@@ -857,47 +868,6 @@ static const struct resource_funcs dce80_res_pool_funcs = { + .validate_bandwidth = dce80_validate_bandwidth + }; + +-static enum dm_pp_clocks_state dce80_resource_convert_clock_state_pp_to_dc( +- enum dm_pp_clocks_state pp_clock_state) +-{ +- enum dm_pp_clocks_state dc_clocks_state = DM_PP_CLOCKS_STATE_INVALID; +- +- switch (pp_clock_state) { +- case DM_PP_CLOCKS_STATE_INVALID: +- dc_clocks_state = DM_PP_CLOCKS_STATE_INVALID; +- break; +- case DM_PP_CLOCKS_STATE_ULTRA_LOW: +- dc_clocks_state = DM_PP_CLOCKS_STATE_ULTRA_LOW; +- break; +- case DM_PP_CLOCKS_STATE_LOW: +- dc_clocks_state = DM_PP_CLOCKS_STATE_LOW; +- break; +- case DM_PP_CLOCKS_STATE_NOMINAL: +- dc_clocks_state = DM_PP_CLOCKS_STATE_NOMINAL; +- break; +- case DM_PP_CLOCKS_STATE_PERFORMANCE: +- dc_clocks_state = DM_PP_CLOCKS_STATE_PERFORMANCE; +- break; +- case DM_PP_CLOCKS_DPM_STATE_LEVEL_4: +- dc_clocks_state = DM_PP_CLOCKS_DPM_STATE_LEVEL_4; +- break; +- case DM_PP_CLOCKS_DPM_STATE_LEVEL_5: +- dc_clocks_state = DM_PP_CLOCKS_DPM_STATE_LEVEL_5; +- break; +- case DM_PP_CLOCKS_DPM_STATE_LEVEL_6: +- dc_clocks_state = DM_PP_CLOCKS_DPM_STATE_LEVEL_6; +- break; +- case DM_PP_CLOCKS_DPM_STATE_LEVEL_7: +- dc_clocks_state = DM_PP_CLOCKS_DPM_STATE_LEVEL_7; +- break; +- default: +- dc_clocks_state = DM_PP_CLOCKS_STATE_INVALID; +- break; +- } +- +- return dc_clocks_state; +-} +- + static bool construct( + uint8_t num_virtual_links, + struct core_dc *dc, +@@ -967,7 +937,10 @@ static bool construct( + } + } + +- pool->base.display_clock = dal_display_clock_dce80_create(ctx); ++ pool->base.display_clock = dce_disp_clk_create(ctx, ++ &disp_clk_regs, ++ &disp_clk_shift, ++ &disp_clk_mask); + if (pool->base.display_clock == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); +@@ -977,8 +950,7 @@ static bool construct( + + if (dm_pp_get_static_clocks(ctx, &static_clk_info)) + pool->base.display_clock->max_clks_state = +- dce80_resource_convert_clock_state_pp_to_dc( +- static_clk_info.max_clocks_state); ++ static_clk_info.max_clocks_state; + + { + struct irq_service_init_data init_data; +diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h +index 44bad17..460971d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h +@@ -43,15 +43,17 @@ enum dm_pp_clocks_state { + + /* Starting from DCE11, Max 8 levels of DPM state supported. */ + DM_PP_CLOCKS_DPM_STATE_LEVEL_INVALID = DM_PP_CLOCKS_STATE_INVALID, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_0 = DM_PP_CLOCKS_STATE_ULTRA_LOW, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_1 = DM_PP_CLOCKS_STATE_LOW, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_2 = DM_PP_CLOCKS_STATE_NOMINAL, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_0, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_1, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_2, + /* to be backward compatible */ +- DM_PP_CLOCKS_DPM_STATE_LEVEL_3 = DM_PP_CLOCKS_STATE_PERFORMANCE, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_4 = DM_PP_CLOCKS_DPM_STATE_LEVEL_3 + 1, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_5 = DM_PP_CLOCKS_DPM_STATE_LEVEL_4 + 1, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_6 = DM_PP_CLOCKS_DPM_STATE_LEVEL_5 + 1, +- DM_PP_CLOCKS_DPM_STATE_LEVEL_7 = DM_PP_CLOCKS_DPM_STATE_LEVEL_6 + 1, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_3, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_4, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_5, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_6, ++ DM_PP_CLOCKS_DPM_STATE_LEVEL_7, ++ ++ DM_PP_CLOCKS_MAX_STATES + }; + + struct dm_pp_gpu_clock_range { +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/Makefile b/drivers/gpu/drm/amd/display/dc/gpu/Makefile +index 0b99a74..6ab4078 100644 +--- a/drivers/gpu/drm/amd/display/dc/gpu/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/gpu/Makefile +@@ -10,23 +10,8 @@ AMD_DAL_GPU = $(addprefix $(AMDDALPATH)/dc/gpu/,$(GPU)) + AMD_DISPLAY_FILES += $(AMD_DAL_GPU) + + ############################################################################### +-# DCE 80 family +-############################################################################### +-GPU_DCE80 = display_clock_dce80.o +- +-AMD_DAL_GPU_DCE80 = $(addprefix $(AMDDALPATH)/dc/gpu/dce80/,$(GPU_DCE80)) +- +-AMD_DISPLAY_FILES += $(AMD_DAL_GPU_DCE80) +- +- +-############################################################################### + # DCE 110 family + ############################################################################### +-GPU_DCE110 = display_clock_dce110.o +- +-AMD_DAL_GPU_DCE110 = $(addprefix $(AMDDALPATH)/dc/gpu/dce110/,$(GPU_DCE110)) +- +-AMD_DISPLAY_FILES += $(AMD_DAL_GPU_DCE110) + + GPU_DCE112 = display_clock_dce112.o + +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.c b/drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.c +deleted file mode 100644 +index 9dabaac..0000000 +--- a/drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.c ++++ /dev/null +@@ -1,516 +0,0 @@ +-/* +- * Copyright 2012-15 Advanced Micro Devices, Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: AMD +- * +- */ +- +-#include "dm_services.h" +- +-#include "dce/dce_11_0_d.h" +-#include "dce/dce_11_0_sh_mask.h" +- +-#include "include/bios_parser_interface.h" +-#include "include/fixed32_32.h" +-#include "include/logger_interface.h" +- +-#include "../divider_range.h" +- +-#include "display_clock_dce110.h" +-#include "dc.h" +- +-#define FROM_DISPLAY_CLOCK(base) \ +- container_of(base, struct display_clock_dce110, disp_clk_base) +- +-#define PSR_SET_WAITLOOP 0x31 +- +-static struct state_dependent_clocks max_clks_by_state[] = { +-/*ClocksStateInvalid - should not be used*/ +-{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, +-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/ +-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 }, +-/*ClocksStateLow*/ +-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 }, +-/*ClocksStateNominal*/ +-{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 }, +-/*ClocksStatePerformance*/ +-{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } }; +- +-/* Starting point for each divider range.*/ +-enum divider_range_start { +- DIVIDER_RANGE_01_START = 200, /* 2.00*/ +- DIVIDER_RANGE_02_START = 1600, /* 16.00*/ +- DIVIDER_RANGE_03_START = 3200, /* 32.00*/ +- DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ +-}; +- +-/* Array identifiers and count for the divider ranges.*/ +-enum divider_range_count { +- DIVIDER_RANGE_01 = 0, +- DIVIDER_RANGE_02, +- DIVIDER_RANGE_03, +- DIVIDER_RANGE_MAX /* == 3*/ +-}; +- +-/* Ranges for divider identifiers (Divider ID or DID) +- mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/ +-enum divider_id_register_setting { +- DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08, +- DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40, +- DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60, +- DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80 +-}; +- +-/* Step size between each divider within a range. +- Incrementing the DENTIST_DISPCLK_WDIVIDER by one +- will increment the divider by this much.*/ +-enum divider_range_step_size { +- DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/ +- DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/ +- DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */ +-}; +- +-union dce110_dmcu_psr_config_data_wait_loop_reg1 { +- struct { +- unsigned int waitLoop:16; /* [15:0] */ +- unsigned int reserved:16; /* [31:16] */ +- } bits; +- unsigned int u32All; +-}; +- +-static struct divider_range divider_ranges[DIVIDER_RANGE_MAX]; +- +-#define DCE110_DFS_BYPASS_THRESHOLD_KHZ 400000 +-/***************************************************************************** +- * static functions +- *****************************************************************************/ +- +-static bool dce110_set_min_clocks_state( +- struct display_clock *dc, +- enum dm_pp_clocks_state clocks_state) +-{ +- struct dm_pp_power_level_change_request level_change_req = { +- clocks_state }; +- +- if (clocks_state > dc->max_clks_state) { +- /*Requested state exceeds max supported state.*/ +- dm_logger_write(dc->ctx->logger, LOG_WARNING, +- "Requested state exceeds max supported state"); +- return false; +- } else if (clocks_state == dc->cur_min_clks_state) { +- /*if we're trying to set the same state, we can just return +- * since nothing needs to be done*/ +- return true; +- } +- +- /* get max clock state from PPLIB */ +- if (dm_pp_apply_power_level_change_request(dc->ctx, &level_change_req)) +- dc->cur_min_clks_state = clocks_state; +- +- return true; +-} +- +-static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc) +-{ +- uint32_t dispclk_cntl_value; +- uint32_t dp_ref_clk_cntl_value; +- uint32_t dp_ref_clk_cntl_src_sel_value; +- uint32_t dp_ref_clk_khz = 600000; +- uint32_t target_div = INVALID_DIVIDER; +- struct display_clock_dce110 *disp_clk = FROM_DISPLAY_CLOCK(dc); +- +- /* ASSERT DP Reference Clock source is from DFS*/ +- dp_ref_clk_cntl_value = dm_read_reg(dc->ctx, +- mmDPREFCLK_CNTL); +- +- dp_ref_clk_cntl_src_sel_value = +- get_reg_field_value( +- dp_ref_clk_cntl_value, +- DPREFCLK_CNTL, DPREFCLK_SRC_SEL); +- +- ASSERT(dp_ref_clk_cntl_src_sel_value == 0); +- +- /* Read the mmDENTIST_DISPCLK_CNTL to get the currently +- * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ +- dispclk_cntl_value = dm_read_reg(dc->ctx, +- mmDENTIST_DISPCLK_CNTL); +- +- /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ +- target_div = dal_divider_range_get_divider( +- divider_ranges, +- DIVIDER_RANGE_MAX, +- get_reg_field_value(dispclk_cntl_value, +- DENTIST_DISPCLK_CNTL, +- DENTIST_DPREFCLK_WDIVIDER)); +- +- if (target_div != INVALID_DIVIDER) { +- /* Calculate the current DFS clock, in kHz.*/ +- dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR +- * disp_clk->dentist_vco_freq_khz) / target_div; +- } +- +- /* SW will adjust DP REF Clock average value for all purposes +- * (DP DTO / DP Audio DTO and DP GTC) +- if clock is spread for all cases: +- -if SS enabled on DP Ref clock and HW de-spreading enabled with SW +- calculations for DS_INCR/DS_MODULO (this is planned to be default case) +- -if SS enabled on DP Ref clock and HW de-spreading enabled with HW +- calculations (not planned to be used, but average clock should still +- be valid) +- -if SS enabled on DP Ref clock and HW de-spreading disabled +- (should not be case with CIK) then SW should program all rates +- generated according to average value (case as with previous ASICs) +- */ +- if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) { +- struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( +- dal_fixed32_32_from_fraction( +- disp_clk->gpu_pll_ss_percentage, +- disp_clk->gpu_pll_ss_divider), 200); +- struct fixed32_32 adj_dp_ref_clk_khz; +- +- ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, +- ss_percentage); +- adj_dp_ref_clk_khz = +- dal_fixed32_32_mul_int( +- ss_percentage, +- dp_ref_clk_khz); +- dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); +- } +- +- return dp_ref_clk_khz; +-} +- +-static void destroy(struct display_clock **base) +-{ +- struct display_clock_dce110 *dc110; +- +- dc110 = DCLCK110_FROM_BASE(*base); +- +- dm_free(dc110); +- +- *base = NULL; +-} +- +-static bool display_clock_integrated_info_construct( +- struct display_clock_dce110 *disp_clk) +-{ +- struct dc_debug *debug = &disp_clk->disp_clk_base.ctx->dc->debug; +- struct dc_bios *bp = disp_clk->disp_clk_base.ctx->dc_bios; +- struct integrated_info info; +- struct firmware_info fw_info; +- uint32_t i; +- struct display_clock *base = &disp_clk->disp_clk_base; +- +- memset(&info, 0, sizeof(struct integrated_info)); +- memset(&fw_info, 0, sizeof(struct firmware_info)); +- +- if (bp->integrated_info) +- info = *bp->integrated_info; +- +- disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq; +- if (disp_clk->dentist_vco_freq_khz == 0) { +- bp->funcs->get_firmware_info(bp, &fw_info); +- disp_clk->dentist_vco_freq_khz = +- fw_info.smu_gpu_pll_output_freq; +- if (disp_clk->dentist_vco_freq_khz == 0) +- disp_clk->dentist_vco_freq_khz = 3600000; +- } +- +- base->min_display_clk_threshold_khz = +- disp_clk->dentist_vco_freq_khz / 64; +- +- if (bp->integrated_info == NULL) +- return false; +- +- /*update the maximum display clock for each power state*/ +- for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { +- enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID; +- +- switch (i) { +- case 0: +- clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW; +- break; +- +- case 1: +- clk_state = DM_PP_CLOCKS_STATE_LOW; +- break; +- +- case 2: +- clk_state = DM_PP_CLOCKS_STATE_NOMINAL; +- break; +- +- case 3: +- clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE; +- break; +- +- default: +- clk_state = DM_PP_CLOCKS_STATE_INVALID; +- break; +- } +- +- /*Do not allow bad VBIOS/SBIOS to override with invalid values, +- * check for > 100MHz*/ +- if (info.disp_clk_voltage[i].max_supported_clk >= 100000) { +- max_clks_by_state[clk_state].display_clk_khz = +- info.disp_clk_voltage[i].max_supported_clk; +- } +- } +- +- disp_clk->dfs_bypass_enabled = false; +- if (!debug->disable_dfs_bypass) +- if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) +- disp_clk->dfs_bypass_enabled = true; +- +- disp_clk->use_max_disp_clk = debug->max_disp_clk; +- +- return true; +-} +- +-static enum dm_pp_clocks_state get_required_clocks_state( +- struct display_clock *dc, +- struct state_dependent_clocks *req_clocks) +-{ +- int32_t i; +- struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc); +- enum dm_pp_clocks_state low_req_clk = dc->max_clks_state; +- +- if (!req_clocks) { +- /* NULL pointer*/ +- dm_logger_write(dc->ctx->logger, LOG_WARNING, +- "%s: Invalid parameter", +- __func__); +- return DM_PP_CLOCKS_STATE_INVALID; +- } +- +- /* Iterate from highest supported to lowest valid state, and update +- * lowest RequiredState with the lowest state that satisfies +- * all required clocks +- */ +- for (i = dc->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; --i) { +- if ((req_clocks->display_clk_khz <= +- max_clks_by_state[i].display_clk_khz) && +- (req_clocks->pixel_clk_khz <= +- max_clks_by_state[i].pixel_clk_khz)) +- low_req_clk = i; +- } +- return low_req_clk; +-} +- +-static void psr_wait_loop(struct dc_context *ctx, unsigned int display_clk_khz) +-{ +- unsigned int dmcu_max_retry_on_wait_reg_ready = 801; +- unsigned int dmcu_wait_reg_ready_interval = 100; +- unsigned int regValue; +- uint32_t masterCmd; +- uint32_t masterComCntl; +- union dce110_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1; +- +- /* waitDMCUReadyForCmd */ +- do { +- dm_delay_in_microseconds(ctx, dmcu_wait_reg_ready_interval); +- regValue = dm_read_reg(ctx, mmMASTER_COMM_CNTL_REG); +- dmcu_max_retry_on_wait_reg_ready--; +- } while +- /* expected value is 0, loop while not 0*/ +- ((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) && +- dmcu_max_retry_on_wait_reg_ready > 0); +- +- masterCmdData1.u32All = 0; +- masterCmdData1.bits.waitLoop = display_clk_khz / 1000 / 7; +- dm_write_reg(ctx, mmMASTER_COMM_DATA_REG1, masterCmdData1.u32All); +- +- /* setDMCUParam_Cmd */ +- masterCmd = dm_read_reg(ctx, mmMASTER_COMM_CMD_REG); +- set_reg_field_value( +- masterCmd, +- PSR_SET_WAITLOOP, +- MASTER_COMM_CMD_REG, +- MASTER_COMM_CMD_REG_BYTE0); +- +- dm_write_reg(ctx, mmMASTER_COMM_CMD_REG, masterCmd); +- +- /* notifyDMCUMsg */ +- masterComCntl = dm_read_reg(ctx, mmMASTER_COMM_CNTL_REG); +- set_reg_field_value( +- masterComCntl, +- 1, +- MASTER_COMM_CNTL_REG, +- MASTER_COMM_INTERRUPT); +- dm_write_reg(ctx, mmMASTER_COMM_CNTL_REG, masterComCntl); +-} +- +-static void dce110_set_clock( +- struct display_clock *base, +- uint32_t requested_clk_khz) +-{ +- struct bp_pixel_clock_parameters pxl_clk_params; +- struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base); +- struct dc_bios *bp = base->ctx->dc_bios; +- +- /* Prepare to program display clock*/ +- memset(&pxl_clk_params, 0, sizeof(pxl_clk_params)); +- +- /* Make sure requested clock isn't lower than minimum threshold*/ +- if (requested_clk_khz > 0) +- requested_clk_khz = dm_max(requested_clk_khz, +- base->min_display_clk_threshold_khz); +- +- pxl_clk_params.target_pixel_clock = requested_clk_khz; +- pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS; +- +- bp->funcs->program_display_engine_pll(bp, &pxl_clk_params); +- +- if (dc->dfs_bypass_enabled) { +- +- /* Cache the fixed display clock*/ +- dc->dfs_bypass_disp_clk = +- pxl_clk_params.dfs_bypass_display_clock; +- } +- +- /* from power down, we need mark the clock state as ClocksStateNominal +- * from HWReset, so when resume we will call pplib voltage regulator.*/ +- if (requested_clk_khz == 0) +- base->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; +- +- psr_wait_loop(base->ctx, requested_clk_khz); +-} +- +- +-static const struct display_clock_funcs funcs = { +- .destroy = destroy, +- .get_dp_ref_clk_frequency = get_dp_ref_clk_frequency, +- .get_required_clocks_state = get_required_clocks_state, +- .set_clock = dce110_set_clock, +- .set_min_clocks_state = dce110_set_min_clocks_state +-}; +- +-static bool dal_display_clock_dce110_construct( +- struct display_clock_dce110 *dc110, +- struct dc_context *ctx) +-{ +- struct display_clock *dc_base = &dc110->disp_clk_base; +- struct dc_bios *bp = ctx->dc_bios; +- +- dc_base->ctx = ctx; +- dc_base->min_display_clk_threshold_khz = 0; +- +- dc_base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID; +- +- dc_base->funcs = &funcs; +- +- dc110->dfs_bypass_disp_clk = 0; +- +- if (!display_clock_integrated_info_construct(dc110)) +- dm_logger_write(dc_base->ctx->logger, LOG_WARNING, +- "Cannot obtain VBIOS integrated info\n"); +- +- dc110->gpu_pll_ss_percentage = 0; +- dc110->gpu_pll_ss_divider = 1000; +- dc110->ss_on_gpu_pll = false; +- +-/* Initially set max clocks state to nominal. This should be updated by +- * via a pplib call to DAL IRI eventually calling a +- * DisplayEngineClock_Dce110::StoreMaxClocksState(). This call will come in +- * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/ +- dc_base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; +- +- dal_divider_range_construct( +- ÷r_ranges[DIVIDER_RANGE_01], +- DIVIDER_RANGE_01_START, +- DIVIDER_RANGE_01_STEP_SIZE, +- DIVIDER_RANGE_01_BASE_DIVIDER_ID, +- DIVIDER_RANGE_02_BASE_DIVIDER_ID); +- dal_divider_range_construct( +- ÷r_ranges[DIVIDER_RANGE_02], +- DIVIDER_RANGE_02_START, +- DIVIDER_RANGE_02_STEP_SIZE, +- DIVIDER_RANGE_02_BASE_DIVIDER_ID, +- DIVIDER_RANGE_03_BASE_DIVIDER_ID); +- dal_divider_range_construct( +- ÷r_ranges[DIVIDER_RANGE_03], +- DIVIDER_RANGE_03_START, +- DIVIDER_RANGE_03_STEP_SIZE, +- DIVIDER_RANGE_03_BASE_DIVIDER_ID, +- DIVIDER_RANGE_MAX_DIVIDER_ID); +- +- { +- uint32_t ss_info_num = +- bp->funcs->get_ss_entry_number(bp, +- AS_SIGNAL_TYPE_GPU_PLL); +- +- if (ss_info_num) { +- struct spread_spectrum_info info; +- enum bp_result result; +- +- memset(&info, 0, sizeof(info)); +- +- result = bp->funcs->get_spread_spectrum_info(bp, +- AS_SIGNAL_TYPE_GPU_PLL, +- 0, +- &info); +- +- /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS +- * even if SS not enabled and in that case +- * SSInfo.spreadSpectrumPercentage !=0 would be sign +- * that SS is enabled +- */ +- if (result == BP_RESULT_OK && +- info.spread_spectrum_percentage != 0) { +- dc110->ss_on_gpu_pll = true; +- dc110->gpu_pll_ss_divider = +- info.spread_percentage_divider; +- +- if (info.type.CENTER_MODE == 0) { +- /* Currently for DP Reference clock we +- * need only SS percentage for +- * downspread */ +- dc110->gpu_pll_ss_percentage = +- info.spread_spectrum_percentage; +- } +- } +- +- } +- } +- +- return true; +-} +- +-/***************************************************************************** +- * public functions +- *****************************************************************************/ +- +-struct display_clock *dal_display_clock_dce110_create( +- struct dc_context *ctx) +-{ +- struct display_clock_dce110 *dc110; +- +- dc110 = dm_alloc(sizeof(struct display_clock_dce110)); +- +- if (dc110 == NULL) +- return NULL; +- +- if (dal_display_clock_dce110_construct(dc110, ctx)) +- return &dc110->disp_clk_base; +- +- dm_free(dc110); +- +- return NULL; +-} +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.h b/drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.h +deleted file mode 100644 +index 50b51c4..0000000 +--- a/drivers/gpu/drm/amd/display/dc/gpu/dce110/display_clock_dce110.h ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* +- * Copyright 2012-15 Advanced Micro Devices, Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: AMD +- * +- */ +-#ifndef __DAL_DISPLAY_CLOCK_DCE110_H__ +-#define __DAL_DISPLAY_CLOCK_DCE110_H__ +- +-#include "display_clock_interface.h" +- +-struct display_clock_dce110 { +- struct display_clock disp_clk_base; +- bool use_max_disp_clk; +- uint32_t dentist_vco_freq_khz; +- /* Cache the status of DFS-bypass feature*/ +- bool dfs_bypass_enabled; +- /* GPU PLL SS percentage (if down-spread enabled) */ +- uint32_t gpu_pll_ss_percentage; +- /* GPU PLL SS percentage Divider (100 or 1000) */ +- uint32_t gpu_pll_ss_divider; +- /* Flag for Enabled SS on GPU PLL */ +- bool ss_on_gpu_pll; +- /* Cache the display clock returned by VBIOS if DFS-bypass is enabled. +- * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */ +- uint32_t dfs_bypass_disp_clk; +-}; +- +-#define DCLCK110_FROM_BASE(dc_base) \ +- container_of(dc_base, struct display_clock_dce110, disp_clk_base) +- +-#endif /* __DAL_DISPLAY_CLOCK_DCE110_H__ */ +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.c b/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.c +index 930548b..e0d67fb 100644 +--- a/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.c ++++ b/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.c +@@ -71,102 +71,6 @@ enum divider_range_step_size { + + static struct divider_range divider_ranges[DIVIDER_RANGE_MAX]; + +-#define dce112_DFS_BYPASS_THRESHOLD_KHZ 400000 +- +-static bool dce112_set_min_clocks_state( +- struct display_clock *dc, +- enum dm_pp_clocks_state clocks_state) +-{ +- struct dm_pp_power_level_change_request level_change_req = { +- clocks_state }; +- +- if (clocks_state > dc->max_clks_state) { +- /*Requested state exceeds max supported state.*/ +- dm_logger_write(dc->ctx->logger, LOG_WARNING, +- "Requested state exceeds max supported state"); +- return false; +- } else if (clocks_state == dc->cur_min_clks_state) { +- /*if we're trying to set the same state, we can just return +- * since nothing needs to be done*/ +- return true; +- } +- +- /* get max clock state from PPLIB */ +- if (dm_pp_apply_power_level_change_request(dc->ctx, &level_change_req)) +- dc->cur_min_clks_state = clocks_state; +- +- return true; +-} +- +-static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc) +-{ +- uint32_t dispclk_cntl_value; +- uint32_t dp_ref_clk_cntl_value; +- uint32_t dp_ref_clk_cntl_src_sel_value; +- uint32_t dp_ref_clk_khz = 600000; +- uint32_t target_div = INVALID_DIVIDER; +- struct display_clock_dce112 *disp_clk = FROM_DISPLAY_CLOCK(dc); +- +- /* ASSERT DP Reference Clock source is from DFS*/ +- dp_ref_clk_cntl_value = dm_read_reg(dc->ctx, +- mmDPREFCLK_CNTL); +- +- dp_ref_clk_cntl_src_sel_value = +- get_reg_field_value( +- dp_ref_clk_cntl_value, +- DPREFCLK_CNTL, DPREFCLK_SRC_SEL); +- +- ASSERT(dp_ref_clk_cntl_src_sel_value == 0); +- +- /* Read the mmDENTIST_DISPCLK_CNTL to get the currently +- * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ +- dispclk_cntl_value = dm_read_reg(dc->ctx, +- mmDENTIST_DISPCLK_CNTL); +- +- /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ +- target_div = dal_divider_range_get_divider( +- divider_ranges, +- DIVIDER_RANGE_MAX, +- get_reg_field_value(dispclk_cntl_value, +- DENTIST_DISPCLK_CNTL, +- DENTIST_DPREFCLK_WDIVIDER)); +- +- if (target_div != INVALID_DIVIDER) { +- /* Calculate the current DFS clock, in kHz.*/ +- dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR +- * disp_clk->dentist_vco_freq_khz) / target_div; +- } +- +- /* SW will adjust DP REF Clock average value for all purposes +- * (DP DTO / DP Audio DTO and DP GTC) +- if clock is spread for all cases: +- -if SS enabled on DP Ref clock and HW de-spreading enabled with SW +- calculations for DS_INCR/DS_MODULO (this is planned to be default case) +- -if SS enabled on DP Ref clock and HW de-spreading enabled with HW +- calculations (not planned to be used, but average clock should still +- be valid) +- -if SS enabled on DP Ref clock and HW de-spreading disabled +- (should not be case with CIK) then SW should program all rates +- generated according to average value (case as with previous ASICs) +- */ +- if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) { +- struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( +- dal_fixed32_32_from_fraction( +- disp_clk->gpu_pll_ss_percentage, +- disp_clk->gpu_pll_ss_divider), 200); +- struct fixed32_32 adj_dp_ref_clk_khz; +- +- ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, +- ss_percentage); +- adj_dp_ref_clk_khz = +- dal_fixed32_32_mul_int( +- ss_percentage, +- dp_ref_clk_khz); +- dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); +- } +- +- return dp_ref_clk_khz; +-} + + void dispclk_dce112_destroy(struct display_clock **base) + { +@@ -233,38 +137,6 @@ static bool display_clock_integrated_info_construct( + return true; + } + +-enum dm_pp_clocks_state dispclk_dce112_get_required_clocks_state( +- struct display_clock *dc, +- struct state_dependent_clocks *req_clocks) +-{ +- int32_t i; +- struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc); +- enum dm_pp_clocks_state low_req_clk = dc->max_clks_state; +- +- if (!req_clocks) { +- /* NULL pointer*/ +- dm_logger_write(dc->ctx->logger, LOG_WARNING, +- "%s: Invalid parameter", +- __func__); +- return DM_PP_CLOCKS_STATE_INVALID; +- } +- +- /* Iterate from highest supported to lowest valid state, and update +- * lowest RequiredState with the lowest state that satisfies +- * all required clocks +- */ +- for (i = dc->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; --i) { +- if ((req_clocks->display_clk_khz <= +- (disp_clk->max_clks_by_state + i)-> +- display_clk_khz) && +- (req_clocks->pixel_clk_khz <= +- (disp_clk->max_clks_by_state + i)-> +- pixel_clk_khz)) +- low_req_clk = i; +- } +- return low_req_clk; +-} +- + void dce112_set_clock( + struct display_clock *base, + uint32_t requested_clk_khz) +@@ -304,10 +176,7 @@ void dce112_set_clock( + + static const struct display_clock_funcs funcs = { + .destroy = dispclk_dce112_destroy, +- .get_dp_ref_clk_frequency = get_dp_ref_clk_frequency, +- .get_required_clocks_state = dispclk_dce112_get_required_clocks_state, + .set_clock = dce112_set_clock, +- .set_min_clocks_state = dce112_set_min_clocks_state + }; + + bool dal_display_clock_dce112_construct( +@@ -406,24 +275,3 @@ bool dal_display_clock_dce112_construct( + return true; + } + +-/***************************************************************************** +- * public functions +- *****************************************************************************/ +- +-struct display_clock *dal_display_clock_dce112_create( +- struct dc_context *ctx) +-{ +- struct display_clock_dce112 *dc112; +- +- dc112 = dm_alloc(sizeof(struct display_clock_dce112)); +- +- if (dc112 == NULL) +- return NULL; +- +- if (dal_display_clock_dce112_construct(dc112, ctx)) +- return &dc112->disp_clk_base; +- +- dm_free(dc112); +- +- return NULL; +-} +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.h b/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.h +index b750bb1..0743c51 100644 +--- a/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.h ++++ b/drivers/gpu/drm/amd/display/dc/gpu/dce112/display_clock_dce112.h +@@ -71,23 +71,9 @@ bool dal_display_clock_dce112_construct( + + void dispclk_dce112_destroy(struct display_clock **base); + +-enum dm_pp_clocks_state dispclk_dce112_get_min_clocks_state( +- struct display_clock *base); +- +-enum dm_pp_clocks_state dispclk_dce112_get_required_clocks_state( +- struct display_clock *dc, +- struct state_dependent_clocks *req_clocks); +- + void dce112_set_clock( + struct display_clock *base, + uint32_t requested_clk_khz); + +-bool dispclk_dce112_set_min_clocks_state( +- struct display_clock *base, +- enum dm_pp_clocks_state clocks_state); +- +-void dispclk_dce112_store_max_clocks_state( +- struct display_clock *base, +- enum dm_pp_clocks_state max_clocks_state); + + #endif /* __DAL_DISPLAY_CLOCK_DCE112_H__ */ +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.c b/drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.c +deleted file mode 100644 +index 9d7cb2c..0000000 +--- a/drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.c ++++ /dev/null +@@ -1,430 +0,0 @@ +-/* +- * Copyright 2012-15 Advanced Micro Devices, Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: AMD +- * +- */ +- +-#include "dm_services.h" +- +-#include "dce/dce_8_0_d.h" +-#include "dce/dce_8_0_sh_mask.h" +- +-#include "include/bios_parser_interface.h" +-#include "include/fixed32_32.h" +-#include "include/logger_interface.h" +- +-#include "../divider_range.h" +-#include "display_clock_dce80.h" +-#include "dc.h" +- +-#define DCE80_DFS_BYPASS_THRESHOLD_KHZ 100000 +- +-/* Max clock values for each state indexed by "enum clocks_state": */ +-static struct state_dependent_clocks max_clks_by_state[] = { +-/* ClocksStateInvalid - should not be used */ +-{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, +-/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */ +-{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, +-/* ClocksStateLow */ +-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000}, +-/* ClocksStateNominal */ +-{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 }, +-/* ClocksStatePerformance */ +-{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } }; +- +-/* Starting point for each divider range.*/ +-enum divider_range_start { +- DIVIDER_RANGE_01_START = 200, /* 2.00*/ +- DIVIDER_RANGE_02_START = 1600, /* 16.00*/ +- DIVIDER_RANGE_03_START = 3200, /* 32.00*/ +- DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ +-}; +- +-/* Ranges for divider identifiers (Divider ID or DID) +- mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/ +-enum divider_id_register_setting { +- DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08, +- DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40, +- DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60, +- DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80 +-}; +- +-/* Step size between each divider within a range. +- Incrementing the DENTIST_DISPCLK_WDIVIDER by one +- will increment the divider by this much.*/ +-enum divider_range_step_size { +- DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/ +- DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/ +- DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */ +-}; +- +-/* Array identifiers and count for the divider ranges.*/ +-enum divider_range_count { +- DIVIDER_RANGE_01 = 0, +- DIVIDER_RANGE_02, +- DIVIDER_RANGE_03, +- DIVIDER_RANGE_MAX /* == 3*/ +-}; +- +-static struct divider_range divider_ranges[DIVIDER_RANGE_MAX]; +- +-#define FROM_DISPLAY_CLOCK(base) \ +- container_of(base, struct display_clock_dce80, disp_clk) +- +-static void dce80_set_clock( +- struct display_clock *dc, +- uint32_t requested_clk_khz) +-{ +- struct bp_pixel_clock_parameters pxl_clk_params; +- struct dc_bios *bp = dc->ctx->dc_bios; +- +- /* Prepare to program display clock*/ +- memset(&pxl_clk_params, 0, sizeof(pxl_clk_params)); +- +- pxl_clk_params.target_pixel_clock = requested_clk_khz; +- pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS; +- +- bp->funcs->program_display_engine_pll(bp, &pxl_clk_params); +- +- /* from power down, we need mark the clock state as ClocksStateNominal +- * from HWReset, so when resume we will call pplib voltage regulator.*/ +- if (requested_clk_khz == 0) +- dc->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; +-} +- +-static enum dm_pp_clocks_state get_required_clocks_state +- (struct display_clock *dc, +- struct state_dependent_clocks *req_clocks) +-{ +- int32_t i; +- enum dm_pp_clocks_state low_req_clk = dc->max_clks_state; +- +- if (!req_clocks) { +- /* NULL pointer*/ +- BREAK_TO_DEBUGGER(); +- return DM_PP_CLOCKS_STATE_INVALID; +- } +- +- /* Iterate from highest supported to lowest valid state, and update +- * lowest RequiredState with the lowest state that satisfies +- * all required clocks +- */ +- for (i = dc->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; --i) { +- if ((req_clocks->display_clk_khz <= +- max_clks_by_state[i].display_clk_khz) && +- (req_clocks->pixel_clk_khz <= +- max_clks_by_state[i].pixel_clk_khz)) +- low_req_clk = i; +- } +- return low_req_clk; +-} +- +-static bool dce80_set_min_clocks_state( +- struct display_clock *dc, +- enum dm_pp_clocks_state clocks_state) +-{ +- struct dm_pp_power_level_change_request level_change_req = { +- clocks_state }; +- +- if (clocks_state > dc->max_clks_state) { +- /*Requested state exceeds max supported state.*/ +- dm_logger_write(dc->ctx->logger, LOG_WARNING, +- "Requested state exceeds max supported state"); +- return false; +- } else if (clocks_state == dc->cur_min_clks_state) { +- /*if we're trying to set the same state, we can just return +- * since nothing needs to be done*/ +- return true; +- } +- +- /* get max clock state from PPLIB */ +- if (dm_pp_apply_power_level_change_request(dc->ctx, &level_change_req)) +- dc->cur_min_clks_state = clocks_state; +- +- return true; +-} +- +-static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc) +-{ +- uint32_t dispclk_cntl_value; +- uint32_t dp_ref_clk_cntl_value; +- uint32_t dp_ref_clk_cntl_src_sel_value; +- uint32_t dp_ref_clk_khz = 600000; +- uint32_t target_div = INVALID_DIVIDER; +- struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); +- +- /* ASSERT DP Reference Clock source is from DFS*/ +- dp_ref_clk_cntl_value = dm_read_reg(dc->ctx, +- mmDPREFCLK_CNTL); +- +- dp_ref_clk_cntl_src_sel_value = +- get_reg_field_value( +- dp_ref_clk_cntl_value, +- DPREFCLK_CNTL, DPREFCLK_SRC_SEL); +- +- ASSERT(dp_ref_clk_cntl_src_sel_value == 0); +- +- /* Read the mmDENTIST_DISPCLK_CNTL to get the currently +- * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ +- dispclk_cntl_value = dm_read_reg(dc->ctx, +- mmDENTIST_DISPCLK_CNTL); +- +- /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ +- target_div = dal_divider_range_get_divider( +- divider_ranges, +- DIVIDER_RANGE_MAX, +- get_reg_field_value(dispclk_cntl_value, +- DENTIST_DISPCLK_CNTL, +- DENTIST_DPREFCLK_WDIVIDER)); +- +- if (target_div != INVALID_DIVIDER) { +- /* Calculate the current DFS clock, in kHz.*/ +- dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR +- * disp_clk->dentist_vco_freq_khz) / target_div; +- } +- +- /* SW will adjust DP REF Clock average value for all purposes +- * (DP DTO / DP Audio DTO and DP GTC) +- if clock is spread for all cases: +- -if SS enabled on DP Ref clock and HW de-spreading enabled with SW +- calculations for DS_INCR/DS_MODULO (this is planned to be default case) +- -if SS enabled on DP Ref clock and HW de-spreading enabled with HW +- calculations (not planned to be used, but average clock should still +- be valid) +- -if SS enabled on DP Ref clock and HW de-spreading disabled +- (should not be case with CIK) then SW should program all rates +- generated according to average value (case as with previous ASICs) +- */ +- if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) { +- struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( +- dal_fixed32_32_from_fraction( +- disp_clk->gpu_pll_ss_percentage, +- disp_clk->gpu_pll_ss_divider), 200); +- struct fixed32_32 adj_dp_ref_clk_khz; +- +- ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, +- ss_percentage); +- adj_dp_ref_clk_khz = +- dal_fixed32_32_mul_int( +- ss_percentage, +- dp_ref_clk_khz); +- dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); +- } +- +- return dp_ref_clk_khz; +-} +- +-static void display_clock_ss_construct( +- struct display_clock_dce80 *disp_clk) +-{ +- struct dc_bios *bp = disp_clk->disp_clk.ctx->dc_bios; +- uint32_t ss_entry_num = bp->funcs->get_ss_entry_number(bp, +- AS_SIGNAL_TYPE_GPU_PLL); +- +- /*Read SS Info from VBIOS SS Info table for DP Reference Clock spread.*/ +- if (ss_entry_num > 0) {/* Should be only one entry */ +- struct spread_spectrum_info ss_info; +- enum bp_result res; +- +- memset(&ss_info, 0, sizeof(struct spread_spectrum_info)); +- +- res = bp->funcs->get_spread_spectrum_info(bp, +- AS_SIGNAL_TYPE_GPU_PLL, 0, &ss_info); +- +- /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS even if +- * SS not enabled and in that case +- * SSInfo.spreadSpectrumPercentage !=0 would be +- * sign that SS is enabled*/ +- if (res == BP_RESULT_OK && ss_info.spread_spectrum_percentage != 0) { +- disp_clk->ss_on_gpu_pll = true; +- disp_clk->gpu_pll_ss_divider = +- ss_info.spread_percentage_divider; +- if (ss_info.type.CENTER_MODE == 0) +- /* Currently we need only SS +- * percentage for down-spread*/ +- disp_clk->gpu_pll_ss_percentage = +- ss_info.spread_spectrum_percentage; +- } +- } +-} +- +-static bool display_clock_integrated_info_construct( +- struct display_clock_dce80 *disp_clk) +-{ +- struct dc_debug *debug = &disp_clk->disp_clk.ctx->dc->debug; +- struct dc_bios *bp = disp_clk->disp_clk.ctx->dc_bios; +- struct integrated_info info = { { { 0 } } }; +- struct firmware_info fw_info = { { 0 } }; +- uint32_t i; +- +- if (bp->integrated_info) +- info = *bp->integrated_info; +- +- disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq; +- if (disp_clk->dentist_vco_freq_khz == 0) { +- bp->funcs->get_firmware_info(bp, &fw_info); +- disp_clk->dentist_vco_freq_khz = +- fw_info.smu_gpu_pll_output_freq; +- if (disp_clk->dentist_vco_freq_khz == 0) +- disp_clk->dentist_vco_freq_khz = 3600000; +- } +- disp_clk->disp_clk.min_display_clk_threshold_khz = +- disp_clk->dentist_vco_freq_khz / 64; +- +- /* TODO: initialise disp_clk->dfs_bypass_disp_clk */ +- +- /*update the maximum display clock for each power state*/ +- for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { +- enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID; +- +- switch (i) { +- case 0: +- clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW; +- break; +- +- case 1: +- clk_state = DM_PP_CLOCKS_STATE_LOW; +- break; +- +- case 2: +- clk_state = DM_PP_CLOCKS_STATE_NOMINAL; +- break; +- +- case 3: +- clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE; +- break; +- +- default: +- clk_state = DM_PP_CLOCKS_STATE_INVALID; +- break; +- } +- +- /*Do not allow bad VBIOS/SBIOS to override with invalid values, +- * check for > 100MHz*/ +- if (info.disp_clk_voltage[i].max_supported_clk >= 100000) { +- max_clks_by_state[clk_state].display_clk_khz = +- info.disp_clk_voltage[i].max_supported_clk; +- } +- } +- +- disp_clk->dfs_bypass_enabled = false; +- if (!debug->disable_dfs_bypass) +- if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) +- disp_clk->dfs_bypass_enabled = true; +- +- disp_clk->use_max_disp_clk = debug->max_disp_clk; +- +- return true; +-} +- +-static void destroy(struct display_clock **dc) +-{ +- struct display_clock_dce80 *disp_clk; +- +- disp_clk = FROM_DISPLAY_CLOCK(*dc); +- dm_free(disp_clk); +- *dc = NULL; +-} +- +-static const struct display_clock_funcs funcs = { +- .destroy = destroy, +- .get_dp_ref_clk_frequency = get_dp_ref_clk_frequency, +- .get_required_clocks_state = get_required_clocks_state, +- .set_clock = dce80_set_clock, +- .set_min_clocks_state = dce80_set_min_clocks_state +-}; +- +- +-struct display_clock *dal_display_clock_dce80_create( +- struct dc_context *ctx) +-{ +- struct display_clock_dce80 *disp_clk; +- struct display_clock *dc_base; +- +- disp_clk = dm_alloc(sizeof(struct display_clock_dce80)); +- +- if (disp_clk == NULL) +- return NULL; +- +- dc_base = &disp_clk->disp_clk; +- +- dc_base->ctx = ctx; +- dc_base->min_display_clk_threshold_khz = 0; +- +- dc_base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID; +- +- dc_base->funcs = &funcs; +- /* +- * set_dp_ref_clock_source +- * set_clock_state +- * get_clock_state +- * get_dfs_bypass_threshold +- */ +- +- disp_clk->gpu_pll_ss_percentage = 0; +- disp_clk->gpu_pll_ss_divider = 1000; +- disp_clk->ss_on_gpu_pll = false; +- disp_clk->dfs_bypass_enabled = false; +- disp_clk->dfs_bypass_disp_clk = 0; +- disp_clk->use_max_disp_clk = true;/* false will hang the system! */ +- +-/* Initially set max clocks state to nominal. This should be updated by +- * via a pplib call to DAL IRI eventually calling a +- * DisplayEngineClock_Dce50::StoreMaxClocksState(). This call will come in +- * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/ +- dc_base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; +-/* Initially set current min clocks state to invalid since we +- * cannot make any assumption about PPLIB's initial state. This will be updated +- * by HWSS via SetMinClocksState() on first mode set prior to programming +- * state dependent clocks.*/ +- disp_clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID; +- +- display_clock_ss_construct(disp_clk); +- +- if (!display_clock_integrated_info_construct(disp_clk)) { +- dm_logger_write(dc_base->ctx->logger, LOG_WARNING, +- "Cannot obtain VBIOS integrated info"); +- } +- +- dal_divider_range_construct( +- ÷r_ranges[DIVIDER_RANGE_01], +- DIVIDER_RANGE_01_START, +- DIVIDER_RANGE_01_STEP_SIZE, +- DIVIDER_RANGE_01_BASE_DIVIDER_ID, +- DIVIDER_RANGE_02_BASE_DIVIDER_ID); +- dal_divider_range_construct( +- ÷r_ranges[DIVIDER_RANGE_02], +- DIVIDER_RANGE_02_START, +- DIVIDER_RANGE_02_STEP_SIZE, +- DIVIDER_RANGE_02_BASE_DIVIDER_ID, +- DIVIDER_RANGE_03_BASE_DIVIDER_ID); +- dal_divider_range_construct( +- ÷r_ranges[DIVIDER_RANGE_03], +- DIVIDER_RANGE_03_START, +- DIVIDER_RANGE_03_STEP_SIZE, +- DIVIDER_RANGE_03_BASE_DIVIDER_ID, +- DIVIDER_RANGE_MAX_DIVIDER_ID); +- +- dm_free(disp_clk); +- return NULL; +-} +- +diff --git a/drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.h b/drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.h +deleted file mode 100644 +index c155bb6..0000000 +--- a/drivers/gpu/drm/amd/display/dc/gpu/dce80/display_clock_dce80.h ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* +- * Copyright 2012-15 Advanced Micro Devices, Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: AMD +- * +- */ +-#ifndef __DAL_DISPLAY_CLOCK_DCE80_H__ +-#define __DAL_DISPLAY_CLOCK_DCE80_H__ +- +-#include "display_clock_interface.h" +- +-struct display_clock_dce80 { +- struct display_clock disp_clk; +- /* DFS input - GPUPLL VCO frequency - from VBIOS Firmware info. */ +- uint32_t dentist_vco_freq_khz; +- /* GPU PLL SS percentage (if down-spread enabled)*/ +- uint32_t gpu_pll_ss_percentage; +- /* GPU PLL SS percentage Divider (100 or 1000)*/ +- uint32_t gpu_pll_ss_divider; +- /* Flag for Enabled SS on GPU PLL*/ +- bool ss_on_gpu_pll; +- /* Current minimum display block clocks state*/ +- enum dm_pp_clocks_state cur_min_clks_state; +- /* DFS-bypass feature variable +- Cache the status of DFS-bypass feature*/ +- bool dfs_bypass_enabled; +- /* Cache the display clock returned by VBIOS if DFS-bypass is enabled. +- * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */ +- uint32_t dfs_bypass_disp_clk; +- bool use_max_disp_clk; +-}; +- +-struct display_clock *dal_display_clock_dce80_create( +- struct dc_context *ctx); +- +-#endif /* __DAL_DISPLAY_CLOCK_DCE80_H__ */ +diff --git a/drivers/gpu/drm/amd/display/include/display_clock_interface.h b/drivers/gpu/drm/amd/display/include/display_clock_interface.h +index 6ba8c09..53a0138 100644 +--- a/drivers/gpu/drm/amd/display/include/display_clock_interface.h ++++ b/drivers/gpu/drm/amd/display/include/display_clock_interface.h +@@ -41,10 +41,9 @@ struct state_dependent_clocks { + struct display_clock { + struct dc_context *ctx; + const struct display_clock_funcs *funcs; +- uint32_t min_display_clk_threshold_khz; +- /* Max display block clocks state*/ +- enum dm_pp_clocks_state max_clks_state; + ++ int min_display_clk_threshold_khz; ++ enum dm_pp_clocks_state max_clks_state; + enum dm_pp_clocks_state cur_min_clks_state; + }; + +@@ -61,15 +60,7 @@ struct display_clock_funcs { + + }; + +-struct display_clock *dal_display_clock_dce112_create( +- struct dc_context *ctx); +- +-struct display_clock *dal_display_clock_dce110_create( +- struct dc_context *ctx); +- +-struct display_clock *dal_display_clock_dce80_create( +- struct dc_context *ctx); +- + void dal_display_clock_destroy(struct display_clock **to_destroy); + ++ + #endif /* __DISPLAY_CLOCK_INTERFACE_H__ */ +-- +2.7.4 + |