[PATCH 03/21] drm/i915: Add DP Helper functions for Haswell

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Shobhit Kumar <shobhit.kumar at intel.com>

Need to program new helpers for mode set and dpms as most of the stuff is done
using DDI port. The current commit uses SPLL clock for SCC enabled panel and
LCPLL for Non-SSC.

Also Haswell has LPT and DDIs are moved on CPU side and has DP_BUF_CTL and
DP_TP_CTL so added a new TP (Transport) holder as well along with DP in intel_dp

Main stream attributes have to be set explicitely from HSW onwrads. So
programmed the same.

Note that in DP mode the value of port width must match the one in the
DDI_BUF_CTL for the DDI port attached to the pipe.

Signed-off-by: Shobhit Kumar <shobhit.kumar at intel.com>
Signed-off-by: Sateesh Kavuri <sateesh.kavuri at intel.com>
Signed-off-by: Eugeni Dodonov <eugeni.dodonov at intel.com>
Reviewed-by: Eugeni Dodonov <eugeni.dodonov at intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h  |  26 +++++-
 drivers/gpu/drm/i915/intel_ddi.c | 167 +++++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_dp.c  |  18 ++++-
 drivers/gpu/drm/i915/intel_drv.h |   8 ++
 4 files changed, 210 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 9dfc4c5..51398a8 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4289,6 +4289,7 @@
 #define  PIPE_DDI_BPC_6					(2<<20)
 #define  PIPE_DDI_BPC_12				(3<<20)
 #define  PIPE_DDI_BFI_ENABLE			(1<<4)
+#define  PIPE_DDI_PORT_WIDTH_MASK		(7<<1)
 #define  PIPE_DDI_PORT_WIDTH_X1			(0<<1)
 #define  PIPE_DDI_PORT_WIDTH_X2			(1<<1)
 #define  PIPE_DDI_PORT_WIDTH_X4			(3<<1)
@@ -4335,6 +4336,7 @@
 #define  DDI_BUF_EMP_800MV_3_5DB_HSW	(8<<24)   /* Sel8 */
 #define  DDI_BUF_EMP_MASK				(0xf<<24)
 #define  DDI_BUF_IS_IDLE				(1<<7)
+#define  DDI_PORT_WIDTH_MASK		(7<<1)
 #define  DDI_PORT_WIDTH_X1				(0<<1)
 #define  DDI_PORT_WIDTH_X2				(1<<1)
 #define  DDI_PORT_WIDTH_X4				(3<<1)
@@ -4427,9 +4429,31 @@
 #define LCPLL_CTL				0x130040
 #define  LCPLL_PLL_DISABLE		(1<<31)
 #define  LCPLL_PLL_LOCK			(1<<30)
-#define  LCPLL_CD_CLOCK_DISABLE	(1<<25)
+
+#define  LCPLL_PLL_REFERENCE_BLK	(2<<28)
+#define  LCPLL_PLL_REFERENCE_SSC	(3<<28)
+#define  LCPLL_PLL_REFERENCE_NON_SSC	(0<<28)
+#define	 LCPLL_PLL_REFERENCE_MASK	(0x3<<28)
+
+#define  LCPLL_CD_FREQ_SELECT_MASK      (0x3<<26)
+#define  LCPLL_CD_FREQ_450MHZ		(0x0<<26)
+#define  LCPLL_CD_FREQ_550MHZ		(0x1<<26)
+
+#define  LCPLL_CD_CLOCK_DISABLE		(1<<25)
+#define  LCPLL_ROOT_CD2X_CLOCK_DISABLE  (1<<24)
 #define  LCPLL_CD2X_CLOCK_DISABLE	(1<<23)
 
+#define HSW_MSA_CTL			0x60410
+#define  HSW_MSA_SYNC_CLK		(1<<0)
+#define  HSW_MSA_DYNAMIC_RANGE		(1<<3)
+#define  HSW_MSA_COLORIMETRY		(1<<4)
+#define  HSW_MSA_BPC_MASK		(7<<5)
+#define  HSW_MSA_BPC_6_BITS		(0<<5)
+#define  HSW_MSA_BPC_8_BITS		(1<<5)
+#define  HSW_MSA_BPC_10_BITS		(2<<5)
+#define  HSW_MSA_BPC_12_BITS		(3<<5)
+#define  HSW_MSA_BPC_16_BITS		(4<<5)
+
 /* Pipe WM_LINETIME - watermark line time */
 #define PIPE_WM_LINETIME_A		0x45270
 #define PIPE_WM_LINETIME_B		0x45274
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index f33fe1a..91ed708 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -729,10 +729,159 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
 	intel_hdmi->set_infoframes(encoder, adjusted_mode);
 }
 
+void
+intel_ddi_mode_set_dp(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	struct drm_crtc *crtc = intel_dp->base.base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int port = intel_dp->ddi_port;
+	int pipe = intel_crtc->pipe;
+	int port_width = PIPE_DDI_PORT_WIDTH_X1;
+	int temp;
+
+	DRM_DEBUG_KMS("Preparing DP DDI mode for Haswell on port %c, pipe %c\n",
+					port_name(port), pipe_name(pipe));
+
+	/* Turn on the eDP PLL if needed */
+	/* TBD: */
+
+	/*
+	 * There are two kinds of DP registers in HSW:
+	 * DDI CPU
+	 * LPT PCH
+	 */
+	/* Preserve the BIOS-computed detected bit. This is
+	 * supposed to be read-only.
+	 */
+	intel_dp->DP = I915_READ(DDI_BUF_CTL(intel_dp->ddi_port));
+	intel_dp->DP |= DDI_BUF_EMP_400MV_0DB_HSW;
+	intel_dp->TP = I915_READ(DP_TP_CTL(intel_dp->ddi_port));
+
+	intel_dp->DP &= ~(DDI_PORT_WIDTH_MASK);
+	switch (intel_dp->lane_count) {
+	case 1:
+		intel_dp->DP |= DDI_PORT_WIDTH_X1;
+		port_width = PIPE_DDI_PORT_WIDTH_X1;
+		break;
+	case 2:
+		intel_dp->DP |= DDI_PORT_WIDTH_X2;
+		port_width = PIPE_DDI_PORT_WIDTH_X2;
+		break;
+	case 4:
+		intel_dp->DP |= DDI_PORT_WIDTH_X4;
+		port_width = PIPE_DDI_PORT_WIDTH_X4;
+		break;
+	default:
+		BUG();
+	}
+
+	if (intel_dp->has_audio)
+		DRM_DEBUG_DRIVER("HSW DP Audio not yet supported\n");
+
+	memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+	intel_dp->link_configuration[0] = intel_dp->link_bw;
+	intel_dp->link_configuration[1] = intel_dp->lane_count;
+	intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B;
+	/*
+	 * Check for DPCD version > 1.1 and enhanced framing support
+	 */
+	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
+	    (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
+		intel_dp->link_configuration[1] |=
+			DP_LANE_COUNT_ENHANCED_FRAME_EN;
+	}
+
+	/* Enable LCPLL if disabled; required in all cases */
+	temp = I915_READ(LCPLL_CTL);
+	if (temp & LCPLL_PLL_DISABLE) {
+		temp &= ~LCPLL_PLL_DISABLE;
+		temp &= ~LCPLL_CD2X_CLOCK_DISABLE;
+		temp &= ~LCPLL_ROOT_CD2X_CLOCK_DISABLE;
+		temp &= ~LCPLL_CD_CLOCK_DISABLE;
+		temp = (temp & ~LCPLL_CD_FREQ_SELECT_MASK) |
+			LCPLL_CD_FREQ_450MHZ;
+		I915_WRITE(LCPLL_CTL, temp);
+		udelay(20);
+	}
+
+	if (IS_HASWELL(dev)) {
+		if (intel_dp->link_configuration[1] &
+				DP_LANE_COUNT_ENHANCED_FRAME_EN)
+			intel_dp->TP |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
+
+		/* Set the MSA bits, since from HSW onwards,
+		 * this has to be explictly set */
+		temp = I915_READ(HSW_MSA_CTL);
+		temp |= HSW_MSA_SYNC_CLK;
+		temp &= ~HSW_MSA_DYNAMIC_RANGE;
+		temp &= ~HSW_MSA_COLORIMETRY;
+		temp &= ~HSW_MSA_BPC_MASK;
+		temp |= HSW_MSA_BPC_8_BITS; /* Color depth */
+
+		I915_WRITE(HSW_MSA_CTL, temp);
+
+		if ((intel_dp->dpcd[DP_MAX_DOWNSPREAD] & 0x1) == 0x1) {
+			/* SSC Enabled Panel */
+			/* Configure SPLL, program the correct divider values
+			 * for the desired frequency and wait for warmup */
+			I915_WRITE(SPLL_CTL,
+					SPLL_PLL_ENABLE |
+					SPLL_PLL_SCC |
+					SPLL_PLL_FREQ_1350MHz);
+			udelay(20);
+
+			/* Use SPLL clock to drive the output to the dp port,
+			 * and tell the pipe to use this port for connection.
+			 */
+			I915_WRITE(PORT_CLK_SEL(port),
+					PORT_CLK_SEL_SPLL);
+			I915_WRITE(PIPE_CLK_SEL(pipe),
+					PIPE_CLK_SEL_PORT(port));
+		} else {
+			/* Non SSC Panel */
+			/* configure LCPLL for NON-SSC */
+			temp = I915_READ(LCPLL_CTL);
+			temp = (temp & ~LCPLL_PLL_REFERENCE_MASK) |
+				LCPLL_PLL_REFERENCE_NON_SSC;
+			I915_WRITE(LCPLL_CTL, temp);
+			udelay(20);
+
+			/* Use LCPLL clock to drive the output to the dp port,
+			 * and tell the pipe to use this port for connection.
+			 */
+			I915_WRITE(PORT_CLK_SEL(port),
+					PORT_CLK_SEL_LCPLL_1350);
+			I915_WRITE(PIPE_CLK_SEL(pipe),
+					PIPE_CLK_SEL_PORT(port));
+		}
+
+		/* Enable PIPE_DDI_FUNC_CTL for the pipe to work in DP mode */
+		temp = I915_READ(DDI_FUNC_CTL(pipe));
+		temp &= ~PIPE_DDI_PORT_MASK;
+		temp &= ~PIPE_DDI_BPC_12;
+		temp &= ~PIPE_DDI_PORT_WIDTH_MASK;
+		temp |= PIPE_DDI_SELECT_PORT(port) |
+			PIPE_DDI_MODE_SELECT_DP_SST |
+			port_width |
+			((intel_crtc->bpp > 24) ?
+			 PIPE_DDI_BPC_12 :
+			 PIPE_DDI_BPC_8) |
+			PIPE_DDI_FUNC_ENABLE;
+
+		I915_WRITE(DDI_FUNC_CTL(pipe), temp);
+	}
+}
+
 void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	int port = intel_hdmi->ddi_port;
 	u32 temp;
