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

Commit 1a2eb460 authored by Keith Packard's avatar Keith Packard
Browse files

drm/i915: Hook up Ivybridge eDP



The Ivybridge eDP control register looks like a cross between a
Cougarpoint PCH DP control register and a Sandybridge eDP control
register.

Where things trivially match, share the code. Where there are any
tricky bits, just split things out into two obviously separate code paths.

Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
Tested-by: default avatarFang Xun <xunx.fang@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41991
parent 8d715f00
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -3447,6 +3447,24 @@
#define  EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B	(0x38<<22)
#define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB	(0x3f<<22)

/* IVB */
#define EDP_LINK_TRAIN_400MV_0DB_IVB		(0x24 <<22)
#define EDP_LINK_TRAIN_400MV_3_5DB_IVB		(0x2a <<22)
#define EDP_LINK_TRAIN_400MV_6DB_IVB		(0x2f <<22)
#define EDP_LINK_TRAIN_600MV_0DB_IVB		(0x30 <<22)
#define EDP_LINK_TRAIN_600MV_3_5DB_IVB		(0x36 <<22)
#define EDP_LINK_TRAIN_800MV_0DB_IVB		(0x38 <<22)
#define EDP_LINK_TRAIN_800MV_3_5DB_IVB		(0x33 <<22)

/* legacy values */
#define EDP_LINK_TRAIN_500MV_0DB_IVB		(0x00 <<22)
#define EDP_LINK_TRAIN_1000MV_0DB_IVB		(0x20 <<22)
#define EDP_LINK_TRAIN_500MV_3_5DB_IVB		(0x02 <<22)
#define EDP_LINK_TRAIN_1000MV_3_5DB_IVB		(0x22 <<22)
#define EDP_LINK_TRAIN_1000MV_6DB_IVB		(0x23 <<22)

#define  EDP_LINK_TRAIN_VOL_EMP_MASK_IVB	(0x3f<<22)

#define  FORCEWAKE				0xA18C
#define  FORCEWAKE_ACK				0x130090
#define  FORCEWAKE_MT				0xa188 /* multi-threaded */
+115 −34
Original line number Diff line number Diff line
@@ -362,8 +362,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
	 * clock divider.
	 */
	if (is_cpu_edp(intel_dp)) {
		if (IS_GEN6(dev))
			aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
		if (IS_GEN6(dev) || IS_GEN7(dev))
			aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
		else
			aux_clock_divider = 225; /* eDP input clock at 450Mhz */
	} else if (HAS_PCH_SPLIT(dev))
@@ -817,10 +817,11 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
	}

	/*
	 * There are three kinds of DP registers:
	 * There are four kinds of DP registers:
	 *
	 * 	IBX PCH
	 * 	CPU
	 * 	SNB CPU
	 *	IVB CPU
	 * 	CPT PCH
	 *
	 * IBX PCH and CPU are the same for almost everything,
@@ -873,7 +874,25 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,

	/* Split out the IBX/CPU vs CPT settings */

	if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
	if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
			intel_dp->DP |= DP_SYNC_HS_HIGH;
		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
			intel_dp->DP |= DP_SYNC_VS_HIGH;
		intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;

		if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN)
			intel_dp->DP |= DP_ENHANCED_FRAMING;

		intel_dp->DP |= intel_crtc->pipe << 29;

		/* don't miss out required setting for eDP */
		intel_dp->DP |= DP_PLL_ENABLE;
		if (adjusted_mode->clock < 200000)
			intel_dp->DP |= DP_PLL_FREQ_160MHZ;
		else
			intel_dp->DP |= DP_PLL_FREQ_270MHZ;
	} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
		intel_dp->DP |= intel_dp->color_range;

		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1375,12 +1394,36 @@ static char *link_train_names[] = {
 * These are source-specific values; current Intel hardware supports
 * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
 */
#define I830_DP_VOLTAGE_MAX	    DP_TRAIN_VOLTAGE_SWING_800
#define I830_DP_VOLTAGE_MAX_CPT	    DP_TRAIN_VOLTAGE_SWING_1200

static uint8_t
intel_dp_pre_emphasis_max(uint8_t voltage_swing)
intel_dp_voltage_max(struct intel_dp *intel_dp)
{
	struct drm_device *dev = intel_dp->base.base.dev;

	if (IS_GEN7(dev) && is_cpu_edp(intel_dp))
		return DP_TRAIN_VOLTAGE_SWING_800;
	else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
		return DP_TRAIN_VOLTAGE_SWING_1200;
	else
		return DP_TRAIN_VOLTAGE_SWING_800;
}

static uint8_t
intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
{
	struct drm_device *dev = intel_dp->base.base.dev;

	if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
		case DP_TRAIN_VOLTAGE_SWING_400:
			return DP_TRAIN_PRE_EMPHASIS_6;
		case DP_TRAIN_VOLTAGE_SWING_600:
		case DP_TRAIN_VOLTAGE_SWING_800:
			return DP_TRAIN_PRE_EMPHASIS_3_5;
		default:
			return DP_TRAIN_PRE_EMPHASIS_0;
		}
	} else {
		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
		case DP_TRAIN_VOLTAGE_SWING_400:
			return DP_TRAIN_PRE_EMPHASIS_6;
@@ -1393,16 +1436,17 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing)
			return DP_TRAIN_PRE_EMPHASIS_0;
		}
	}
}

