[PATCH 48/49] drm/i915/bxt: VSwing programming sequence

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

 



From: Vandana Kannan <vandana.kannan@xxxxxxxxx>

VSwing programming sequence as specified in the updated BXT BSpec

v2: Satheesh's review comments addressed.
- clear value before setting into registers
- move print statement to bxt function
Other changes
- since signal level will not be set into DDI_BUF_CTL, the value need
  not be returned to intel_dp_set_signal_levels(). Making the bxt
  specific function to return void and setting signal_levels = 0 for
  bxt inside intel_dp_set_signal_levels()
- instead of signal levels, printing vswing level and pre-emphasis
  level
- in case none of the pre-emphasis levels or vswing levels are set,
  setting default of 400mV + 0dB

v3: Satheesh's review comments
- Check for mask before printing signal_levels.
- Removing redundant register writes
- Call intel_prepare_ddi_buffers only for HAS_PCH_SPLIT
- Making register write part generic as it will be required for HDMI as
  well.

Re-structure the code to include an array for vswing related values, set
signal levels

v4: Satheesh's review comments
- Rebase over latest renaming patches
- use hsw_signal_levels for HAS_DDI
Other changes
- Modified vswing_sequence() func definition
- Rebased on top of register macro definitions

v5: Satheesh's review comments
- Check ddi translation table size

v6: Imre's review comments
- removed comments in vswing sequence
- added vswing, pre-emphasis prints in intel_dp_set_signal_levels
- added comment explaining use of DP vswing values for eDP
- initialize n_entries and ddi_transaltion table based on encoder type
- create bxt_ddi_buf_trans structure and use decimal values
- adding a flag in bxt buffer translation table to indicate def entry

v7: (imre)
- squash in Vandana's "VSwing register definition",
  "HDMI VSwing programming", "Re-enable vswing programming",
  "Fix vswing sequence" patches
- use BXT_PORT_* regs directly instead of via a temp var
- simplify BXT_PORT_* macro definitions
- add code comment why we read lane while write group registers
- fix readout of DP_TRAIN_PRE_EMPHASIS in debug message

Signed-off-by: Vandana Kannan <vandana.kannan@xxxxxxxxx> (v6)
Signed-off-by: Imre Deak <imre.deak@xxxxxxxxx>
---
 drivers/gpu/drm/i915/i915_reg.h  |  61 ++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ddi.c | 120 ++++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_dp.c  |  64 ++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_drv.h |   2 +
 4 files changed, 244 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2e72283c..545b7cf 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1269,6 +1269,21 @@ enum bxt_phy {
 						     _PORT_REF_DW8_BC)
 
 /* BXT PHY PCS registers */
+#define _PORT_PCS_DW10_LN01_A		0x162428
+#define _PORT_PCS_DW10_LN01_B		0x6C428
+#define _PORT_PCS_DW10_LN01_C		0x6C828
+#define _PORT_PCS_DW10_GRP_A		0x162C28
+#define _PORT_PCS_DW10_GRP_B		0x6CC28
+#define _PORT_PCS_DW10_GRP_C		0x6CE28
+#define BXT_PORT_PCS_DW10_LN01(port)	_PORT3(port, _PORT_PCS_DW10_LN01_A, \
+						     _PORT_PCS_DW10_LN01_B, \
+						     _PORT_PCS_DW10_LN01_C)
+#define BXT_PORT_PCS_DW10_GRP(port)	_PORT3(port, _PORT_PCS_DW10_GRP_A,  \
+						     _PORT_PCS_DW10_GRP_B,  \
+						     _PORT_PCS_DW10_GRP_C)
+#define   TX2_SWING_CALC_INIT		(1 << 31)
+#define   TX1_SWING_CALC_INIT		(1 << 30)
+
 #define _PORT_PCS_DW12_LN01_A		0x162430
 #define _PORT_PCS_DW12_LN01_B		0x6C430
 #define _PORT_PCS_DW12_LN01_C		0x6C830
@@ -1294,6 +1309,52 @@ enum bxt_phy {
 #define BXT_LANE_OFFSET(lane)           (((lane) >> 1) * 0x200 +	\
 					 ((lane) & 1) * 0x80)
 
