The biggest difference from HSW/BDW PSR here is that VLV enable_source function enables PSR but let it in Inactive state. So it might be called on early stage along with setup and enable_sink ones. Signed-off-by: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx> --- drivers/gpu/drm/i915/intel_dp.c | 161 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 145 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ac70b3a..335a711 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2134,7 +2134,44 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp, POSTING_READ(ctl_reg); } -static void intel_edp_psr_setup_vsc(struct intel_dp *intel_dp) +/** + * vlv_edp_psr_setup_vsc - Setup PSR related VSC aux registers on VLV+. + * @intel_dp: DP struct + * + * On VLV we don't need to generate VSC. It auto generates according + * EDP 1.3 spec, Table 3.10. + * HB0 - Secondary Data Packet ID = 0 + * HB1 - Secondary Data Packet Type = 07h + * HB2 - Bits 4:0 = Revision Number = 02h + * Bits 7:5 = Reserved (all 0s) + * HB3 - Bits 4:0 Number of Valid Data Bytes = 08h + * Bits 7:5 Reserved + * DB0 - Bits 7:4 Stereo Interface Method Specific Paramenter + * Bits 3:0 Stereo Interface Method Code + * DB1 - Bit 0 - PSR State (0 when Inactive / 1 when Active) + * Bit 1 - Update RFB. (0 do not update RFB / 1 update RFB) + * Bit 2 - CRC Valid. VLV always send 0 which + * means CRC value in DB7:2 invalid + * Bits 7:3 - Reserved + * DB2-7 - CRC - don't care because DB1[2] always tells this is invalid. + */ +static void vlv_edp_psr_setup_vsc(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 drm_crtc *crtc = intel_dig_port->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + uint32_t val; + + /* VLV auto-generate VSC package as per EDP 1.3 spec, Table 3.10 */ + val = I915_READ(VLV_VSCSDP(pipe)); + val &= ~VLV_EDP_PSR_SDP_FREQ_MASK; + val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME; + I915_WRITE(VLV_VSCSDP(pipe), val); +} + +static void hsw_edp_psr_setup_vsc(struct intel_dp *intel_dp) { struct edp_vsc_psr psr_vsc; @@ -2147,7 +2184,20 @@ static void intel_edp_psr_setup_vsc(struct intel_dp *intel_dp) intel_edp_psr_write_vsc(intel_dp, &psr_vsc); } -static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp) +/** + * vlv_edp_psr_enable_sink - Enable PSR on Panel for VLV. + * @intel_dp: DP struct + * + * This function enable PSR on Panel (Sink) side over DPCD write. + */ +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp) +{ + /* Enable PSR in sink */ + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, + DP_PSR_ENABLE); +} + +static void hsw_edp_psr_enable_sink(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; @@ -2191,7 +2241,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp) (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); } -static void intel_edp_psr_enable_source(struct intel_dp *intel_dp) +/** + * vlv_edp_psr_enable_source - Enable PSR on VLV without activate it. + * @intel_dp: DP struct + * + * This function do the transition from PSR_state 0 to PSR_state 1 that is + * PSR Inactive one.. + */ +static void vlv_edp_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; + struct drm_crtc *crtc = dig_port->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + + I915_WRITE(VLV_PSRCTL(pipe), + VLV_EDP_PSR_SRC_TRANSMITTER_STATE | + VLV_EDP_PSR_MODE_SW_TIMER | + VLV_EDP_PSR_ENABLE); +} + +static void hsw_edp_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; @@ -2276,7 +2347,7 @@ static void intel_edp_psr_do_enable(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->psr.lock); /* Enable/Re-enable PSR on the host */ - intel_edp_psr_enable_source(intel_dp); + hsw_edp_psr_enable_source(intel_dp); dev_priv->psr.active = true; } @@ -2307,30 +2378,71 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp) dev_priv->psr.busy_frontbuffer_bits = 0; - intel_edp_psr_setup_vsc(intel_dp); + if (HAS_DDI(dev)) { + hsw_edp_psr_setup_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); - /* 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); + /* Enable PSR on the panel */ + hsw_edp_psr_enable_sink(intel_dp); + } else { + vlv_edp_psr_setup_vsc(intel_dp); - /* Enable PSR on the panel */ - intel_edp_psr_enable_sink(intel_dp); + /* Enable PSR on the panel */ + vlv_edp_psr_enable_sink(intel_dp); + + /* On HSW/BDW enable_source also means go to PSR entry/active + * state as soon as idle_frame achieved and here would be + * to soon. However on VLV enable_source just enable PSR + * but let it on inactive state. So we might do this prior + * to active transition, i.e. here. + */ + vlv_edp_psr_enable_source(intel_dp); + } dev_priv->psr.enabled = intel_dp; unlock: mutex_unlock(&dev_priv->psr.lock); } -void intel_edp_psr_disable(struct intel_dp *intel_dp) +/** + * vlv_edp_psr_disable - Disable PSR on VLV + * @intel_dp: DP struct + * + * This function puts PSR VLV back to PSR_state 0 that is PSR Disabled. + */ +static void vlv_edp_psr_disable(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp_to_dev(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 *intel_crtc = + to_intel_crtc(intel_dig_port->base.base.crtc); + uint32_t val; - mutex_lock(&dev_priv->psr.lock); - if (!dev_priv->psr.enabled) { - mutex_unlock(&dev_priv->psr.lock); - return; + if (dev_priv->psr.active) { + if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) & + VLV_EDP_PSR_IN_TRANS) == 0, 250)) + WARN(1, "PSR transition took longer than expected\n"); + + val = I915_READ(VLV_PSRCTL(intel_crtc->pipe)); + val &= ~VLV_EDP_PSR_ACTIVE_ENTRY; + val &= ~VLV_EDP_PSR_ENABLE; + val &= ~VLV_EDP_PSR_MODE_MASK; + I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val); + + dev_priv->psr.active = false; + } else { + WARN_ON(vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe)); } +} + +static void hsw_edp_psr_disable(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->psr.active) { I915_WRITE(EDP_PSR_CTL(dev), @@ -2345,6 +2457,23 @@ void intel_edp_psr_disable(struct intel_dp *intel_dp) } else { WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE); } +} + +void intel_edp_psr_disable(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->psr.lock); + if (!dev_priv->psr.enabled) { + mutex_unlock(&dev_priv->psr.lock); + return; + } + + if (HAS_DDI(dev)) + hsw_edp_psr_disable(intel_dp); + else + vlv_edp_psr_disable(intel_dp); dev_priv->psr.enabled = NULL; mutex_unlock(&dev_priv->psr.lock); -- 1.9.3 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx