diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dp.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 173 | 
1 files changed, 133 insertions, 40 deletions
| diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4d0358fad937..92b041b66e49 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -208,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw)   */  static int -intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock) +intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock, int check_bpp)  {  	struct drm_crtc *crtc = intel_dp->base.base.crtc;  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);  	int bpp = 24; -	if (intel_crtc) +	if (check_bpp) +		bpp = check_bpp; +	else if (intel_crtc)  		bpp = intel_crtc->bpp;  	return (pixel_clock * bpp + 9) / 10; @@ -233,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector,  	struct intel_dp *intel_dp = intel_attached_dp(connector);  	int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));  	int max_lanes = intel_dp_max_lane_count(intel_dp); +	int max_rate, mode_rate;  	if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {  		if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) @@ -242,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector,  			return MODE_PANEL;  	} -	if (intel_dp_link_required(intel_dp, mode->clock) -	    > intel_dp_max_data_rate(max_link_clock, max_lanes)) -		return MODE_CLOCK_HIGH; +	mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0); +	max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); + +	if (mode_rate > max_rate) { +			mode_rate = intel_dp_link_required(intel_dp, +							   mode->clock, 18); +			if (mode_rate > max_rate) +				return MODE_CLOCK_HIGH; +			else +				mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC; +	}  	if (mode->clock < 10000)  		return MODE_CLOCK_LOW; @@ -362,8 +373,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)) @@ -672,6 +683,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,  	int lane_count, clock;  	int max_lane_count = intel_dp_max_lane_count(intel_dp);  	int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; +	int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 0;  	static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };  	if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { @@ -689,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,  		for (clock = 0; clock <= max_clock; clock++) {  			int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); -			if (intel_dp_link_required(intel_dp, mode->clock) +			if (intel_dp_link_required(intel_dp, mode->clock, bpp)  					<= link_avail) {  				intel_dp->link_bw = bws[clock];  				intel_dp->lane_count = lane_count; @@ -817,10 +829,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 +886,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,34 +1406,59 @@ 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)  { -	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: -		return DP_TRAIN_PRE_EMPHASIS_6; -	case DP_TRAIN_VOLTAGE_SWING_800: -		return DP_TRAIN_PRE_EMPHASIS_3_5; -	case DP_TRAIN_VOLTAGE_SWING_1200: -	default: -		return DP_TRAIN_PRE_EMPHASIS_0; +	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; +		case DP_TRAIN_VOLTAGE_SWING_600: +			return DP_TRAIN_PRE_EMPHASIS_6; +		case DP_TRAIN_VOLTAGE_SWING_800: +			return DP_TRAIN_PRE_EMPHASIS_3_5; +		case DP_TRAIN_VOLTAGE_SWING_1200: +		default: +			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 +1470,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 +1548,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 +1684,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 +1699,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 +1712,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 +1793,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 +1804,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 +1845,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 +1875,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 +1887,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; | 
