diff mbox

[RFC,20/30] drm/i915: add TRANSCODER_EDP

Message ID 1346191621-12996-21-git-send-email-przanoni@gmail.com (mailing list archive)
State RFC
Headers show

Commit Message

Paulo Zanoni Aug. 28, 2012, 10:06 p.m. UTC
From: Paulo Zanoni <paulo.r.zanoni@intel.com>

Before Haswell we used to have 3 pipes (A, B and C) and 3 transcoders
(A, B and C), and there was an 1:1 mapping on then. Because of this
mapping, every register that was actually part of the transcoder was
called PIPE_SOMETHING instead of TRANSCODER_SOMETHING and its
definition used the PIPE macro.

Starting from Haswell, we have 3 pipes (A, B and C) but 4 transcoders
(A, B, C and EDP). Transcoder EDP can be connected to any of the 3
pipes, and as its name says, it is used by EDP.

So what we do here is:
  - Create "enum transcoder" just like "enum pipe", but with the
    additional TRANSCODER_EDP definition.
  - Make "enum transcoder" be part of "struct intel_crtc".
  - Create a TRANSCODER macro just like the PIPE macro.
  - Convert the transcoder registers to use the TRANSCODER macro
    instead of the PIPE macro.
  - Create the pipe_to_transcoder function to get the transcoder
    associated to a given pipe.
  - Make the code use the transcoder variable instead of pipe.
  - Correct assign TRANSCODER_EDP when needed.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |   8 +++
 drivers/gpu/drm/i915/i915_irq.c      |   7 ++-
 drivers/gpu/drm/i915/i915_reg.h      |  47 ++++++++--------
 drivers/gpu/drm/i915/intel_ddi.c     |  10 ++--
 drivers/gpu/drm/i915/intel_display.c | 104 +++++++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_dp.c      |   9 +--
 drivers/gpu/drm/i915/intel_drv.h     |   3 +
 7 files changed, 119 insertions(+), 69 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f5bbd1a..ceef8f5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -58,6 +58,14 @@  enum pipe {
 };
 #define pipe_name(p) ((p) + 'A')
 
+enum transcoder {
+	TRANSCODER_A = 0,
+	TRANSCODER_B,
+	TRANSCODER_C,
+	TRANSCODER_EDP = 0xF,
+};
+#define transcoder_name(t) ((t) + 'A')
+
 enum plane {
 	PLANE_A = 0,
 	PLANE_B,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0c8cb7f..d67d7eb 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -123,7 +123,9 @@  static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
+
+	return I915_READ(PIPECONF(transcoder)) & PIPECONF_ENABLE;
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -179,6 +181,7 @@  static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
 			     int *vpos, int *hpos)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 	u32 vbl = 0, position = 0;
 	int vbl_start, vbl_end, htotal, vtotal;
 	bool in_vbl = true;
@@ -211,7 +214,7 @@  static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
 		 */
 		position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
 
-		htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff);
+		htotal = 1 + ((I915_READ(HTOTAL(transcoder)) >> 16) & 0x1fff);
 		*vpos = position / htotal;
 		*hpos = position - (*vpos * htotal);
 	}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 9c9f288..4bf4cc9 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -29,6 +29,8 @@ 
 
 #define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
 
+#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a)))
+
 #define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a))
 #define _MASKED_BIT_DISABLE(a) ((a) << 16)
 
@@ -1550,15 +1552,14 @@ 
 #define _BCLRPAT_B	0x61020
 #define _VSYNCSHIFT_B	0x61028
 
-
-#define HTOTAL(pipe) _PIPE(pipe, _HTOTAL_A, _HTOTAL_B)
-#define HBLANK(pipe) _PIPE(pipe, _HBLANK_A, _HBLANK_B)
-#define HSYNC(pipe) _PIPE(pipe, _HSYNC_A, _HSYNC_B)
-#define VTOTAL(pipe) _PIPE(pipe, _VTOTAL_A, _VTOTAL_B)
-#define VBLANK(pipe) _PIPE(pipe, _VBLANK_A, _VBLANK_B)
-#define VSYNC(pipe) _PIPE(pipe, _VSYNC_A, _VSYNC_B)
-#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
-#define VSYNCSHIFT(pipe) _PIPE(pipe, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
+#define HTOTAL(tran)	_TRANSCODER(tran, _HTOTAL_A, _HTOTAL_B)
+#define HBLANK(tran)	_TRANSCODER(tran, _HBLANK_A, _HBLANK_B)
+#define HSYNC(tran)	_TRANSCODER(tran, _HSYNC_A, _HSYNC_B)
+#define VTOTAL(tran)	_TRANSCODER(tran, _VTOTAL_A, _VTOTAL_B)
+#define VBLANK(tran)	_TRANSCODER(tran, _VBLANK_A, _VBLANK_B)
+#define VSYNC(tran)	_TRANSCODER(tran, _VSYNC_A, _VSYNC_B)
+#define BCLRPAT(pipe)	_PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
+#define VSYNCSHIFT(tran) _TRANSCODER(tran, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
 /* VGA port control */
 #define ADPA			0x61100
@@ -2707,7 +2708,7 @@ 
 #define   PIPE_12BPC				(3 << 5)
 
 #define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC)
-#define PIPECONF(pipe) _PIPE(pipe, _PIPEACONF, _PIPEBCONF)
+#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF)
 #define PIPEDSL(pipe)  _PIPE(pipe, _PIPEADSL, _PIPEBDSL)
 #define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH)
 #define PIPEFRAMEPIXEL(pipe)  _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
@@ -3297,14 +3298,14 @@ 
 #define _PIPEB_LINK_M2           0x61048
 #define _PIPEB_LINK_N2           0x6104c
 
-#define PIPE_DATA_M1(pipe) _PIPE(pipe, _PIPEA_DATA_M1, _PIPEB_DATA_M1)
-#define PIPE_DATA_N1(pipe) _PIPE(pipe, _PIPEA_DATA_N1, _PIPEB_DATA_N1)
-#define PIPE_DATA_M2(pipe) _PIPE(pipe, _PIPEA_DATA_M2, _PIPEB_DATA_M2)
-#define PIPE_DATA_N2(pipe) _PIPE(pipe, _PIPEA_DATA_N2, _PIPEB_DATA_N2)
-#define PIPE_LINK_M1(pipe) _PIPE(pipe, _PIPEA_LINK_M1, _PIPEB_LINK_M1)
-#define PIPE_LINK_N1(pipe) _PIPE(pipe, _PIPEA_LINK_N1, _PIPEB_LINK_N1)
-#define PIPE_LINK_M2(pipe) _PIPE(pipe, _PIPEA_LINK_M2, _PIPEB_LINK_M2)
-#define PIPE_LINK_N2(pipe) _PIPE(pipe, _PIPEA_LINK_N2, _PIPEB_LINK_N2)
+#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1)
+#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1)
+#define PIPE_DATA_M2(tran) _TRANSCODER(tran, _PIPEA_DATA_M2, _PIPEB_DATA_M2)
+#define PIPE_DATA_N2(tran) _TRANSCODER(tran, _PIPEA_DATA_N2, _PIPEB_DATA_N2)
+#define PIPE_LINK_M1(tran) _TRANSCODER(tran, _PIPEA_LINK_M1, _PIPEB_LINK_M1)
+#define PIPE_LINK_N1(tran) _TRANSCODER(tran, _PIPEA_LINK_N1, _PIPEB_LINK_N1)
+#define PIPE_LINK_M2(tran) _TRANSCODER(tran, _PIPEA_LINK_M2, _PIPEB_LINK_M2)
+#define PIPE_LINK_N2(tran) _TRANSCODER(tran, _PIPEA_LINK_N2, _PIPEB_LINK_N2)
 
 /* CPU panel fitter */
 /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */
@@ -3724,8 +3725,8 @@ 
 #define HSW_VIDEO_DIP_VSC_ECC_B		0x61344
 #define HSW_VIDEO_DIP_GCP_B		0x61210
 
-#define HSW_TVIDEO_DIP_CTL(pipe) \
-	 _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
+#define HSW_TVIDEO_DIP_CTL(tran) \
+	 _TRANSCODER(tran, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
 #define HSW_TVIDEO_DIP_AVI_DATA(pipe) \
 	 _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
 #define HSW_TVIDEO_DIP_SPD_DATA(pipe) \
@@ -4378,8 +4379,8 @@ 
 #define PIPE_DDI_FUNC_CTL_B		0x61400
 #define PIPE_DDI_FUNC_CTL_C		0x62400
 #define PIPE_DDI_FUNC_CTL_EDP		0x6F400
-#define DDI_FUNC_CTL(pipe) _PIPE(pipe, PIPE_DDI_FUNC_CTL_A, \
-				       PIPE_DDI_FUNC_CTL_B)
+#define DDI_FUNC_CTL(tran) _TRANSCODER(tran, PIPE_DDI_FUNC_CTL_A, \
+					     PIPE_DDI_FUNC_CTL_B)
 #define  PIPE_DDI_FUNC_ENABLE		(1<<31)
 /* Those bits are ignored by pipe EDP since it can only connect to DDI A */
 #define  PIPE_DDI_PORT_MASK		(7<<28)
@@ -4528,7 +4529,7 @@ 
 
 #define _PIPEA_MSA_MISC			0x60410
 #define _PIPEB_MSA_MISC			0x61410
-#define PIPE_MSA_MISC(pipe) _PIPE(pipe, _PIPEA_MSA_MISC, _PIPEB_MSA_MISC)
+#define PIPE_MSA_MISC(tran) _TRANSCODER(tran, _PIPEA_MSA_MISC, _PIPEB_MSA_MISC)
 #define  PIPE_MSA_SYNC_CLK		(1<<0)
 #define  PIPE_MSA_6_BPC			(0<<5)
 #define  PIPE_MSA_8_BPC			(1<<5)
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index c2377b0..ad1fb5f 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -797,6 +797,7 @@  static void intel_ddi_enable_pipe(struct intel_encoder *intel_encoder)
 	struct drm_display_mode *mode = &crtc->mode;
 	int port;
 	int pipe = intel_crtc->pipe;
+	enum transcoder transcoder = intel_crtc->transcoder;
 	u32 func_val, msa_val;
 	struct intel_hdmi *intel_hdmi = NULL;
 	struct intel_dp *intel_dp = NULL;
@@ -864,10 +865,10 @@  static void intel_ddi_enable_pipe(struct intel_encoder *intel_encoder)
 			     intel_dp->lane_count);
 		}
 
-		I915_WRITE(PIPE_MSA_MISC(pipe), msa_val);
+		I915_WRITE(PIPE_MSA_MISC(transcoder), msa_val);
 	}
 
-	I915_WRITE(DDI_FUNC_CTL(pipe), func_val);
+	I915_WRITE(DDI_FUNC_CTL(transcoder), func_val);
 
 	if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
 		if (intel_hdmi->has_audio) {
@@ -988,12 +989,13 @@  void intel_ddi_commit(struct drm_encoder *encoder)
 static void intel_ddi_disable_pipe(struct drm_i915_private *dev_priv,
 				   enum pipe pipe)
 {
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 	uint32_t temp;
 
-	temp = I915_READ(DDI_FUNC_CTL(pipe));
+	temp = I915_READ(DDI_FUNC_CTL(transcoder));
 	temp &= ~(PIPE_DDI_FUNC_ENABLE | PIPE_DDI_PORT_MASK);
 	temp |= PIPE_DDI_PORT_NONE;
-	I915_WRITE(DDI_FUNC_CTL(pipe), temp);
+	I915_WRITE(DDI_FUNC_CTL(transcoder), temp);
 
 	I915_WRITE(PIPE_CLK_SEL(pipe), PIPE_CLK_SEL_DISABLED);
 }
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 986d790..c7ba7ad 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -927,6 +927,15 @@  intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
 	return true;
 }
 
