[Intel-gfx] [PATCH 02/15] drm/i915: Introduce intel_psr.c
R, Durgadoss
durgadoss.r at intel.com
Tue Nov 18 19:16:23 CET 2014
>-----Original Message-----
>From: Intel-gfx [mailto:intel-gfx-bounces at lists.freedesktop.org] On Behalf Of Rodrigo Vivi
>Sent: Friday, November 14, 2014 10:22 PM
>To: intel-gfx at lists.freedesktop.org
>Cc: Vivi, Rodrigo
>Subject: [Intel-gfx] [PATCH 02/15] drm/i915: Introduce intel_psr.c
>
>No functional changes. Just cleaning and reorganizing it.
>
>v2: Rebase it puting it to begin of psr rework. This helps to blame easily
>at least latest changes.
>
>Signed-off-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
>---
> drivers/gpu/drm/i915/Makefile | 1 +
> drivers/gpu/drm/i915/intel_ddi.c | 4 +-
> drivers/gpu/drm/i915/intel_display.c | 2 +-
> drivers/gpu/drm/i915/intel_dp.c | 381 +----------------------------
> drivers/gpu/drm/i915/intel_drv.h | 21 +-
> drivers/gpu/drm/i915/intel_frontbuffer.c | 4 +-
> drivers/gpu/drm/i915/intel_psr.c | 408 +++++++++++++++++++++++++++++++
> 7 files changed, 428 insertions(+), 393 deletions(-)
> create mode 100644 drivers/gpu/drm/i915/intel_psr.c
>
>diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>index 891e584..e4083e4 100644
>--- a/drivers/gpu/drm/i915/Makefile
>+++ b/drivers/gpu/drm/i915/Makefile
>@@ -51,6 +51,7 @@ i915-y += intel_audio.o \
> intel_frontbuffer.o \
> intel_modes.o \
> intel_overlay.o \
>+ intel_psr.o \
> intel_sideband.o \
> intel_sprite.o
> i915-$(CONFIG_ACPI) += intel_acpi.o intel_opregion.o
>diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
>index 68703ce..a5a8acd 100644
>--- a/drivers/gpu/drm/i915/intel_ddi.c
>+++ b/drivers/gpu/drm/i915/intel_ddi.c
>@@ -1228,7 +1228,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
> intel_dp_stop_link_train(intel_dp);
>
> intel_edp_backlight_on(intel_dp);
>- intel_edp_psr_enable(intel_dp);
>+ intel_psr_enable(intel_dp);
> }
>
> if (intel_crtc->config.has_audio) {
>@@ -1254,7 +1254,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
> if (type == INTEL_OUTPUT_EDP) {
> struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
>
>- intel_edp_psr_disable(intel_dp);
>+ intel_psr_disable(intel_dp);
> intel_edp_backlight_off(intel_dp);
> }
> }
>diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>index 4706856..2ca6939 100644
>--- a/drivers/gpu/drm/i915/intel_display.c
>+++ b/drivers/gpu/drm/i915/intel_display.c
>@@ -12310,7 +12310,7 @@ static void intel_setup_outputs(struct drm_device *dev)
> if (SUPPORTS_TV(dev))
> intel_tv_init(dev);
>
>- intel_edp_psr_init(dev);
>+ intel_psr_init(dev);
>
> for_each_intel_encoder(dev, encoder) {
> encoder->base.possible_crtcs = encoder->crtc_mask;
>diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>index 01834cd..98f7ecd 100644
>--- a/drivers/gpu/drm/i915/intel_dp.c
>+++ b/drivers/gpu/drm/i915/intel_dp.c
>@@ -2066,385 +2066,6 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> }
> }
>
>-static bool is_edp_psr(struct intel_dp *intel_dp)
>-{
>- return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>-}
>-
>-static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>-{
>- struct drm_i915_private *dev_priv = dev->dev_private;
>-
>- if (!HAS_PSR(dev))
>- return false;
>-
>- return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>-}
>-
>-static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>- struct edp_vsc_psr *vsc_psr)
>-{
>- 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 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);
>- uint32_t *data = (uint32_t *) vsc_psr;
>- unsigned int i;
>-
>- /* As per BSPec (Pipe Video Data Island Packet), we need to disable
>- the video DIP being updated before program video DIP data buffer
>- registers for DIP being updated. */
>- I915_WRITE(ctl_reg, 0);
>- POSTING_READ(ctl_reg);
>-
>- for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
>- if (i < sizeof(struct edp_vsc_psr))
>- I915_WRITE(data_reg + i, *data++);
>- else
>- I915_WRITE(data_reg + i, 0);
>- }
>-
>- I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
>- POSTING_READ(ctl_reg);
>-}
>-
>-static void intel_edp_psr_setup_vsc(struct intel_dp *intel_dp)
>-{
>- struct edp_vsc_psr psr_vsc;
>-
>- /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>- memset(&psr_vsc, 0, sizeof(psr_vsc));
>- psr_vsc.sdp_header.HB0 = 0;
>- psr_vsc.sdp_header.HB1 = 0x7;
>- psr_vsc.sdp_header.HB2 = 0x2;
>- psr_vsc.sdp_header.HB3 = 0x8;
>- intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>-}
>-
>-static void intel_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;
>- struct drm_i915_private *dev_priv = dev->dev_private;
>- uint32_t aux_clock_divider;
>- int precharge = 0x3;
>- bool only_standby = false;
>- static const uint8_t aux_msg[] = {
>- [0] = DP_AUX_NATIVE_WRITE << 4,
>- [1] = DP_SET_POWER >> 8,
>- [2] = DP_SET_POWER & 0xff,
>- [3] = 1 - 1,
>- [4] = DP_SET_POWER_D0,
>- };
>- int i;
>-
>- BUILD_BUG_ON(sizeof(aux_msg) > 20);
>-
>- 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)
>- 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);
>-
>- /* Setup AUX registers */
>- for (i = 0; i < sizeof(aux_msg); i += 4)
>- I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
>- intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
>-
>- I915_WRITE(EDP_PSR_AUX_CTL(dev),
>- 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_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;
>- uint32_t max_sleep_time = 0x1f;
>- uint32_t idle_frames = 1;
>- 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) {
>- 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;
>-
>- 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);
>-}
>-
>-static bool intel_edp_psr_match_conditions(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;
>- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>-
>- lockdep_assert_held(&dev_priv->psr.lock);
>- WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
>- WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
>-
>- dev_priv->psr.source_ok = false;
>-
>- if (IS_HASWELL(dev) && dig_port->port != PORT_A) {
>- DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>- return false;
>- }
>-
>- if (!i915.enable_psr) {
>- DRM_DEBUG_KMS("PSR disable by flag\n");
>- 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) {
>- DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
>- return false;
>- }
>-
>- if (intel_crtc->config.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_edp_psr_do_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;
>-
>- WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>- WARN_ON(dev_priv->psr.active);
>- lockdep_assert_held(&dev_priv->psr.lock);
>-
>- /* Enable/Re-enable PSR on the host */
>- intel_edp_psr_enable_source(intel_dp);
>-
>- dev_priv->psr.active = true;
>-}
>-
>-void intel_edp_psr_enable(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 (!HAS_PSR(dev)) {
>- DRM_DEBUG_KMS("PSR not supported on this platform\n");
>- return;
>- }
>-
>- if (!is_edp_psr(intel_dp)) {
>- DRM_DEBUG_KMS("PSR not supported by this panel\n");
>- return;
>- }
>-
>- mutex_lock(&dev_priv->psr.lock);
>- if (dev_priv->psr.enabled) {
>- DRM_DEBUG_KMS("PSR already in use\n");
>- goto unlock;
>- }
>-
>- if (!intel_edp_psr_match_conditions(intel_dp))
>- goto unlock;
>-
>- dev_priv->psr.busy_frontbuffer_bits = 0;
>-
>- intel_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);
>-
>- /* Enable PSR on the panel */
>- intel_edp_psr_enable_sink(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)
>-{
>- 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 (dev_priv->psr.active) {
>- I915_WRITE(EDP_PSR_CTL(dev),
>- I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
>-
>- /* Wait till PSR is idle */
>- if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
>- EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
>- DRM_ERROR("Timed out waiting for PSR Idle State\n");
>-
>- dev_priv->psr.active = false;
>- } else {
>- WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>- }
>-
>- dev_priv->psr.enabled = NULL;
>- mutex_unlock(&dev_priv->psr.lock);
>-
>- cancel_delayed_work_sync(&dev_priv->psr.work);
>-}
>-
>-static void intel_edp_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;
>-
>- /* 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;
>- }
>-
>- mutex_lock(&dev_priv->psr.lock);
>- intel_dp = dev_priv->psr.enabled;
>-
>- if (!intel_dp)
>- goto unlock;
>-
>- /*
>- * The delayed work can race with an invalidate hence we need to
>- * recheck. Since psr_flush first clears this and then reschedules we
>- * won't ever miss a flush when bailing out here.
>- */
>- if (dev_priv->psr.busy_frontbuffer_bits)
>- goto unlock;
>-
>- intel_edp_psr_do_enable(intel_dp);
>-unlock:
>- mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-static void intel_edp_psr_do_exit(struct drm_device *dev)
>-{
>- struct drm_i915_private *dev_priv = dev->dev_private;
>-
>- if (dev_priv->psr.active) {
>- u32 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;
>- }
>-
>-}
>-
>-void intel_edp_psr_invalidate(struct drm_device *dev,
>- unsigned frontbuffer_bits)
>-{
>- struct drm_i915_private *dev_priv = dev->dev_private;
>- struct drm_crtc *crtc;
>- enum pipe pipe;
>-
>- 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;
>-
>- intel_edp_psr_do_exit(dev);
>-
>- frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
>-
>- dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits;
>- mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-void intel_edp_psr_flush(struct drm_device *dev,
>- unsigned frontbuffer_bits)
>-{
>- struct drm_i915_private *dev_priv = dev->dev_private;
>- struct drm_crtc *crtc;
>- enum pipe pipe;
>-
>- 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;
>- dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits;
>-
>- /*
>- * On Haswell sprite plane updates don't result in a psr invalidating
>- * signal in the hardware. 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 (IS_HASWELL(dev) &&
>- (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
>- intel_edp_psr_do_exit(dev);
>-
>- if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
>- schedule_delayed_work(&dev_priv->psr.work,
>- msecs_to_jiffies(100));
>- mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-void intel_edp_psr_init(struct drm_device *dev)
>-{
>- struct drm_i915_private *dev_priv = dev->dev_private;
>-
>- INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
>- mutex_init(&dev_priv->psr.lock);
>-}
>-
> static void intel_disable_dp(struct intel_encoder *encoder)
> {
> struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>@@ -5115,7 +4736,7 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
> * hard to tell without seeing the user of this function of this code.
> * Check locking and ordering once that lands.
> */
>- if (INTEL_INFO(dev)->gen < 8 && intel_edp_is_psr_enabled(dev)) {
>+ if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) {
Shouldn't we do <= 8 to cover CHV ?
Also, I see that we are converting the 'static' _is_enabled function into a
non-static (exported) one and use 'psr.enabled' variable. (patch 9/15)
In this case, shouldn't we protect this function using psr.lock ?
[actually a comment on patch 9/15, but the caller is here]
Thanks,
Durga
> DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
> return;
> }
>diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>index 8432ae2..ccfee9c 100644
>--- a/drivers/gpu/drm/i915/intel_drv.h
>+++ b/drivers/gpu/drm/i915/intel_drv.h
>@@ -996,21 +996,16 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp);
> void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
> void intel_edp_panel_on(struct intel_dp *intel_dp);
> void intel_edp_panel_off(struct intel_dp *intel_dp);
>-void intel_edp_psr_enable(struct intel_dp *intel_dp);
>-void intel_edp_psr_disable(struct intel_dp *intel_dp);
> void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
>-void intel_edp_psr_invalidate(struct drm_device *dev,
>- unsigned frontbuffer_bits);
>-void intel_edp_psr_flush(struct drm_device *dev,
>- unsigned frontbuffer_bits);
>-void intel_edp_psr_init(struct drm_device *dev);
>-
> void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
> void intel_dp_mst_suspend(struct drm_device *dev);
> void intel_dp_mst_resume(struct drm_device *dev);
> int intel_dp_max_link_bw(struct intel_dp *intel_dp);
> void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
> void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
>+uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
>+void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
>+
> /* intel_dp_mst.c */
> int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
> void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
>@@ -1114,6 +1109,16 @@ void intel_backlight_register(struct drm_device *dev);
> void intel_backlight_unregister(struct drm_device *dev);
>
>
>+/* intel_psr.c */
>+bool intel_psr_is_enabled(struct drm_device *dev);
>+void intel_psr_enable(struct intel_dp *intel_dp);
>+void intel_psr_disable(struct intel_dp *intel_dp);
>+void intel_psr_invalidate(struct drm_device *dev,
>+ unsigned frontbuffer_bits);
>+void intel_psr_flush(struct drm_device *dev,
>+ unsigned frontbuffer_bits);
>+void intel_psr_init(struct drm_device *dev);
>+
> /* intel_runtime_pm.c */
> int intel_power_domains_init(struct drm_i915_private *);
> void intel_power_domains_fini(struct drm_i915_private *);
>diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c
>index 58cf2e6..79f6d72 100644
>--- a/drivers/gpu/drm/i915/intel_frontbuffer.c
>+++ b/drivers/gpu/drm/i915/intel_frontbuffer.c
>@@ -156,7 +156,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
>
> intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring);
>
>- intel_edp_psr_invalidate(dev, obj->frontbuffer_bits);
>+ intel_psr_invalidate(dev, obj->frontbuffer_bits);
> }
>
> /**
>@@ -182,7 +182,7 @@ void intel_frontbuffer_flush(struct drm_device *dev,
>
> intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
>
>- intel_edp_psr_flush(dev, frontbuffer_bits);
>+ intel_psr_flush(dev, frontbuffer_bits);
>
> /*
> * FIXME: Unconditional fbc flushing here is a rather gross hack and
>diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
>new file mode 100644
>index 0000000..7b3ed91
>--- /dev/null
>+++ b/drivers/gpu/drm/i915/intel_psr.c
>@@ -0,0 +1,408 @@
>+/*
>+ * Copyright © 2014 Intel Corporation
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a
>+ * copy of this software and associated documentation files (the "Software"),
>+ * to deal in the Software without restriction, including without limitation
>+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>+ * and/or sell copies of the Software, and to permit persons to whom the
>+ * Software is furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice (including the next
>+ * paragraph) shall be included in all copies or substantial portions of the
>+ * Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>+ * DEALINGS IN THE SOFTWARE.
>+ */
>+
>+#include <drm/drmP.h>
>+
>+#include "intel_drv.h"
>+#include "i915_drv.h"
>+
>+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)
>+{
>+ struct drm_i915_private *dev_priv = dev->dev_private;
>+
>+ if (!HAS_PSR(dev))
>+ return false;
>+
>+ return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>+}
>+
>+static void intel_psr_write_vsc(struct intel_dp *intel_dp,
>+ struct edp_vsc_psr *vsc_psr)
>+{
>+ 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 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);
>+ uint32_t *data = (uint32_t *) vsc_psr;
>+ unsigned int i;
>+
>+ /* As per BSPec (Pipe Video Data Island Packet), we need to disable
>+ the video DIP being updated before program video DIP data buffer
>+ registers for DIP being updated. */
>+ I915_WRITE(ctl_reg, 0);
>+ POSTING_READ(ctl_reg);
>+
>+ for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
>+ if (i < sizeof(struct edp_vsc_psr))
>+ I915_WRITE(data_reg + i, *data++);
>+ else
>+ I915_WRITE(data_reg + i, 0);
>+ }
>+
>+ I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
>+ POSTING_READ(ctl_reg);
>+}
>+
>+static void intel_psr_setup_vsc(struct intel_dp *intel_dp)
>+{
>+ struct edp_vsc_psr psr_vsc;
>+
>+ /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>+ memset(&psr_vsc, 0, sizeof(psr_vsc));
>+ psr_vsc.sdp_header.HB0 = 0;
>+ psr_vsc.sdp_header.HB1 = 0x7;
>+ psr_vsc.sdp_header.HB2 = 0x2;
>+ psr_vsc.sdp_header.HB3 = 0x8;
>+ intel_psr_write_vsc(intel_dp, &psr_vsc);
>+}
>+
>+static void intel_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;
>+ int precharge = 0x3;
>+ bool only_standby = false;
>+ static const uint8_t aux_msg[] = {
>+ [0] = DP_AUX_NATIVE_WRITE << 4,
>+ [1] = DP_SET_POWER >> 8,
>+ [2] = DP_SET_POWER & 0xff,
>+ [3] = 1 - 1,
>+ [4] = DP_SET_POWER_D0,
>+ };
>+ int i;
>+
>+ BUILD_BUG_ON(sizeof(aux_msg) > 20);
>+
>+ 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)
>+ 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);
>+
>+ /* Setup AUX registers */
>+ for (i = 0; i < sizeof(aux_msg); i += 4)
>+ I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
>+ intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
>+
>+ I915_WRITE(EDP_PSR_AUX_CTL(dev),
>+ 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)
>+{
>+ 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;
>+ 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) {
>+ 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;
>+
>+ 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);
>+}
>+
>+static bool intel_psr_match_conditions(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;
>+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>+
>+ lockdep_assert_held(&dev_priv->psr.lock);
>+ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
>+ WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
>+
>+ dev_priv->psr.source_ok = false;
>+
>+ if (IS_HASWELL(dev) && dig_port->port != PORT_A) {
>+ DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>+ return false;
>+ }
>+
>+ if (!i915.enable_psr) {
>+ DRM_DEBUG_KMS("PSR disable by flag\n");
>+ 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) {
>+ DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
>+ return false;
>+ }
>+
>+ if (intel_crtc->config.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)
>+{
>+ 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;
>+
>+ WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>+ WARN_ON(dev_priv->psr.active);
>+ lockdep_assert_held(&dev_priv->psr.lock);
>+
>+ /* Enable/Re-enable PSR on the host */
>+ intel_psr_enable_source(intel_dp);
>+
>+ dev_priv->psr.active = true;
>+}
>+
>+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;
>+
>+ if (!HAS_PSR(dev)) {
>+ DRM_DEBUG_KMS("PSR not supported on this platform\n");
>+ return;
>+ }
>+
>+ if (!is_edp_psr(intel_dp)) {
>+ DRM_DEBUG_KMS("PSR not supported by this panel\n");
>+ return;
>+ }
>+
>+ mutex_lock(&dev_priv->psr.lock);
>+ if (dev_priv->psr.enabled) {
>+ DRM_DEBUG_KMS("PSR already in use\n");
>+ goto unlock;
>+ }
>+
>+ if (!intel_psr_match_conditions(intel_dp))
>+ goto unlock;
>+
>+ dev_priv->psr.busy_frontbuffer_bits = 0;
>+
>+ intel_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);
>+
>+ /* Enable PSR on the panel */
>+ intel_psr_enable_sink(intel_dp);
>+
>+ dev_priv->psr.enabled = intel_dp;
>+unlock:
>+ mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+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 (dev_priv->psr.active) {
>+ I915_WRITE(EDP_PSR_CTL(dev),
>+ I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
>+
>+ /* Wait till PSR is idle */
>+ if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
>+ EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
>+ DRM_ERROR("Timed out waiting for PSR Idle State\n");
>+
>+ dev_priv->psr.active = false;
>+ } else {
>+ WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>+ }
>+
>+ dev_priv->psr.enabled = NULL;
>+ mutex_unlock(&dev_priv->psr.lock);
>+
>+ cancel_delayed_work_sync(&dev_priv->psr.work);
>+}
>+
>+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;
>+
>+ /* 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;
>+ }
>+
>+ mutex_lock(&dev_priv->psr.lock);
>+ intel_dp = dev_priv->psr.enabled;
>+
>+ if (!intel_dp)
>+ goto unlock;
>+
>+ /*
>+ * The delayed work can race with an invalidate hence we need to
>+ * recheck. Since psr_flush first clears this and then reschedules we
>+ * won't ever miss a flush when bailing out here.
>+ */
>+ if (dev_priv->psr.busy_frontbuffer_bits)
>+ goto unlock;
>+
>+ intel_psr_do_enable(intel_dp);
>+unlock:
>+ mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+static void intel_psr_exit(struct drm_device *dev)
>+{
>+ struct drm_i915_private *dev_priv = dev->dev_private;
>+
>+ if (dev_priv->psr.active) {
>+ u32 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;
>+ }
>+
>+}
>+
>+void intel_psr_invalidate(struct drm_device *dev,
>+ unsigned frontbuffer_bits)
>+{
>+ struct drm_i915_private *dev_priv = dev->dev_private;
>+ struct drm_crtc *crtc;
>+ enum pipe pipe;
>+
>+ 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;
>+
>+ intel_psr_exit(dev);
>+
>+ frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
>+
>+ dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits;
>+ mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+void intel_psr_flush(struct drm_device *dev,
>+ unsigned frontbuffer_bits)
>+{
>+ struct drm_i915_private *dev_priv = dev->dev_private;
>+ struct drm_crtc *crtc;
>+ enum pipe pipe;
>+
>+ 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;
>+ dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits;
>+
>+ /*
>+ * On Haswell sprite plane updates don't result in a psr invalidating
>+ * signal in the hardware. 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 (IS_HASWELL(dev) &&
>+ (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
>+ 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));
>+ mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+void intel_psr_init(struct drm_device *dev)
>+{
>+ struct drm_i915_private *dev_priv = dev->dev_private;
>+
>+ INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work);
>+ mutex_init(&dev_priv->psr.lock);
>+}
>--
>1.9.3
>
>_______________________________________________
>Intel-gfx mailing list
>Intel-gfx at lists.freedesktop.org
>http://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list