@@ -745,10 +894,16 @@ void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
 		temp |= DDI_BUF_CTL_ENABLE;
 	}
 
-	/* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
-	 * and swing/emphasis values are ignored so nothing special needs
-	 * to be done besides enabling the port.
-	 */
-	I915_WRITE(DDI_BUF_CTL(port),
-			temp);
+	if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+		DRM_DEBUG_DRIVER("DPMS is not yet enabled on DP port\n");
+		return;
+	} else {
+
+		/* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
+		 * and swing/emphasis values are ignored so nothing special
+		 * needs to be done besides enabling the port.
+		 */
+		I915_WRITE(DDI_BUF_CTL(port),
+				temp);
+	}
 }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e324c7a..f4c6e98 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -74,7 +74,7 @@ static bool is_cpu_edp(struct intel_dp *intel_dp)
 	return is_edp(intel_dp) && !is_pch_edp(intel_dp);
 }
 
-static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
+struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
 	return container_of(encoder, struct intel_dp, base.base);
 }
@@ -2339,6 +2339,14 @@ static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
 	.commit = intel_dp_commit,
 };
 
+static const struct drm_encoder_helper_funcs intel_dp_helper_funcs_hsw = {
+	.dpms = intel_ddi_dpms,
+	.mode_fixup = intel_dp_mode_fixup,
+	.prepare = intel_dp_prepare,
+	.mode_set = intel_ddi_mode_set_dp,
+	.commit = intel_dp_commit,
+};
+
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.detect = intel_dp_detect,
@@ -2482,7 +2490,13 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
 	drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
 			 DRM_MODE_ENCODER_TMDS);
-	drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
+
+	if (IS_HASWELL(dev))
+		drm_encoder_helper_add(&intel_encoder->base,
+						&intel_dp_helper_funcs_hsw);
+	else
+		drm_encoder_helper_add(&intel_encoder->base,
+						&intel_dp_helper_funcs);
 
 	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	drm_sysfs_connector_add(connector);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7cffb12..65b5b7c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -316,6 +316,7 @@ struct intel_dp {
 	struct intel_encoder base;
 	uint32_t output_reg;
 	uint32_t DP;
+	uint32_t TP;
 	uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
 	bool has_audio;
 	enum hdmi_force_audio force_audio;
@@ -390,6 +391,8 @@ extern void intel_mark_busy(struct drm_device *dev,
 			    struct drm_i915_gem_object *obj);
 extern bool intel_lvds_init(struct drm_device *dev);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
+extern struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder);
+
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		 struct drm_display_mode *adjusted_mode);
@@ -534,5 +537,10 @@ extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
 extern void intel_ddi_mode_set(struct drm_encoder *encoder,
 				struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode);
+void
+intel_ddi_mode_set_dp(struct drm_encoder *encoder,
+			struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode);
+
 
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.11.1



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux