Commit a046a0da authored by Matt Roper's avatar Matt Roper
Browse files

drm/i915/dg2: Add vswing programming for SNPS phys



Vswing programming for SNPS PHYs is just a single step -- look up the
value that corresponds to the voltage level from a table and program it
into the SNPS_PHY_TX_EQ register.

Bspec: 53920
Cc: Matt Atwood <matthew.s.atwood@intel.com>
Signed-off-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Reviewed-by: default avatarMatt Atwood <matthew.s.atwood@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210723174239.1551352-26-matthew.d.roper@intel.com
parent 865b73ea
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -1496,6 +1496,16 @@ static int intel_ddi_dp_level(struct intel_dp *intel_dp)
	return translate_signal_level(intel_dp, signal_levels);
}

static void
dg2_set_signal_levels(struct intel_dp *intel_dp,
		      const struct intel_crtc_state *crtc_state)
{
	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
	int level = intel_ddi_dp_level(intel_dp);

	intel_snps_phy_ddi_vswing_sequence(encoder, level);
}

static void
tgl_set_signal_levels(struct intel_dp *intel_dp,
		      const struct intel_crtc_state *crtc_state)
@@ -2563,6 +2573,9 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
	 */

	/* 7.e Configure voltage swing and related IO settings */
	if (IS_DG2(dev_priv))
		intel_snps_phy_ddi_vswing_sequence(encoder, level);
	else
		tgl_ddi_vswing_sequence(encoder, crtc_state, level);

	/*
@@ -3102,7 +3115,9 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
			    "[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n",
			    connector->base.id, connector->name);

	if (DISPLAY_VER(dev_priv) >= 12)
	if (IS_DG2(dev_priv))
		intel_snps_phy_ddi_vswing_sequence(encoder, U32_MAX);
	else if (DISPLAY_VER(dev_priv) >= 12)
		tgl_ddi_vswing_sequence(encoder, crtc_state, level);
	else if (DISPLAY_VER(dev_priv) == 11)
		icl_ddi_vswing_sequence(encoder, crtc_state, level);
@@ -4084,7 +4099,9 @@ intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
	dig_port->dp.set_link_train = intel_ddi_set_link_train;
	dig_port->dp.set_idle_link_train = intel_ddi_set_idle_link_train;

	if (DISPLAY_VER(dev_priv) >= 12)
	if (IS_DG2(dev_priv))
		dig_port->dp.set_signal_levels = dg2_set_signal_levels;
	else if (DISPLAY_VER(dev_priv) >= 12)
		dig_port->dp.set_signal_levels = tgl_set_signal_levels;
	else if (DISPLAY_VER(dev_priv) >= 11)
		dig_port->dp.set_signal_levels = icl_set_signal_levels;
+54 −0
Original line number Diff line number Diff line
@@ -21,6 +21,60 @@
 * since it is not handled by the shared DPLL framework as on other platforms.
 */

static const u32 dg2_ddi_translations[] = {
	/* VS 0, pre-emph 0 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 26),

	/* VS 0, pre-emph 1 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 33) |
		REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 6),

	/* VS 0, pre-emph 2 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 38) |
		REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 12),

	/* VS 0, pre-emph 3 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 43) |
		REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 19),

	/* VS 1, pre-emph 0 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 39),

	/* VS 1, pre-emph 1 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 44) |
		REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 8),

	/* VS 1, pre-emph 2 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 47) |
		REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 15),

	/* VS 2, pre-emph 0 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 52),

	/* VS 2, pre-emph 1 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 51) |
		REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 10),

	/* VS 3, pre-emph 0 */
	REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 62),
};

void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
					u32 level)
{
	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
	enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
	int n_entries, ln;

	n_entries = ARRAY_SIZE(dg2_ddi_translations);
	if (level >= n_entries)
		level = n_entries - 1;

	for (ln = 0; ln < 4; ln++)
		intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy),
			       dg2_ddi_translations[level]);
}

/*
 * Basic DP link rates with 100 MHz reference clock.
 */
+4 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@
#ifndef __INTEL_SNPS_PHY_H__
#define __INTEL_SNPS_PHY_H__

#include <linux/types.h>

struct intel_encoder;
struct intel_crtc_state;
struct intel_mpllb_state;
@@ -21,5 +23,7 @@ int intel_mpllb_calc_port_clock(struct intel_encoder *encoder,
				const struct intel_mpllb_state *pll_state);

int intel_snps_phy_check_hdmi_link_rate(int clock);
void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
					u32 level);

#endif /* __INTEL_SNPS_PHY_H__ */
+5 −0
Original line number Diff line number Diff line
@@ -2332,6 +2332,11 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define SNPS_PHY_REF_CONTROL(phy)		_MMIO_SNPS(phy, 0x168188)
#define   SNPS_PHY_REF_CONTROL_REF_RANGE	REG_GENMASK(31, 27)

#define SNPS_PHY_TX_EQ(ln, phy)			_MMIO_SNPS_LN(ln, phy, 0x168300)
#define   SNPS_PHY_TX_EQ_MAIN			REG_GENMASK(23, 18)
#define   SNPS_PHY_TX_EQ_POST			REG_GENMASK(15, 10)
#define   SNPS_PHY_TX_EQ_PRE			REG_GENMASK(7, 2)

/* The spec defines this only for BXT PHY0, but lets assume that this
 * would exist for PHY1 too if it had a second channel.
 */