Commit 47a05eca authored by Jesse Barnes's avatar Jesse Barnes Committed by Chris Wilson
Browse files

drm/i915: disable PCH ports if needed when disabling a CRTC



Disable any PCH ports associated with a pipe when disabling it.  This
should prevent transcoder disable failures due to ports still being on.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
[ickle: introduce *_PIPE_ENABLED() macro]
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent bed636ab
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -1440,6 +1440,7 @@
#define   LVDS_PORT_EN			(1 << 31)
/* Selects pipe B for LVDS data.  Must be set on pre-965. */
#define   LVDS_PIPEB_SELECT		(1 << 30)
#define   LVDS_PIPE_MASK		(1 << 30)
/* LVDS dithering flag on 965/g4x platform */
#define   LVDS_ENABLE_DITHER		(1 << 25)
/* LVDS sync polarity flags. Set to invert (i.e. negative) */
@@ -1479,6 +1480,9 @@
#define   LVDS_B0B3_POWER_DOWN		(0 << 2)
#define   LVDS_B0B3_POWER_UP		(3 << 2)

#define LVDS_PIPE_ENABLED(V, P) \
	(((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN))

/* Video Data Island Packet control */
#define VIDEO_DIP_DATA		0x61178
#define VIDEO_DIP_CTL		0x61170
@@ -2067,6 +2071,10 @@

#define   DP_PORT_EN			(1 << 31)
#define   DP_PIPEB_SELECT		(1 << 30)
#define   DP_PIPE_MASK			(1 << 30)

#define DP_PIPE_ENABLED(V, P) \
	(((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN))

/* Link training mode - select a suitable mode for each stage */
#define   DP_LINK_TRAIN_PAT_1		(0 << 28)
@@ -3180,11 +3188,15 @@
#define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
#define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)

#define ADPA_PIPE_ENABLED(V, P) \
	(((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE))

/* or SDVOB */
#define HDMIB   0xe1140
#define  PORT_ENABLE    (1 << 31)
#define  TRANSCODER_A   (0)
#define  TRANSCODER_B   (1 << 30)
#define  TRANSCODER_MASK   (1 << 30)
#define  COLOR_FORMAT_8bpc      (0)
#define  COLOR_FORMAT_12bpc     (3 << 26)
#define  SDVOB_HOTPLUG_ENABLE   (1 << 23)
@@ -3200,6 +3212,9 @@
#define  HSYNC_ACTIVE_HIGH      (1 << 3)
#define  PORT_DETECTED          (1 << 2)

#define HDMI_PIPE_ENABLED(V, P) \
	(((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE))

/* PCH SDVOB multiplex with HDMIB */
#define PCH_SDVOB	HDMIB

+59 −25
Original line number Diff line number Diff line
@@ -1270,12 +1270,8 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
				   enum pipe pipe, int reg)
{
	u32 val;
	u32 sel_pipe;

	val = I915_READ(reg);
	sel_pipe = (val & DP_PIPEB_SELECT) >> 30;
	WARN((val & DP_PORT_EN) && sel_pipe == pipe,
	u32 val = I915_READ(reg);
	WARN(DP_PIPE_ENABLED(val, pipe),
	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
	     reg, pipe_name(pipe));
}
@@ -1283,12 +1279,8 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
				     enum pipe pipe, int reg)
{
	u32 val;
	u32 sel_pipe;

	val = I915_READ(reg);
	sel_pipe = (val & TRANSCODER_B) >> 30;
	WARN((val & PORT_ENABLE) && sel_pipe == pipe,
	u32 val = I915_READ(reg);
	WARN(HDMI_PIPE_ENABLED(val, pipe),
	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
	     reg, pipe_name(pipe));
}
@@ -1298,7 +1290,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
{
	int reg;
	u32 val;
	u32 sel_pipe;

	assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B);
	assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C);
@@ -1306,15 +1297,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,

	reg = PCH_ADPA;
	val = I915_READ(reg);
	sel_pipe = (val & ADPA_TRANS_B_SELECT) >> 30;
	WARN(sel_pipe == pipe && (val & ADPA_DAC_ENABLE),
	WARN(ADPA_PIPE_ENABLED(val, pipe),
	     "PCH VGA enabled on transcoder %c, should be disabled\n",
	     pipe_name(pipe));

	reg = PCH_LVDS;
	val = I915_READ(reg);
	sel_pipe = (val & LVDS_PIPEB_SELECT) >> 30;
	WARN(sel_pipe == pipe && (val & LVDS_PORT_EN),
	WARN(LVDS_PIPE_ENABLED(val, pipe),
	     "PCH LVDS enabled on transcoder %c, should be disabled\n",
	     pipe_name(pipe));

@@ -1628,6 +1617,53 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
	intel_wait_for_vblank(dev_priv->dev, pipe);
}

static void disable_pch_dp(struct drm_i915_private *dev_priv,
			   enum pipe pipe, int reg)
{
	u32 val = I915_READ(reg);
	if (DP_PIPE_ENABLED(val, pipe))
		I915_WRITE(reg, val & ~DP_PORT_EN);
}

static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
			     enum pipe pipe, int reg)
{
	u32 val = I915_READ(reg);
	if (HDMI_PIPE_ENABLED(val, pipe))
		I915_WRITE(reg, val & ~PORT_ENABLE);
}

/* Disable any ports connected to this transcoder */
static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
				    enum pipe pipe)
{
	u32 reg, val;

	val = I915_READ(PCH_PP_CONTROL);
	I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);

	disable_pch_dp(dev_priv, pipe, PCH_DP_B);
	disable_pch_dp(dev_priv, pipe, PCH_DP_C);
	disable_pch_dp(dev_priv, pipe, PCH_DP_D);

	reg = PCH_ADPA;
	val = I915_READ(reg);
	if (ADPA_PIPE_ENABLED(val, pipe))
		I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);

	reg = PCH_LVDS;
	val = I915_READ(reg);
	if (LVDS_PIPE_ENABLED(val, pipe)) {
		I915_WRITE(reg, val & ~LVDS_PORT_EN);
		POSTING_READ(reg);
		udelay(100);
	}

	disable_pch_hdmi(dev_priv, pipe, HDMIB);
	disable_pch_hdmi(dev_priv, pipe, HDMIC);
	disable_pch_hdmi(dev_priv, pipe, HDMID);
}

static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
{
	struct drm_device *dev = crtc->dev;
@@ -2864,14 +2900,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)

	ironlake_fdi_disable(crtc);

	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
		temp = I915_READ(PCH_LVDS);
		if (temp & LVDS_PORT_EN) {
			I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
			POSTING_READ(PCH_LVDS);
			udelay(100);
		}
	}
	/* This is a horrible layering violation; we should be doing this in
	 * the connector/encoder ->prepare instead, but we don't always have
	 * enough information there about the config to know whether it will
	 * actually be necessary or just cause undesired flicker.
	 */
	intel_disable_pch_ports(dev_priv, pipe);

	intel_disable_transcoder(dev_priv, pipe);