+enum transcoder pipe_to_transcoder(struct drm_i915_private *dev_priv,
+				   enum pipe pipe)
+{
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	return intel_crtc->transcoder;
+}
+
 static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -999,9 +1008,10 @@  void intel_wait_for_vblank(struct drm_device *dev, int pipe)
 void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 
 	if (INTEL_INFO(dev)->gen >= 4) {
-		int reg = PIPECONF(pipe);
+		int reg = PIPECONF(transcoder);
 
 		/* Wait for the Pipe State to go off */
 		if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
@@ -1100,13 +1110,14 @@  static void assert_pch_pll(struct drm_i915_private *dev_priv,
 static void assert_fdi_tx(struct drm_i915_private *dev_priv,
 			  enum pipe pipe, bool state)
 {
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 	int reg;
 	u32 val;
 	bool cur_state;
 
 	if (IS_HASWELL(dev_priv->dev)) {
 		/* On Haswell, DDI is used instead of FDI_TX_CTL */
-		reg = DDI_FUNC_CTL(pipe);
+		reg = DDI_FUNC_CTL(transcoder);
 		val = I915_READ(reg);
 		cur_state = !!(val & PIPE_DDI_FUNC_ENABLE);
 	} else {
@@ -1209,6 +1220,7 @@  static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
 void assert_pipe(struct drm_i915_private *dev_priv,
 		 enum pipe pipe, bool state)
 {
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 	int reg;
 	u32 val;
 	bool cur_state;
@@ -1217,7 +1229,7 @@  void assert_pipe(struct drm_i915_private *dev_priv,
 	if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
 		state = true;
 
-	reg = PIPECONF(pipe);
+	reg = PIPECONF(transcoder);
 	val = I915_READ(reg);
 	cur_state = !!(val & PIPECONF_ENABLE);
 	WARN(cur_state != state,
@@ -1649,6 +1661,7 @@  static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
 	int reg;
 	u32 val, pipeconf_val;
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 
 	/* PCH only available on ILK+ */
 	BUG_ON(dev_priv->info->gen < 5);
@@ -1668,7 +1681,7 @@  static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
 	}
 	reg = TRANSCONF(pipe);
 	val = I915_READ(reg);
-	pipeconf_val = I915_READ(PIPECONF(pipe));
+	pipeconf_val = I915_READ(PIPECONF(transcoder));
 
 	if (HAS_PCH_IBX(dev_priv->dev)) {
 		/*
@@ -1733,6 +1746,7 @@  static void intel_disable_transcoder(struct drm_i915_private *dev_priv,
 static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 			      bool pch_port)
 {
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 	int reg;
 	u32 val;
 
@@ -1752,7 +1766,7 @@  static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 		/* FIXME: assert CPU port conditions for SNB+ */
 	}
 
-	reg = PIPECONF(pipe);
+	reg = PIPECONF(transcoder);
 	val = I915_READ(reg);
 	if (val & PIPECONF_ENABLE)
 		return;
@@ -1775,6 +1789,7 @@  static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
  */
 void intel_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
+	enum transcoder transcoder = pipe_to_transcoder(dev_priv, pipe);
 	int reg;
 	u32 val;
 
@@ -1788,7 +1803,7 @@  void intel_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
 	if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
 		return;
 
-	reg = PIPECONF(pipe);
+	reg = PIPECONF(transcoder);
 	val = I915_READ(reg);
 	if ((val & PIPECONF_ENABLE) == 0)
 		return;
@@ -2713,6 +2728,7 @@  static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = intel_crtc->pipe;
+	enum transcoder transcoder = intel_crtc->transcoder;
 	u32 reg, temp;
 
 	/* Write the TU size bits so error detection works */
@@ -2724,7 +2740,7 @@  static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
 	temp = I915_READ(reg);
 	temp &= ~((0x7 << 19) | (0x7 << 16));
 	temp |= (intel_crtc->fdi_lanes - 1) << 19;
-	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	temp |= (I915_READ(PIPECONF(transcoder)) & PIPE_BPC_MASK) << 11;
 	I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
 	POSTING_READ(reg);
@@ -2798,6 +2814,7 @@  static void ironlake_fdi_disable(struct drm_crtc *crtc)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
+	enum transcoder transcoder = intel_crtc->transcoder;
 	u32 reg, temp;
 
 	/* disable CPU FDI tx and PCH FDI rx */
@@ -2809,7 +2826,7 @@  static void ironlake_fdi_disable(struct drm_crtc *crtc)
 	reg = FDI_RX_CTL(pipe);
 	temp = I915_READ(reg);
 	temp &= ~(0x7 << 16);
-	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	temp |= (I915_READ(PIPECONF(transcoder)) & PIPE_BPC_MASK) << 11;
 	I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
 
 	POSTING_READ(reg);
@@ -2843,7 +2860,7 @@  static void ironlake_fdi_disable(struct drm_crtc *crtc)
 	}
 	/* BPC in FDI rx is consistent with that in PIPECONF */
 	temp &= ~(0x07 << 16);
-	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	temp |= (I915_READ(PIPECONF(transcoder)) & PIPE_BPC_MASK) << 11;
 	I915_WRITE(reg, temp);
 
 	POSTING_READ(reg);
@@ -3005,6 +3022,7 @@  static void ironlake_pch_enable(struct drm_crtc *crtc)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
+	enum transcoder transcoder = intel_crtc->transcoder;
 	u32 reg, temp;
 
 	assert_transcoder_disabled(dev_priv, pipe);
@@ -3045,14 +3063,14 @@  static void ironlake_pch_enable(struct drm_crtc *crtc)
 
 	/* set transcoder timing, panel must allow it */
 	assert_panel_unlocked(dev_priv, pipe);
-	I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
-	I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
-	I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
+	I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(transcoder)));
+	I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(transcoder)));
+	I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(transcoder)));
 