+#define _PORT_TX_DW2_LN0_A		0x162508
+#define _PORT_TX_DW2_LN0_B		0x6C508
+#define _PORT_TX_DW2_LN0_C		0x6C908
+#define _PORT_TX_DW2_GRP_A		0x162D08
+#define _PORT_TX_DW2_GRP_B		0x6CD08
+#define _PORT_TX_DW2_GRP_C		0x6CF08
+#define BXT_PORT_TX_DW2_GRP(port)	_PORT3(port, _PORT_TX_DW2_GRP_A,  \
+						     _PORT_TX_DW2_GRP_B,  \
+						     _PORT_TX_DW2_GRP_C)
+#define BXT_PORT_TX_DW2_LN0(port)	_PORT3(port, _PORT_TX_DW2_LN0_A,  \
+						     _PORT_TX_DW2_LN0_B,  \
+						     _PORT_TX_DW2_LN0_C)
+#define   MARGIN_000_SHIFT		16
+#define   MARGIN_000			(0xFF << MARGIN_000_SHIFT)
+#define   UNIQ_TRANS_SCALE_SHIFT	8
+#define   UNIQ_TRANS_SCALE		(0xFF << UNIQ_TRANS_SCALE_SHIFT)
+
+#define _PORT_TX_DW3_LN0_A		0x16250C
+#define _PORT_TX_DW3_LN0_B		0x6C50C
+#define _PORT_TX_DW3_LN0_C		0x6C90C
+#define _PORT_TX_DW3_GRP_A		0x162D0C
+#define _PORT_TX_DW3_GRP_B		0x6CD0C
+#define _PORT_TX_DW3_GRP_C		0x6CF0C
+#define BXT_PORT_TX_DW3_GRP(port)	_PORT3(port, _PORT_TX_DW3_GRP_A,  \
+						     _PORT_TX_DW3_GRP_B,  \
+						     _PORT_TX_DW3_GRP_C)
+#define BXT_PORT_TX_DW3_LN0(port)	_PORT3(port, _PORT_TX_DW3_LN0_A,  \
+						     _PORT_TX_DW3_LN0_B,  \
+						     _PORT_TX_DW3_LN0_C)
+#define   UNIQE_TRANGE_EN_METHOD	(1 << 27)
+
+#define _PORT_TX_DW4_LN0_A		0x162510
+#define _PORT_TX_DW4_LN0_B		0x6C510
+#define _PORT_TX_DW4_LN0_C		0x6C910
+#define _PORT_TX_DW4_GRP_A		0x162D10
+#define _PORT_TX_DW4_GRP_B		0x6CD10
+#define _PORT_TX_DW4_GRP_C		0x6CF10
+#define BXT_PORT_TX_DW4_LN0(port)	_PORT3(port, _PORT_TX_DW4_LN0_A,  \
+						     _PORT_TX_DW4_LN0_B,  \
+						     _PORT_TX_DW4_LN0_C)
+#define BXT_PORT_TX_DW4_GRP(port)	_PORT3(port, _PORT_TX_DW4_GRP_A,  \
+						     _PORT_TX_DW4_GRP_B,  \
+						     _PORT_TX_DW4_GRP_C)
+#define   DEEMPH_SHIFT			24
+#define   DE_EMPHASIS			(0xFF << DEEMPH_SHIFT)
+
 #define _PORT_TX_DW14_LN0_A		0x162538
 #define _PORT_TX_DW14_LN0_B		0x6C538
 #define _PORT_TX_DW14_LN0_C		0x6C938
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 5aa4dab..799f9fc 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -159,6 +159,48 @@ static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
 	{ 0x00004014, 0x00000087 },	/* 0:	800	1000	2   */
 };
 
+struct bxt_ddi_buf_trans {
+	u32 margin;	/* swing value */
+	u32 scale;	/* scale value */
+	u32 enable;	/* scale enable */
+	u32 deemphasis;
+	bool default_index; /* true if the entry represents default value */
+};
+
+/* BSpec does not define separate vswing/pre-emphasis values for eDP.
+ * Using DP values for eDP as well.
+ */
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
+					/* Idx	NT mV diff	db  */
+	{ 52,  0,    0, 128, true  },	/* 0:	400		0   */
+	{ 78,  0,    0, 85,  false },	/* 1:	400		3.5 */
+	{ 104, 0,    0, 64,  false },	/* 2:	400		6   */
+	{ 154, 0,    0, 43,  false },	/* 3:	400		9.5 */
+	{ 77,  0,    0, 128, false },	/* 4:	600		0   */
+	{ 116, 0,    0, 85,  false },	/* 5:	600		3.5 */
+	{ 154, 0,    0, 64,  false },	/* 6:	600		6   */
+	{ 102, 0,    0, 128, false },	/* 7:	800		0   */
+	{ 154, 0,    0, 85,  false },	/* 8:	800		3.5 */
+	{ 154, 0x9A, 1, 128, false },  /* 9:	1200		0   */
+};
+
+/* BSpec has 2 recommended values - entries 0 and 8.
+ * Using the entry with higher vswing.
+ */
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
+					/* Idx	NT mV diff	db  */
+	{ 52,  0,    0, 128, false },	/* 0:	400		0   */
+	{ 52,  0,    0, 85,  false },	/* 1:	400		3.5 */
+	{ 52,  0,    0, 64,  false },	/* 2:	400		6   */
+	{ 42,  0,    0, 43,  false },	/* 3:	400		9.5 */
+	{ 77,  0,    0, 128, false },	/* 4:	600		0   */
+	{ 77,  0,    0, 85,  false },	/* 5:	600		3.5 */
+	{ 77,  0,    0, 64,  false },	/* 6:	600		6   */
+	{ 102, 0,    0, 128, false },	/* 7:	800		0   */
+	{ 102, 0,    0, 85,  false },	/* 8:	800		3.5 */
+	{ 154, 0x9A, 1, 128, true },	/* 9:	1200		0   */
+};
+
 enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
@@ -210,7 +252,15 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev,
 	const struct ddi_buf_trans *ddi_translations_hdmi;
 	const struct ddi_buf_trans *ddi_translations;
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_BROXTON(dev)) {
+		if (!intel_dig_port_supports_hdmi(intel_dig_port))
+			return;
+
+		/* Vswing programming for HDMI */
+		bxt_ddi_vswing_sequence(dev, hdmi_level, port,
+					INTEL_OUTPUT_HDMI);
+		return;
+	} else if (IS_SKYLAKE(dev)) {
 		ddi_translations_fdi = NULL;
 		ddi_translations_dp = skl_ddi_translations_dp;
 		n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp);
@@ -1666,6 +1716,67 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
 			   TRANS_CLK_SEL_DISABLED);
 }
 
+void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
+			     enum port port, int type)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const struct bxt_ddi_buf_trans *ddi_translations;
+	u32 n_entries, i;
+	uint32_t val;
+
+	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
+		n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
+		ddi_translations = bxt_ddi_translations_dp;
+	} else if (type == INTEL_OUTPUT_HDMI) {
+		n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi);
+		ddi_translations = bxt_ddi_translations_hdmi;
+	} else {
+		DRM_DEBUG_KMS("Vswing programming not done for encoder %d\n",
+				type);
+		return;
+	}
+
+	/* Check if default value has to be used */
+	if (level >= n_entries ||
+	    (type == INTEL_OUTPUT_HDMI && level == HDMI_LEVEL_SHIFT_UNKNOWN)) {
+		for (i = 0; i < n_entries; i++) {
+			if (ddi_translations[i].default_index) {
+				level = i;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * While we write to the group register to program all lanes at once we
+	 * can read only lane registers and we pick lanes 0/1 for that.
+	 */
+	val = I915_READ(BXT_PORT_PCS_DW10_LN01(port));
+	val &= ~(TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT);
+	I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val);
+
+	val = I915_READ(BXT_PORT_TX_DW2_LN0(port));
+	val &= ~(MARGIN_000 | UNIQ_TRANS_SCALE);
+	val |= ddi_translations[level].margin << MARGIN_000_SHIFT |
+	       ddi_translations[level].scale << UNIQ_TRANS_SCALE_SHIFT;
+	I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val);
+
+	val = I915_READ(BXT_PORT_TX_DW3_LN0(port));
+	val &= ~UNIQE_TRANGE_EN_METHOD;
+	if (ddi_translations[level].enable)
+		val |= UNIQE_TRANGE_EN_METHOD;
+	I915_WRITE(BXT_PORT_TX_DW3_GRP(port), val);
+
+	val = I915_READ(BXT_PORT_TX_DW4_LN0(port));
+	val &= ~DE_EMPHASIS;
+	val |= ddi_translations[level].deemphasis << DEEMPH_SHIFT;
+	I915_WRITE(BXT_PORT_TX_DW4_GRP(port), val);
+
+	val = I915_READ(BXT_PORT_PCS_DW10_LN01(port));
+	val |= TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT;
+	I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val);
+}
+
 static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
