From fcb5b31058fdc3bbba78871d8311e7e9c8272c1b Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin 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 Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- 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