diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_psr.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_psr.c | 118 | 
1 files changed, 97 insertions, 21 deletions
| diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index a8f9348259ae..5ee0fa57ed19 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -117,6 +117,19 @@ static void vlv_psr_setup_vsc(struct intel_dp *intel_dp)  	I915_WRITE(VLV_VSCSDP(pipe), val);  } +static void skl_psr_setup_su_vsc(struct intel_dp *intel_dp) +{ +	struct edp_vsc_psr psr_vsc; + +	/* Prepare VSC Header for SU as per EDP 1.4 spec, Table 6.11 */ +	memset(&psr_vsc, 0, sizeof(psr_vsc)); +	psr_vsc.sdp_header.HB0 = 0; +	psr_vsc.sdp_header.HB1 = 0x7; +	psr_vsc.sdp_header.HB2 = 0x3; +	psr_vsc.sdp_header.HB3 = 0xb; +	intel_psr_write_vsc(intel_dp, &psr_vsc); +} +  static void hsw_psr_setup_vsc(struct intel_dp *intel_dp)  {  	struct edp_vsc_psr psr_vsc; @@ -133,7 +146,7 @@ static void hsw_psr_setup_vsc(struct intel_dp *intel_dp)  static void vlv_psr_enable_sink(struct intel_dp *intel_dp)  {  	drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, -			   DP_PSR_ENABLE); +			   DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);  }  static void hsw_psr_enable_sink(struct intel_dp *intel_dp) @@ -157,13 +170,14 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp)  	aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); -	/* Enable PSR in sink */ -	if (dev_priv->psr.link_standby) -		drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, -				   DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); -	else -		drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, -				   DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE); +	drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, +			   DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE); + +	/* Enable AUX frame sync at sink */ +	if (dev_priv->psr.aux_frame_sync) +		drm_dp_dpcd_writeb(&intel_dp->aux, +				DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF, +				DP_AUX_FRAME_SYNC_ENABLE);  	aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ?  				DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev); @@ -183,8 +197,10 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp)  		val |= DP_AUX_CH_CTL_TIME_OUT_1600us;  		val &= ~DP_AUX_CH_CTL_MESSAGE_SIZE_MASK;  		val |= (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); -		/* Use hardcoded data values for PSR */ +		/* Use hardcoded data values for PSR, frame sync and GTC */  		val &= ~DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL; +		val &= ~DP_AUX_CH_CTL_FS_DATA_AUX_REG_SKL; +		val &= ~DP_AUX_CH_CTL_GTC_DATA_AUX_REG_SKL;  		I915_WRITE(aux_ctl_reg, val);  	} else {  		I915_WRITE(aux_ctl_reg, @@ -193,6 +209,8 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp)  		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |  		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));  	} + +	drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, DP_PSR_ENABLE);  }  static void vlv_psr_enable_source(struct intel_dp *intel_dp) @@ -232,6 +250,7 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)  	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);  	struct drm_device *dev = dig_port->base.base.dev;  	struct drm_i915_private *dev_priv = dev->dev_private; +  	uint32_t max_sleep_time = 0x1f;  	/* Lately it was identified that depending on panel idle frame count  	 * calculated at HW can be off by 1. So let's use what came @@ -242,19 +261,25 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)  	uint32_t val = 0x0;  	const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; -	if (dev_priv->psr.link_standby) { -		val |= EDP_PSR_LINK_STANDBY; +	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) { +		/* It doesn't mean we shouldn't send TPS patters, so let's +		   send the minimal TP1 possible and skip TP2. */ +		val |= EDP_PSR_TP1_TIME_100us;  		val |= EDP_PSR_TP2_TP3_TIME_0us; -		val |= EDP_PSR_TP1_TIME_0us;  		val |= EDP_PSR_SKIP_AUX_EXIT; -	} else -		val |= EDP_PSR_LINK_DISABLE; +		/* Sink should be able to train with the 5 or 6 idle patterns */ +		idle_frames += 4; +	}  	I915_WRITE(EDP_PSR_CTL(dev), val |  		   (IS_BROADWELL(dev) ? 0 : link_entry_time) |  		   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |  		   idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |  		   EDP_PSR_ENABLE); + +	if (dev_priv->psr.psr2_support) +		I915_WRITE(EDP_PSR2_CTL, EDP_PSR2_ENABLE | +				EDP_SU_TRACK_ENABLE | EDP_PSR2_TP2_TIME_100);  }  static bool intel_psr_match_conditions(struct intel_dp *intel_dp) @@ -294,6 +319,12 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)  		return false;  	} +	if (!IS_VALLEYVIEW(dev) && ((dev_priv->vbt.psr.full_link) || +				    (dig_port->port != PORT_A))) { +		DRM_DEBUG_KMS("PSR condition failed: Link Standby requested/needed but not supported on this platform\n"); +		return false; +	} +  	dev_priv->psr.source_ok = true;  	return true;  } @@ -332,6 +363,7 @@ void intel_psr_enable(struct intel_dp *intel_dp)  	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);  	struct drm_device *dev = intel_dig_port->base.base.dev;  	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);  	if (!HAS_PSR(dev)) {  		DRM_DEBUG_KMS("PSR not supported on this platform\n"); @@ -352,18 +384,20 @@ void intel_psr_enable(struct intel_dp *intel_dp)  	if (!intel_psr_match_conditions(intel_dp))  		goto unlock; -	/* First we check VBT, but we must respect sink and source -	 * known restrictions */ -	dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; -	if ((intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) || -	    (IS_BROADWELL(dev) && intel_dig_port->port != PORT_A)) -		dev_priv->psr.link_standby = true; -  	dev_priv->psr.busy_frontbuffer_bits = 0;  	if (HAS_DDI(dev)) {  		hsw_psr_setup_vsc(intel_dp); +		if (dev_priv->psr.psr2_support) { +			/* PSR2 is restricted to work with panel resolutions upto 3200x2000 */ +			if (crtc->config->pipe_src_w > 3200 || +				crtc->config->pipe_src_h > 2000) +				dev_priv->psr.psr2_support = false; +			else +				skl_psr_setup_su_vsc(intel_dp); +		} +  		/* Avoid continuous PSR exit by masking memup and hpd */  		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |  			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); @@ -560,6 +594,48 @@ static void intel_psr_exit(struct drm_device *dev)  }  /** + * intel_psr_single_frame_update - Single Frame Update + * @dev: DRM device + * + * Some platforms support a single frame update feature that is used to + * send and update only one frame on Remote Frame Buffer. + * So far it is only implemented for Valleyview and Cherryview because + * hardware requires this to be done before a page flip. + */ +void intel_psr_single_frame_update(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_crtc *crtc; +	enum pipe pipe; +	u32 val; + +	/* +	 * Single frame update is already supported on BDW+ but it requires +	 * many W/A and it isn't really needed. +	 */ +	if (!IS_VALLEYVIEW(dev)) +		return; + +	mutex_lock(&dev_priv->psr.lock); +	if (!dev_priv->psr.enabled) { +		mutex_unlock(&dev_priv->psr.lock); +		return; +	} + +	crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; +	pipe = to_intel_crtc(crtc)->pipe; +	val = I915_READ(VLV_PSRCTL(pipe)); + +	/* +	 * We need to set this bit before writing registers for a flip. +	 * This bit will be self-clear when it gets to the PSR active state. +	 */ +	I915_WRITE(VLV_PSRCTL(pipe), val | VLV_EDP_PSR_SINGLE_FRAME_UPDATE); + +	mutex_unlock(&dev_priv->psr.lock); +} + +/**   * intel_psr_invalidate - Invalidade PSR   * @dev: DRM device   * @frontbuffer_bits: frontbuffer plane tracking bits | 