-	I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
-	I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
-	I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
-	I915_WRITE(TRANS_VSYNCSHIFT(pipe),  I915_READ(VSYNCSHIFT(pipe)));
+	I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(transcoder)));
+	I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(transcoder)));
+	I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(transcoder)));
+	I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(transcoder)));
 
 	if (!IS_HASWELL(dev))
 		intel_fdi_normal_train(crtc);
@@ -3061,7 +3079,7 @@  static void ironlake_pch_enable(struct drm_crtc *crtc)
 	if (HAS_PCH_CPT(dev) &&
 	    (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
 	     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
-		u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) >> 5;
+		u32 bpc = (I915_READ(PIPECONF(transcoder)) & PIPE_BPC_MASK) >> 5;
 		reg = TRANS_DP_CTL(pipe);
 		temp = I915_READ(reg);
 		temp &= ~(TRANS_DP_PORT_SEL_MASK |
@@ -4579,6 +4597,7 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
+	enum transcoder transcoder;
 	int refclk, num_connectors = 0;
 	intel_clock_t clock, reduced_clock;
 	u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
@@ -4627,10 +4646,17 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 		num_connectors++;
 	}
 
-	if (IS_HASWELL(dev))
+	if (IS_HASWELL(dev)) {
 		if (!intel_ddi_pll_mode_set(crtc))
 			return -EINVAL;
 
+		if (is_cpu_edp)
+			intel_crtc->transcoder = TRANSCODER_EDP;
+		else
+			intel_crtc->transcoder = pipe;
+	}
+	transcoder = intel_crtc->transcoder;
+
 	refclk = ironlake_get_refclk(crtc);
 
 	/*
@@ -4694,7 +4720,7 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 		target_clock = adjusted_mode->clock;
 
 	/* determine panel color depth */
-	temp = I915_READ(PIPECONF(pipe));
+	temp = I915_READ(PIPECONF(transcoder));
 	temp &= ~PIPE_BPC_MASK;
 	dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
 	switch (pipe_bpp) {
@@ -4719,7 +4745,7 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	}
 
 	intel_crtc->bpp = pipe_bpp;
-	I915_WRITE(PIPECONF(pipe), temp);
+	I915_WRITE(PIPECONF(transcoder), temp);
 
 	if (!lane) {
 		/*
@@ -4804,7 +4830,7 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 		dpll |= PLL_REF_INPUT_DREFCLK;
 
 	/* setup pipeconf */
-	pipeconf = I915_READ(PIPECONF(pipe));
+	pipeconf = I915_READ(PIPECONF(transcoder));
 
 	/* Set up the display plane register */
 	dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -4915,31 +4941,31 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 		/* the chip adds 2 halflines automatically */
 		adjusted_mode->crtc_vtotal -= 1;
 		adjusted_mode->crtc_vblank_end -= 1;
-		I915_WRITE(VSYNCSHIFT(pipe),
+		I915_WRITE(VSYNCSHIFT(transcoder),
 			   adjusted_mode->crtc_hsync_start
 			   - adjusted_mode->crtc_htotal/2);
 	} else {
 		pipeconf |= PIPECONF_PROGRESSIVE;
-		I915_WRITE(VSYNCSHIFT(pipe), 0);
+		I915_WRITE(VSYNCSHIFT(transcoder), 0);
 	}
 
-	I915_WRITE(HTOTAL(pipe),
+	I915_WRITE(HTOTAL(transcoder),
 		   (adjusted_mode->crtc_hdisplay - 1) |
 		   ((adjusted_mode->crtc_htotal - 1) << 16));
-	I915_WRITE(HBLANK(pipe),
+	I915_WRITE(HBLANK(transcoder),
 		   (adjusted_mode->crtc_hblank_start - 1) |
 		   ((adjusted_mode->crtc_hblank_end - 1) << 16));
-	I915_WRITE(HSYNC(pipe),
+	I915_WRITE(HSYNC(transcoder),
 		   (adjusted_mode->crtc_hsync_start - 1) |
 		   ((adjusted_mode->crtc_hsync_end - 1) << 16));
 
-	I915_WRITE(VTOTAL(pipe),
+	I915_WRITE(VTOTAL(transcoder),
 		   (adjusted_mode->crtc_vdisplay - 1) |
 		   ((adjusted_mode->crtc_vtotal - 1) << 16));
-	I915_WRITE(VBLANK(pipe),
+	I915_WRITE(VBLANK(transcoder),
 		   (adjusted_mode->crtc_vblank_start - 1) |
 		   ((adjusted_mode->crtc_vblank_end - 1) << 16));
-	I915_WRITE(VSYNC(pipe),
+	I915_WRITE(VSYNC(transcoder),
 		   (adjusted_mode->crtc_vsync_start - 1) |
 		   ((adjusted_mode->crtc_vsync_end - 1) << 16));
 
@@ -4959,8 +4985,8 @@  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	if (is_cpu_edp)
 		ironlake_set_pll_edp(crtc, adjusted_mode->clock);
 
-	I915_WRITE(PIPECONF(pipe), pipeconf);
-	POSTING_READ(PIPECONF(pipe));
+	I915_WRITE(PIPECONF(transcoder), pipeconf);
+	POSTING_READ(PIPECONF(transcoder));
 
 	intel_wait_for_vblank(dev, pipe);
 
@@ -5911,12 +5937,12 @@  struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int pipe = intel_crtc->pipe;
+	enum transcoder transcoder = intel_crtc->transcoder;
 	struct drm_display_mode *mode;
-	int htot = I915_READ(HTOTAL(pipe));
-	int hsync = I915_READ(HSYNC(pipe));
-	int vtot = I915_READ(VTOTAL(pipe));
-	int vsync = I915_READ(VSYNC(pipe));
+	int htot = I915_READ(HTOTAL(transcoder));
+	int hsync = I915_READ(HSYNC(transcoder));
+	int vtot = I915_READ(VTOTAL(transcoder));
+	int vsync = I915_READ(VSYNC(transcoder));
 
 	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
 	if (!mode)
@@ -6539,6 +6565,11 @@  static void intel_sanitize_modesetting(struct drm_device *dev,
 		reg = PIPECONF(i);
 		I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 	}
+	if (IS_HASWELL(dev)) {
+		reg = PIPECONF(TRANSCODER_EDP);
+		I915_WRITE(reg,
+			   I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+	}
 
 	if (HAS_PCH_SPLIT(dev))
 		return;
@@ -6651,6 +6682,7 @@  static void intel_crtc_init(struct drm_device *dev, int pipe)
 	/* Swap pipes & planes for FBC on pre-965 */
 	intel_crtc->pipe = pipe;
 	intel_crtc->plane = pipe;
+	intel_crtc->transcoder = pipe;
 	if (IS_MOBILE(dev) && IS_GEN3(dev)) {
 		DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
 		intel_crtc->plane = !pipe;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 531d49c..11c7d08 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -787,6 +787,7 @@  intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	int lane_count = 4;
 	struct intel_dp_m_n m_n;
 	int pipe = intel_crtc->pipe;
+	enum transcoder transcoder = intel_crtc->transcoder;
 
 	/*
 	 * Find the lane count in the intel_encoder private
@@ -811,12 +812,12 @@  intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 			     mode->clock, adjusted_mode->clock, &m_n);
 
 	if (IS_HASWELL(dev)) {
-		I915_WRITE(PIPE_DATA_M1(pipe),
+		I915_WRITE(PIPE_DATA_M1(transcoder),
 			   ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 			   m_n.gmch_m);
-		I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
-		I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
-		I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
+		I915_WRITE(PIPE_DATA_N1(transcoder), m_n.gmch_n);
+		I915_WRITE(PIPE_LINK_M1(transcoder), m_n.link_m);
+		I915_WRITE(PIPE_LINK_N1(transcoder), m_n.link_n);
 	} else if (HAS_PCH_SPLIT(dev)) {
 		I915_WRITE(TRANSDATA_M1(pipe),
 			   ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a8ef8ca..01173d4 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -153,6 +153,7 @@  struct intel_crtc {
 	struct drm_crtc base;
 	enum pipe pipe;
 	enum plane plane;
+	enum transcoder transcoder;
 	u8 lut_r[256], lut_g[256], lut_b[256];
 	int dpms_mode;
 	bool active; /* is the crtc on? independent of the dpms mode */
@@ -435,6 +436,8 @@  extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
 						    struct drm_crtc *crtc);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
+extern enum transcoder pipe_to_transcoder(struct drm_i915_private *dev_priv,
+					  enum pipe pipe);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
 extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);