Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit adc7f04b authored by Imre Deak's avatar Imre Deak
Browse files

drm/i915/bxt: Add HW state verification for DDI PHY and CDCLK



I caught a few errors in our current PHY/CDCLK programming by sanity
checking the actual programmed state, so I thought it would be also
useful for the future. In addition to verifying the state after
programming it also verify it after exiting DC5, to make sure DMC
restored/kept intact everything related.

v2:
- Inlining __phy_reg_verify_state() doesn't make sense and also
  incorrect, so don't do it (PW/CI gcc)
v3:
- Rebase on latest -nightly

Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarDavid Weinehall <david.weinehall@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1459780030-15781-1-git-send-email-imre.deak@intel.com
parent bd480061
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1924,6 +1924,7 @@ struct drm_i915_private {
	 * crappiness (can't read out DPLL_MD for pipes B & C).
	 */
	u32 chv_dpll_md[I915_MAX_PIPES];
	u32 bxt_phy_grc;

	u32 suspend_count;
	bool suspended_to_idle;
+122 −2
Original line number Diff line number Diff line
@@ -1753,6 +1753,13 @@ static bool broxton_phy_is_enabled(struct drm_i915_private *dev_priv,
	return true;
}

static u32 broxton_get_grc(struct drm_i915_private *dev_priv, enum dpio_phy phy)
{
	u32 val = I915_READ(BXT_PORT_REF_DW6(phy));

	return (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
}

static void broxton_phy_init(struct drm_i915_private *dev_priv,
			     enum dpio_phy phy)
{
@@ -1762,6 +1769,9 @@ static void broxton_phy_init(struct drm_i915_private *dev_priv,
	if (broxton_phy_is_enabled(dev_priv, phy)) {
		DRM_DEBUG_DRIVER("DDI PHY %d already enabled, "
				 "won't reprogram it\n", phy);
		/* Still read out the GRC value for state verification */
		if (phy == DPIO_PHY1)
			dev_priv->bxt_phy_grc = broxton_get_grc(dev_priv, phy);

		return;
	}
@@ -1857,8 +1867,8 @@ static void broxton_phy_init(struct drm_i915_private *dev_priv,
			     10))
			DRM_ERROR("timeout waiting for PHY1 GRC\n");

		val = I915_READ(BXT_PORT_REF_DW6(DPIO_PHY1));
		val = (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
		val = dev_priv->bxt_phy_grc = broxton_get_grc(dev_priv,
							      DPIO_PHY1);
		grc_code = val << GRC_CODE_FAST_SHIFT |
			   val << GRC_CODE_SLOW_SHIFT |
			   val;
@@ -1901,6 +1911,116 @@ void broxton_ddi_phy_uninit(struct drm_i915_private *dev_priv)
	broxton_phy_uninit(dev_priv, DPIO_PHY0);
}

static bool __printf(6, 7)
__phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy,
		       i915_reg_t reg, u32 mask, u32 expected,
		       const char *reg_fmt, ...)
{
	struct va_format vaf;
	va_list args;
	u32 val;

	val = I915_READ(reg);
	if ((val & mask) == expected)
		return true;

	va_start(args, reg_fmt);
	vaf.fmt = reg_fmt;
	vaf.va = &args;

	DRM_DEBUG_DRIVER("DDI PHY %d reg %pV [%08x] state mismatch: "
			 "current %08x, expected %08x (mask %08x)\n",
			 phy, &vaf, reg.reg, val, (val & ~mask) | expected,
			 mask);

	va_end(args);

	return false;
}

static bool broxton_phy_verify_state(struct drm_i915_private *dev_priv,
				     enum dpio_phy phy)
{
	enum port port;
	u32 ports;
	uint32_t mask;
	bool ok;

#define _CHK(reg, mask, exp, fmt, ...)					\
	__phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt,	\
			       ## __VA_ARGS__)

	/* We expect the PHY to be always enabled */
	if (!broxton_phy_is_enabled(dev_priv, phy))
		return false;

	ok = true;

	if (phy == DPIO_PHY0)
		ports = BIT(PORT_B) | BIT(PORT_C);
	else
		ports = BIT(PORT_A);

	for_each_port_masked(port, ports) {
		int lane;

		for (lane = 0; lane < 4; lane++)
			ok &= _CHK(BXT_PORT_TX_DW14_LN(port, lane),
				    LATENCY_OPTIM,
				    lane != 1 ? LATENCY_OPTIM : 0,
				    "BXT_PORT_TX_DW14_LN(%d, %d)", port, lane);
	}

	/* PLL Rcomp code offset */
	ok &= _CHK(BXT_PORT_CL1CM_DW9(phy),
		    IREF0RC_OFFSET_MASK, 0xe4 << IREF0RC_OFFSET_SHIFT,
		    "BXT_PORT_CL1CM_DW9(%d)", phy);
	ok &= _CHK(BXT_PORT_CL1CM_DW10(phy),
		    IREF1RC_OFFSET_MASK, 0xe4 << IREF1RC_OFFSET_SHIFT,
		    "BXT_PORT_CL1CM_DW10(%d)", phy);

	/* Power gating */
	mask = OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | SUS_CLK_CONFIG;
	ok &= _CHK(BXT_PORT_CL1CM_DW28(phy), mask, mask,
		    "BXT_PORT_CL1CM_DW28(%d)", phy);

	if (phy == DPIO_PHY0)
		ok &= _CHK(BXT_PORT_CL2CM_DW6_BC,
			   DW6_OLDO_DYN_PWR_DOWN_EN, DW6_OLDO_DYN_PWR_DOWN_EN,
			   "BXT_PORT_CL2CM_DW6_BC");

	/*
	 * TODO: Verify BXT_PORT_CL1CM_DW30 bit OCL2_LDOFUSE_PWR_DIS,
	 * at least on stepping A this bit is read-only and fixed at 0.
	 */

	if (phy == DPIO_PHY0) {
		u32 grc_code = dev_priv->bxt_phy_grc;

		grc_code = grc_code << GRC_CODE_FAST_SHIFT |
			   grc_code << GRC_CODE_SLOW_SHIFT |
			   grc_code;
		mask = GRC_CODE_FAST_MASK | GRC_CODE_SLOW_MASK |
		       GRC_CODE_NOM_MASK;
		ok &= _CHK(BXT_PORT_REF_DW6(DPIO_PHY0), mask, grc_code,
			    "BXT_PORT_REF_DW6(%d)", DPIO_PHY0);

		mask = GRC_DIS | GRC_RDY_OVRD;
		ok &= _CHK(BXT_PORT_REF_DW8(DPIO_PHY0), mask, mask,
			    "BXT_PORT_REF_DW8(%d)", DPIO_PHY0);
	}

	return ok;
#undef _CHK
}

void broxton_ddi_phy_verify_state(struct drm_i915_private *dev_priv)
{
	if (!broxton_phy_verify_state(dev_priv, DPIO_PHY0) ||
	    !broxton_phy_verify_state(dev_priv, DPIO_PHY1))
		i915_report_error(dev_priv, "DDI PHY state mismatch\n");
}

void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
{
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+5 −0
Original line number Diff line number Diff line
@@ -5468,6 +5468,11 @@ static bool broxton_cdclk_is_enabled(struct drm_i915_private *dev_priv)
	return true;
}

bool broxton_cdclk_verify_state(struct drm_i915_private *dev_priv)
{
	return broxton_cdclk_is_enabled(dev_priv);
}

void broxton_init_cdclk(struct drm_i915_private *dev_priv)
{
	/* check if cd clock is enabled */
+2 −0
Original line number Diff line number Diff line
@@ -1226,8 +1226,10 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv);
void hsw_disable_pc8(struct drm_i915_private *dev_priv);
void broxton_init_cdclk(struct drm_i915_private *dev_priv);
void broxton_uninit_cdclk(struct drm_i915_private *dev_priv);
bool broxton_cdclk_verify_state(struct drm_i915_private *dev_priv);
void broxton_ddi_phy_init(struct drm_i915_private *dev_priv);
void broxton_ddi_phy_uninit(struct drm_i915_private *dev_priv);
void broxton_ddi_phy_verify_state(struct drm_i915_private *dev_priv);
void bxt_enable_dc9(struct drm_i915_private *dev_priv);
void bxt_disable_dc9(struct drm_i915_private *dev_priv);
void skl_init_cdclk(struct drm_i915_private *dev_priv);
+8 −0
Original line number Diff line number Diff line
@@ -799,6 +799,11 @@ static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
					  struct i915_power_well *power_well)
{
	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);

	if (IS_BROXTON(dev_priv)) {
		broxton_cdclk_verify_state(dev_priv);
		broxton_ddi_phy_verify_state(dev_priv);
	}
}

static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
@@ -2199,6 +2204,9 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv,
	broxton_init_cdclk(dev_priv);
	broxton_ddi_phy_init(dev_priv);

	broxton_cdclk_verify_state(dev_priv);
	broxton_ddi_phy_verify_state(dev_priv);

	if (resume && dev_priv->csr.dmc_payload)
		intel_csr_load_program(dev_priv);
}