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 Original line Diff line number Diff line
@@ -3447,6 +3447,24 @@
#define  EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B	(0x38<<22)
#define  EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B	(0x38<<22)
#define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB	(0x3f<<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				0xA18C
#define  FORCEWAKE_ACK				0x130090
#define  FORCEWAKE_ACK				0x130090
#define  FORCEWAKE_MT				0xa188 /* multi-threaded */
#define  FORCEWAKE_MT				0xa188 /* multi-threaded */
+115 −34
Original line number Original line Diff line number Diff line
@@ -362,8 +362,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
	 * clock divider.
	 * clock divider.
	 */
	 */
	if (is_cpu_edp(intel_dp)) {
	if (is_cpu_edp(intel_dp)) {
		if (IS_GEN6(dev))
		if (IS_GEN6(dev) || IS_GEN7(dev))
			aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
			aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
		else
		else
			aux_clock_divider = 225; /* eDP input clock at 450Mhz */
			aux_clock_divider = 225; /* eDP input clock at 450Mhz */
	} else if (HAS_PCH_SPLIT(dev))
	} 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
	 * 	IBX PCH
	 * 	CPU
	 * 	SNB CPU
	 *	IVB CPU
	 * 	CPT PCH
	 * 	CPT PCH
	 *
	 *
	 * IBX PCH and CPU are the same for almost everything,
	 * 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 */
	/* 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;
		intel_dp->DP |= intel_dp->color_range;


		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
		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
 * These are source-specific values; current Intel hardware supports
 * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
 * 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
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) {
		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
		case DP_TRAIN_VOLTAGE_SWING_400:
		case DP_TRAIN_VOLTAGE_SWING_400:
			return DP_TRAIN_PRE_EMPHASIS_6;
			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;
			return DP_TRAIN_PRE_EMPHASIS_0;
		}
		}
	}
	}
}


static void
static void
intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
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 v = 0;
	uint8_t p = 0;
	uint8_t p = 0;
	int lane;
	int lane;
	uint8_t	*adjust_request = link_status + (DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS);
	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++) {
	for (lane = 0; lane < intel_dp->lane_count; lane++) {
		uint8_t this_v = intel_get_adjust_request_voltage(adjust_request, 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;
			p = this_p;
	}
	}


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


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


	for (lane = 0; lane < 4; lane++)
	for (lane = 0; lane < 4; lane++)
		intel_dp->train_set[lane] = v | p;
		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
static uint8_t
intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
		      int lane)
		      int lane)
@@ -1599,7 +1672,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
				  DP_LINK_CONFIGURATION_SIZE);
				  DP_LINK_CONFIGURATION_SIZE);


	DP |= DP_PORT_EN;
	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;
		DP &= ~DP_LINK_TRAIN_MASK_CPT;
	else
	else
		DP &= ~DP_LINK_TRAIN_MASK;
		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];
		uint8_t	    link_status[DP_LINK_STATUS_SIZE];
		uint32_t    signal_levels;
		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]);
			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
		} else {
		} 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;
			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;
			reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
		else
		else
			reg = DP | DP_LINK_TRAIN_PAT_1;
			reg = DP | DP_LINK_TRAIN_PAT_1;
@@ -1703,7 +1781,10 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
			break;
			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]);
			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
		} else {
		} 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;
			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;
			reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
		else
		else
			reg = DP | DP_LINK_TRAIN_PAT_2;
			reg = DP | DP_LINK_TRAIN_PAT_2;
@@ -1752,7 +1833,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
		++tries;
		++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;
		reg = DP | DP_LINK_TRAIN_OFF_CPT;
	else
	else
		reg = DP | DP_LINK_TRAIN_OFF;
		reg = DP | DP_LINK_TRAIN_OFF;
@@ -1782,7 +1863,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
		udelay(100);
		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;
		DP &= ~DP_LINK_TRAIN_MASK_CPT;
		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
	} else {
	} else {
@@ -1794,7 +1875,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
	msleep(17);
	msleep(17);


	if (is_edp(intel_dp)) {
	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;
			DP |= DP_LINK_TRAIN_OFF_CPT;
		else
		else
			DP |= DP_LINK_TRAIN_OFF;
			DP |= DP_LINK_TRAIN_OFF;