diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/1022-drm-amd-display-Compensate-for-XGMI-SS-downspread-on.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.19.8/1022-drm-amd-display-Compensate-for-XGMI-SS-downspread-on.patch | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/1022-drm-amd-display-Compensate-for-XGMI-SS-downspread-on.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/1022-drm-amd-display-Compensate-for-XGMI-SS-downspread-on.patch new file mode 100644 index 00000000..2bfcd1f2 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/1022-drm-amd-display-Compensate-for-XGMI-SS-downspread-on.patch @@ -0,0 +1,417 @@ +From b428ec219b34c4fb3e22433d47c1e39ab76dca41 Mon Sep 17 00:00:00 2001 +From: Leo Li <sunpeng.li@amd.com> +Date: Thu, 1 Nov 2018 11:10:18 -0400 +Subject: [PATCH 1022/2940] drm/amd/display: Compensate for XGMI SS downspread + on dprefclk + +[Why] +When XGMI is enabled, we need to adjust the dprefclk according to the +WAFL link's spread spectrum info. This is for VG20 (DCE121) only. + +[How] +dce_clk_mgr already stores SS info, currently being used by audio clock. +Therefore, patch the clk_mgr's SS info with the xGMI SS info, if xGMI +is enabled. For display clock, adjust it during dce12_update_clocks() +before calling set_clock(). + +Since we rely on a mmhub register to reliably determine if xGMI is +enabled, the patching step needs to happen after resource_construct() +has initialized the hardware sequencer. + +Signed-off-by: Leo Li <sunpeng.li@amd.com> +Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> +Acked-by: Harry Wentland <Harry.Wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + .../gpu/drm/amd/display/dc/dce/dce_clk_mgr.c | 64 +++++++++++++++ + .../gpu/drm/amd/display/dc/dce/dce_clk_mgr.h | 35 +++++++- + .../gpu/drm/amd/display/dc/dce/dce_hwseq.h | 12 +++ + .../display/dc/dce120/dce120_hw_sequencer.c | 15 ++++ + .../display/dc/dce120/dce120_hw_sequencer.h | 1 + + .../amd/display/dc/dce120/dce120_resource.c | 81 +++++++++++++++++-- + 6 files changed, 198 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c +index 2579478ae622..2c64333fa8f8 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c +@@ -447,6 +447,42 @@ void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce) + } + } + ++/** ++ * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info ++ * @clk_mgr: clock manager base structure ++ * ++ * Reads from VBIOS the XGMI spread spectrum info and saves it within ++ * the dce clock manager. This operation will overwrite the existing dprefclk ++ * SS values if the vBIOS query succeeds. Otherwise, it does nothing. It also ++ * sets the ->xgmi_enabled flag. ++ */ ++void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr) ++{ ++ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr); ++ enum bp_result result; ++ struct spread_spectrum_info info = { { 0 } }; ++ struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios; ++ ++ clk_mgr_dce->xgmi_enabled = false; ++ ++ result = bp->funcs->get_spread_spectrum_info(bp, AS_SIGNAL_TYPE_XGMI, ++ 0, &info); ++ if (result == BP_RESULT_OK && info.spread_spectrum_percentage != 0) { ++ clk_mgr_dce->xgmi_enabled = true; ++ clk_mgr_dce->ss_on_dprefclk = true; ++ clk_mgr_dce->dprefclk_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_mgr_dce->dprefclk_ss_percentage = ++ info.spread_spectrum_percentage; ++ } ++ } ++} ++ + void dce110_fill_display_configs( + const struct dc_state *context, + struct dm_pp_display_configuration *pp_display_cfg) +@@ -712,6 +748,13 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr, + + if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; ++ /* ++ * When xGMI is enabled, the display clk needs to be adjusted ++ * with the WAFL link's SS percentage. ++ */ ++ if (clk_mgr_dce->xgmi_enabled) ++ patched_disp_clk = clk_mgr_adjust_dp_ref_freq_for_ss( ++ clk_mgr_dce, patched_disp_clk); + clock_voltage_req.clocks_in_khz = patched_disp_clk; + clk_mgr->clks.dispclk_khz = dce112_set_clock(clk_mgr, patched_disp_clk); + +@@ -877,6 +920,27 @@ struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx) + return &clk_mgr_dce->base; + } + ++struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx) ++{ ++ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), ++ GFP_KERNEL); ++ ++ if (clk_mgr_dce == NULL) { ++ BREAK_TO_DEBUGGER(); ++ return NULL; ++ } ++ ++ memcpy(clk_mgr_dce->max_clks_by_state, dce120_max_clks_by_state, ++ sizeof(dce120_max_clks_by_state)); ++ ++ dce_clk_mgr_construct(clk_mgr_dce, ctx, NULL, NULL, NULL); ++ ++ clk_mgr_dce->dprefclk_khz = 625000; ++ clk_mgr_dce->base.funcs = &dce120_funcs; ++ ++ return &clk_mgr_dce->base; ++} ++ + void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr) + { + struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr); +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h +index 3bceb31d910d..c8f8c442142a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h +@@ -94,11 +94,37 @@ struct dce_clk_mgr { + * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */ + int dfs_bypass_disp_clk; + +- /* Flag for Enabled SS on DPREFCLK */ ++ /** ++ * @ss_on_dprefclk: ++ * ++ * True if spread spectrum is enabled on the DP ref clock. ++ */ + bool ss_on_dprefclk; +- /* DPREFCLK SS percentage (if down-spread enabled) */ ++ ++ /** ++ * @xgmi_enabled: ++ * ++ * True if xGMI is enabled. On VG20, both audio and display clocks need ++ * to be adjusted with the WAFL link's SS info if xGMI is enabled. ++ */ ++ bool xgmi_enabled; ++ ++ /** ++ * @dprefclk_ss_percentage: ++ * ++ * DPREFCLK SS percentage (if down-spread enabled). ++ * ++ * Note that if XGMI is enabled, the SS info (percentage and divider) ++ * from the WAFL link is used instead. This is decided during ++ * dce_clk_mgr initialization. ++ */ + int dprefclk_ss_percentage; +- /* DPREFCLK SS percentage Divider (100 or 1000) */ ++ ++ /** ++ * @dprefclk_ss_divider: ++ * ++ * DPREFCLK SS percentage Divider (100 or 1000). ++ */ + int dprefclk_ss_divider; + int dprefclk_khz; + +@@ -163,6 +189,9 @@ struct clk_mgr *dce112_clk_mgr_create( + + struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx); + ++struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx); ++void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr); ++ + void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr); + + int dentist_get_divider_from_did(int did); +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +index c83a7f05f14c..956bdf14503f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +@@ -133,6 +133,10 @@ + SR(DCHUB_AGP_TOP), \ + BL_REG_LIST() + ++#define HWSEQ_VG20_REG_LIST() \ ++ HWSEQ_DCE120_REG_LIST(),\ ++ MMHUB_SR(MC_VM_XGMI_LFB_CNTL) ++ + #define HWSEQ_DCE112_REG_LIST() \ + HWSEQ_DCE10_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \ +@@ -298,6 +302,7 @@ struct dce_hwseq_registers { + uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB; + uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR; + uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR; ++ uint32_t MC_VM_XGMI_LFB_CNTL; + uint32_t AZALIA_AUDIO_DTO; + uint32_t AZALIA_CONTROLLER_CLOCK_GATING; + }; +@@ -382,6 +387,11 @@ struct dce_hwseq_registers { + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + ++#define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\ ++ HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\ ++ HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_LFB_REGION, mask_sh),\ ++ HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, mask_sh) ++ + #define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ + HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \ +@@ -470,6 +480,8 @@ struct dce_hwseq_registers { + type PHYSICAL_PAGE_NUMBER_MSB;\ + type PHYSICAL_PAGE_NUMBER_LSB;\ + type LOGICAL_ADDR; \ ++ type PF_LFB_REGION;\ ++ type PF_MAX_REGION;\ + type ENABLE_L1_TLB;\ + type SYSTEM_ACCESS_MODE;\ + type LVTMA_BLON;\ +diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +index eb0f5f9a973b..1ca30928025e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +@@ -244,6 +244,21 @@ static void dce120_update_dchub( + dh_data->dchub_info_valid = false; + } + ++/** ++ * dce121_xgmi_enabled() - Check if xGMI is enabled ++ * @hws: DCE hardware sequencer object ++ * ++ * Return true if xGMI is enabled. False otherwise. ++ */ ++bool dce121_xgmi_enabled(struct dce_hwseq *hws) ++{ ++ uint32_t pf_max_region; ++ ++ REG_GET(MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, &pf_max_region); ++ /* PF_MAX_REGION == 0 means xgmi is disabled */ ++ return !!pf_max_region; ++} ++ + void dce120_hw_sequencer_construct(struct dc *dc) + { + /* All registers used by dce11.2 match those in dce11 in offset and +diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h +index 77a6b86d7606..c51afbd0b012 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h +@@ -30,6 +30,7 @@ + + struct dc; + ++bool dce121_xgmi_enabled(struct dce_hwseq *hws); + void dce120_hw_sequencer_construct(struct dc *dc); + + #endif /* __DC_HWSS_DCE112_H__ */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +index f12696674eb0..48a210ec975b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +@@ -62,6 +62,8 @@ + #include "soc15_hw_ip.h" + #include "vega10_ip_offset.h" + #include "nbio/nbio_6_1_offset.h" ++#include "mmhub/mmhub_9_4_0_offset.h" ++#include "mmhub/mmhub_9_4_0_sh_mask.h" + #include "reg_helper.h" + + #include "dce100/dce100_resource.h" +@@ -139,6 +141,17 @@ static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = { + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + ++/* MMHUB */ ++#define MMHUB_BASE_INNER(seg) \ ++ MMHUB_BASE__INST0_SEG ## seg ++ ++#define MMHUB_BASE(seg) \ ++ MMHUB_BASE_INNER(seg) ++ ++#define MMHUB_SR(reg_name)\ ++ .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ ++ mm ## reg_name ++ + /* macros to expend register list macro defined in HW object header file + * end *********************/ + +@@ -681,6 +694,19 @@ static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE12_MASK_SH_LIST(_MASK) + }; + ++/* HWSEQ regs for VG20 */ ++static const struct dce_hwseq_registers dce121_hwseq_reg = { ++ HWSEQ_VG20_REG_LIST() ++}; ++ ++static const struct dce_hwseq_shift dce121_hwseq_shift = { ++ HWSEQ_VG20_MASK_SH_LIST(__SHIFT) ++}; ++ ++static const struct dce_hwseq_mask dce121_hwseq_mask = { ++ HWSEQ_VG20_MASK_SH_LIST(_MASK) ++}; ++ + static struct dce_hwseq *dce120_hwseq_create( + struct dc_context *ctx) + { +@@ -695,6 +721,20 @@ static struct dce_hwseq *dce120_hwseq_create( + return hws; + } + ++static struct dce_hwseq *dce121_hwseq_create( ++ struct dc_context *ctx) ++{ ++ struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); ++ ++ if (hws) { ++ hws->ctx = ctx; ++ hws->regs = &dce121_hwseq_reg; ++ hws->shifts = &dce121_hwseq_shift; ++ hws->masks = &dce121_hwseq_mask; ++ } ++ return hws; ++} ++ + static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, +@@ -702,6 +742,14 @@ static const struct resource_create_funcs res_create_funcs = { + .create_hwseq = dce120_hwseq_create, + }; + ++static const struct resource_create_funcs dce121_res_create_funcs = { ++ .read_dce_straps = read_dce_straps, ++ .create_audio = create_audio, ++ .create_stream_encoder = dce120_stream_encoder_create, ++ .create_hwseq = dce121_hwseq_create, ++}; ++ ++ + #define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) } + static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), +@@ -911,7 +959,8 @@ static bool construct( + int j; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data irq_init_data; +- bool harvest_enabled = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev); ++ static const struct resource_create_funcs *res_funcs; ++ bool is_vg20 = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev); + uint32_t pipe_fuses; + + ctx->dc_bios->regs = &bios_regs; +@@ -975,7 +1024,11 @@ static bool construct( + } + } + +- pool->base.clk_mgr = dce120_clk_mgr_create(ctx); ++ if (is_vg20) ++ pool->base.clk_mgr = dce121_clk_mgr_create(ctx); ++ else ++ pool->base.clk_mgr = dce120_clk_mgr_create(ctx); ++ + if (pool->base.clk_mgr == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); +@@ -1008,14 +1061,14 @@ static bool construct( + if (!pool->base.irqs) + goto irqs_create_fail; + +- /* retrieve valid pipe fuses */ +- if (harvest_enabled) ++ /* VG20: Pipe harvesting enabled, retrieve valid pipe fuses */ ++ if (is_vg20) + pipe_fuses = read_pipe_fuses(ctx); + + /* index to valid pipe resource */ + j = 0; + for (i = 0; i < pool->base.pipe_count; i++) { +- if (harvest_enabled) { ++ if (is_vg20) { + if ((pipe_fuses & (1 << i)) != 0) { + dm_error("DC: skip invalid pipe %d!\n", i); + continue; +@@ -1093,10 +1146,24 @@ static bool construct( + pool->base.pipe_count = j; + pool->base.timing_generator_count = j; + +- if (!resource_construct(num_virtual_links, dc, &pool->base, +- &res_create_funcs)) ++ if (is_vg20) ++ res_funcs = &dce121_res_create_funcs; ++ else ++ res_funcs = &res_create_funcs; ++ ++ if (!resource_construct(num_virtual_links, dc, &pool->base, res_funcs)) + goto res_create_fail; + ++ /* ++ * This is a bit of a hack. The xGMI enabled info is used to determine ++ * if audio and display clocks need to be adjusted with the WAFL link's ++ * SS info. This is a responsiblity of the clk_mgr. But since MMHUB is ++ * under hwseq, and the relevant register is in MMHUB, we have to do it ++ * here. ++ */ ++ if (is_vg20 && dce121_xgmi_enabled(dc->hwseq)) ++ dce121_clock_patch_xgmi_ss_info(pool->base.clk_mgr); ++ + /* Create hardware sequencer */ + if (!dce120_hw_sequencer_create(dc)) + goto controller_create_fail; +-- +2.17.1 + |