static void
intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
{
	struct drm_device *dev = intel_dp->base.base.dev;
	uint8_t v = 0;
	uint8_t p = 0;
	int lane;
	uint8_t	*adjust_request = link_status + (DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS);
	int voltage_max;
	uint8_t voltage_max;
	uint8_t preemph_max;

	for (lane = 0; lane < intel_dp->lane_count; lane++) {
		uint8_t this_v = intel_get_adjust_request_voltage(adjust_request, lane);
@@ -1414,15 +1458,13 @@ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ST
			p = this_p;
	}

	if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
		voltage_max = I830_DP_VOLTAGE_MAX_CPT;
	else
		voltage_max = I830_DP_VOLTAGE_MAX;
	voltage_max = intel_dp_voltage_max(intel_dp);
	if (v >= voltage_max)
		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;

	if (p >= intel_dp_pre_emphasis_max(v))
		p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
	preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
	if (p >= preemph_max)
		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;

	for (lane = 0; lane < 4; lane++)
		intel_dp->train_set[lane] = v | p;
@@ -1494,6 +1536,37 @@ intel_gen6_edp_signal_levels(uint8_t train_set)
	}
}

/* Gen7's DP voltage swing and pre-emphasis control */
static uint32_t
intel_gen7_edp_signal_levels(uint8_t train_set)
{
	int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
					 DP_TRAIN_PRE_EMPHASIS_MASK);
	switch (signal_levels) {
	case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
		return EDP_LINK_TRAIN_400MV_0DB_IVB;
	case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
		return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
	case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
		return EDP_LINK_TRAIN_400MV_6DB_IVB;

	case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
		return EDP_LINK_TRAIN_600MV_0DB_IVB;
	case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
		return EDP_LINK_TRAIN_600MV_3_5DB_IVB;

	case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
		return EDP_LINK_TRAIN_800MV_0DB_IVB;
	case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
		return EDP_LINK_TRAIN_800MV_3_5DB_IVB;

	default:
		DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
			      "0x%x\n", signal_levels);
		return EDP_LINK_TRAIN_500MV_0DB_IVB;
	}
}

static uint8_t
intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
		      int lane)
@@ -1599,7 +1672,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
				  DP_LINK_CONFIGURATION_SIZE);

	DP |= DP_PORT_EN;
	if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))

	if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
		DP &= ~DP_LINK_TRAIN_MASK_CPT;
	else
		DP &= ~DP_LINK_TRAIN_MASK;
@@ -1613,7 +1687,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
		uint8_t	    link_status[DP_LINK_STATUS_SIZE];
		uint32_t    signal_levels;

		if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {

		if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
			signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]);
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels;
		} else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
		} else {
@@ -1622,7 +1700,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
			DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
		}

		if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
		if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
			reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
		else
			reg = DP | DP_LINK_TRAIN_PAT_1;
@@ -1703,7 +1781,10 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
			break;
		}

		if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
		if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
			signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]);
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels;
		} else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
		} else {
@@ -1711,7 +1792,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
			DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
		}

		if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
		if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
			reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
		else
			reg = DP | DP_LINK_TRAIN_PAT_2;
@@ -1752,7 +1833,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
		++tries;
	}

	if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
	if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
		reg = DP | DP_LINK_TRAIN_OFF_CPT;
	else
		reg = DP | DP_LINK_TRAIN_OFF;
@@ -1782,7 +1863,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
		udelay(100);
	}

	if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) {
	if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
		DP &= ~DP_LINK_TRAIN_MASK_CPT;
		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
	} else {
@@ -1794,7 +1875,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
	msleep(17);

	if (is_edp(intel_dp)) {
		if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
		if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
			DP |= DP_LINK_TRAIN_OFF_CPT;
		else
			DP |= DP_LINK_TRAIN_OFF;