diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_psr.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_psr.c | 308 |
1 files changed, 247 insertions, 61 deletions
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 716b8a961eea..b9f40c2e0af7 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -61,14 +61,15 @@ static bool is_edp_psr(struct intel_dp *intel_dp) return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED; } -bool intel_psr_is_enabled(struct drm_device *dev) +static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val; - if (!HAS_PSR(dev)) - return false; - - return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; + val = I915_READ(VLV_PSRSTAT(pipe)) & + VLV_EDP_PSR_CURR_STATE_MASK; + return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) || + (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE); } static void intel_psr_write_vsc(struct intel_dp *intel_dp, @@ -78,8 +79,8 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp, struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder); - u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder); + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder); + u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config->cpu_transcoder); uint32_t *data = (uint32_t *) vsc_psr; unsigned int i; @@ -100,7 +101,23 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp, POSTING_READ(ctl_reg); } -static void intel_psr_setup_vsc(struct intel_dp *intel_dp) +static void vlv_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_psr_setup_vsc(struct intel_dp *intel_dp) { struct edp_vsc_psr psr_vsc; @@ -113,14 +130,20 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp) intel_psr_write_vsc(intel_dp, &psr_vsc); } -static void intel_psr_enable_sink(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); +} + +static void hsw_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; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t aux_clock_divider; + uint32_t aux_data_reg, aux_ctl_reg; int precharge = 0x3; - bool only_standby = false; static const uint8_t aux_msg[] = { [0] = DP_AUX_NATIVE_WRITE << 4, [1] = DP_SET_POWER >> 8, @@ -134,49 +157,96 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); - if (IS_BROADWELL(dev) && dig_port->port != PORT_A) - only_standby = true; - /* Enable PSR in sink */ - if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) + 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); + 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); + DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE); + + aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ? + DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev); + aux_ctl_reg = (INTEL_INFO(dev)->gen >= 9) ? + DPA_AUX_CH_CTL : EDP_PSR_AUX_CTL(dev); /* Setup AUX registers */ for (i = 0; i < sizeof(aux_msg); i += 4) - I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i, + I915_WRITE(aux_data_reg + i, intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i)); - I915_WRITE(EDP_PSR_AUX_CTL(dev), + if (INTEL_INFO(dev)->gen >= 9) { + uint32_t val; + + val = I915_READ(aux_ctl_reg); + val &= ~DP_AUX_CH_CTL_TIME_OUT_MASK; + 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 */ + val &= ~DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL; + I915_WRITE(aux_ctl_reg, val); + } else { + I915_WRITE(aux_ctl_reg, DP_AUX_CH_CTL_TIME_OUT_400us | (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); + } } -static void intel_psr_enable_source(struct intel_dp *intel_dp) +static void vlv_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; + + /* Transition from PSR_state 0 to PSR_state 1, i.e. PSR Inactive */ + I915_WRITE(VLV_PSRCTL(pipe), + VLV_EDP_PSR_MODE_SW_TIMER | + VLV_EDP_PSR_SRC_TRANSMITTER_STATE | + VLV_EDP_PSR_ENABLE); +} + +static void vlv_psr_activate(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; + + /* Let's do the transition from PSR_state 1 to PSR_state 2 + * that is PSR transition to active - static frame transmission. + * Then Hardware is responsible for the transition to PSR_state 3 + * that is PSR active - no Remote Frame Buffer (RFB) update. + */ + I915_WRITE(VLV_PSRCTL(pipe), I915_READ(VLV_PSRCTL(pipe)) | + VLV_EDP_PSR_ACTIVE_ENTRY); +} + +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; - uint32_t idle_frames = 1; + /* 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 + * from VBT + 1 and at minimum 2 to be on the safe side. + */ + uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ? + dev_priv->vbt.psr.idle_frames + 1 : 2; uint32_t val = 0x0; const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; - bool only_standby = false; - - if (IS_BROADWELL(dev) && dig_port->port != PORT_A) - only_standby = true; - if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) { + if (dev_priv->psr.link_standby) { val |= EDP_PSR_LINK_STANDBY; val |= EDP_PSR_TP2_TP3_TIME_0us; val |= EDP_PSR_TP1_TIME_0us; val |= EDP_PSR_SKIP_AUX_EXIT; - val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0; } else val |= EDP_PSR_LINK_DISABLE; @@ -211,27 +281,24 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) return false; } - /* Below limitations aren't valid for Broadwell */ - if (IS_BROADWELL(dev)) - goto out; - - if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) & - S3D_ENABLE) { + if (IS_HASWELL(dev) && + I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config->cpu_transcoder)) & + S3D_ENABLE) { DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n"); return false; } - if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) { + if (IS_HASWELL(dev) && + intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) { DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n"); return false; } - out: dev_priv->psr.source_ok = true; return true; } -static void intel_psr_do_enable(struct intel_dp *intel_dp) +static void intel_psr_activate(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; @@ -242,7 +309,14 @@ static void intel_psr_do_enable(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->psr.lock); /* Enable/Re-enable PSR on the host */ - intel_psr_enable_source(intel_dp); + if (HAS_DDI(dev)) + /* On HSW+ after we enable PSR on source it will activate it + * as soon as it match configure idle_frame count. So + * we just actually enable it here on activation time. + */ + hsw_psr_enable_source(intel_dp); + else + vlv_psr_activate(intel_dp); dev_priv->psr.active = true; } @@ -278,39 +352,79 @@ 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; - intel_psr_setup_vsc(intel_dp); + if (HAS_DDI(dev)) { + hsw_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_psr_enable_sink(intel_dp); - /* Enable PSR on the panel */ - intel_psr_enable_sink(intel_dp); + if (INTEL_INFO(dev)->gen >= 9) + intel_psr_activate(intel_dp); + } else { + vlv_psr_setup_vsc(intel_dp); + + /* Enable PSR on the panel */ + vlv_psr_enable_sink(intel_dp); + + /* On HSW+ 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_psr_enable_source(intel_dp); + } dev_priv->psr.enabled = intel_dp; unlock: mutex_unlock(&dev_priv->psr.lock); } -/** - * intel_psr_disable - Disable PSR - * @intel_dp: Intel DP - * - * This function needs to be called before disabling pipe. - */ -void intel_psr_disable(struct intel_dp *intel_dp) +static void vlv_psr_disable(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 *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) { + /* Put VLV PSR back to PSR_state 0 that is PSR Disabled. */ + if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) & + VLV_EDP_PSR_IN_TRANS) == 0, 1)) + 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_is_psr_active_on_pipe(dev, intel_crtc->pipe)); } +} + +static void hsw_psr_disable(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; if (dev_priv->psr.active) { I915_WRITE(EDP_PSR_CTL(dev), @@ -325,6 +439,30 @@ void intel_psr_disable(struct intel_dp *intel_dp) } else { WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE); } +} + +/** + * intel_psr_disable - Disable PSR + * @intel_dp: Intel DP + * + * This function needs to be called before disabling pipe. + */ +void intel_psr_disable(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; + + mutex_lock(&dev_priv->psr.lock); + if (!dev_priv->psr.enabled) { + mutex_unlock(&dev_priv->psr.lock); + return; + } + + if (HAS_DDI(dev)) + hsw_psr_disable(intel_dp); + else + vlv_psr_disable(intel_dp); dev_priv->psr.enabled = NULL; mutex_unlock(&dev_priv->psr.lock); @@ -337,18 +475,27 @@ static void intel_psr_work(struct work_struct *work) struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), psr.work.work); struct intel_dp *intel_dp = dev_priv->psr.enabled; + struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; /* We have to make sure PSR is ready for re-enable * otherwise it keeps disabled until next full enable/disable cycle. * PSR might take some time to get fully disabled * and be ready for re-enable. */ - if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) & - EDP_PSR_STATUS_STATE_MASK) == 0, 50)) { - DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); - return; + if (HAS_DDI(dev_priv->dev)) { + if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) & + EDP_PSR_STATUS_STATE_MASK) == 0, 50)) { + DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); + return; + } + } else { + if (wait_for((I915_READ(VLV_PSRSTAT(pipe)) & + VLV_EDP_PSR_IN_TRANS) == 0, 1)) { + DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); + return; + } } - mutex_lock(&dev_priv->psr.lock); intel_dp = dev_priv->psr.enabled; @@ -363,7 +510,7 @@ static void intel_psr_work(struct work_struct *work) if (dev_priv->psr.busy_frontbuffer_bits) goto unlock; - intel_psr_do_enable(intel_dp); + intel_psr_activate(intel_dp); unlock: mutex_unlock(&dev_priv->psr.lock); } @@ -371,17 +518,47 @@ unlock: static void intel_psr_exit(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp *intel_dp = dev_priv->psr.enabled; + struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + u32 val; - if (dev_priv->psr.active) { - u32 val = I915_READ(EDP_PSR_CTL(dev)); + if (!dev_priv->psr.active) + return; + + if (HAS_DDI(dev)) { + val = I915_READ(EDP_PSR_CTL(dev)); WARN_ON(!(val & EDP_PSR_ENABLE)); I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE); dev_priv->psr.active = false; + } else { + val = I915_READ(VLV_PSRCTL(pipe)); + + /* Here we do the transition from PSR_state 3 to PSR_state 5 + * directly once PSR State 4 that is active with single frame + * update can be skipped. PSR_state 5 that is PSR exit then + * Hardware is responsible to transition back to PSR_state 1 + * that is PSR inactive. Same state after + * vlv_edp_psr_enable_source. + */ + val &= ~VLV_EDP_PSR_ACTIVE_ENTRY; + I915_WRITE(VLV_PSRCTL(pipe), val); + + /* Send AUX wake up - Spec says after transitioning to PSR + * active we have to send AUX wake up by writing 01h in DPCD + * 600h of sink device. + * XXX: This might slow down the transition, but without this + * HW doesn't complete the transition to PSR_state 1 and we + * never get the screen updated. + */ + drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, + DP_SET_POWER_D0); } + dev_priv->psr.active = false; } /** @@ -459,6 +636,15 @@ void intel_psr_flush(struct drm_device *dev, (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe))) intel_psr_exit(dev); + /* + * On Valleyview and Cherryview we don't use hardware tracking so + * any plane updates or cursor moves don't result in a PSR + * invalidating. Which means we need to manually fake this in + * software for all flushes, not just when we've seen a preceding + * invalidation through frontbuffer rendering. */ + if (!HAS_DDI(dev)) + intel_psr_exit(dev); + if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->psr.work, msecs_to_jiffies(100)); |