@@ -1674,6 +1785,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
 	int type = intel_encoder->type;
+	int hdmi_level;
 
 	if (type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -1730,6 +1842,12 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 	} else if (type == INTEL_OUTPUT_HDMI) {
 		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
+		if (IS_BROXTON(dev)) {
+			hdmi_level = dev_priv->vbt.
+				ddi_port_info[port].hdmi_level_shift;
+			bxt_ddi_vswing_sequence(dev, hdmi_level, port,
+					INTEL_OUTPUT_HDMI);
+		}
 		intel_hdmi->set_infoframes(encoder,
 					   crtc->config->has_hdmi_sink,
 					   &crtc->config->base.adjusted_mode);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 4bfbeed..1cb6eb0 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3354,6 +3354,55 @@ intel_hsw_signal_levels(uint8_t train_set)
 	}
 }
 
+static void intel_bxt_signal_levels(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+	enum port port = dport->port;
+	struct drm_device *dev = dport->base.base.dev;
+	struct intel_encoder *encoder = &dport->base;
+	uint8_t train_set = intel_dp->train_set[0];
+	uint32_t level = 0;
+
+	int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+					 DP_TRAIN_PRE_EMPHASIS_MASK);
+	switch (signal_levels) {
+	default:
+		DRM_DEBUG_KMS("Unsupported voltage swing/pre-emph level\n");
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+		level = 0;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+		level = 1;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+		level = 2;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3:
+		level = 3;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+		level = 4;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+		level = 5;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+		level = 6;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+		level = 7;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+		level = 8;
+		break;
+	case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+		level = 9;
+		break;
+	}
+
+	bxt_ddi_vswing_sequence(dev, level, port, encoder->type);
+}
+
 /* Properly updates "DP" with the correct signal levels. */
 static void
 intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
@@ -3364,7 +3413,11 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
 	uint32_t signal_levels, mask;
 	uint8_t train_set = intel_dp->train_set[0];
 
-	if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
+	if (IS_BROXTON(dev)) {
+		signal_levels = 0;
+		intel_bxt_signal_levels(intel_dp);
+		mask = 0;
+	} else if (HAS_DDI(dev)) {
 		signal_levels = intel_hsw_signal_levels(train_set);
 		mask = DDI_BUF_EMP_MASK;
 	} else if (IS_CHERRYVIEW(dev)) {
@@ -3384,7 +3437,14 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
 		mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK;
 	}
 
-	DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels);
+	if (mask)
+		DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels);
+
+	DRM_DEBUG_KMS("Using vswing level %d\n",
+		train_set & DP_TRAIN_VOLTAGE_SWING_MASK);
+	DRM_DEBUG_KMS("Using pre-emphasis level %d\n",
+		(train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+			DP_TRAIN_PRE_EMPHASIS_SHIFT);
 
 	*DP = (*DP & ~mask) | signal_levels;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 097fb85..f07a14a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -874,6 +874,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 void bxt_select_cdclk_freq(struct drm_device *dev, u32 frequency);
+void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
+				enum port port, int type);
 
 /* intel_frontbuffer.c */
 void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx





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