Commit 508f5fcb authored by Leo Li's avatar Leo Li Committed by Alex Deucher
Browse files

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: default avatarLeo Li <sunpeng.li@amd.com>
Reviewed-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 09f609c3
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -450,6 +450,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)
@@ -710,6 +746,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);

@@ -875,6 +918,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);
+32 −3
Original line number Diff line number Diff line
@@ -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);
+12 −0
Original line number Diff line number Diff line
@@ -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;\
+15 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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__ */
Loading