>-----Original Message----- >From: Intel-gfx [mailto:intel-gfx-bounces@xxxxxxxxxxxxxxxxxxxxx] On Behalf Of >Rodrigo Vivi >Sent: Wednesday, October 29, 2014 12:16 AM >To: intel-gfx@xxxxxxxxxxxxxxxxxxxxx >Cc: Vivi, Rodrigo >Subject: [PATCH 04/10] drm/i915: PSR VLV/CHV: Introduce setup, >enable and disable functions > >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 | I see we are keeping the source active during PSR. Making this '0' may provide better power savings, but we need to manage a lot of hassle during PSR exit.. (like Link training, DPIO/PLL bring up etc..) >+ 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. I hope you meant 'puts VLV PSR'.. >+ */ >+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"); The spec claims this waiting time as 250 micro seconds. Looks like we are waiting for 250 ms.. No ? Just curious, did you see this transition during testing ? Thanks, Durga >+ >+ 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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx