]> git.itanic.dy.fi Git - linux-stable/commitdiff
drm/i915/display: Only keep PSR enabled if there is active planes
authorJosé Roberto de Souza <jose.souza@intel.com>
Wed, 22 Sep 2021 21:52:42 +0000 (14:52 -0700)
committerJosé Roberto de Souza <jose.souza@intel.com>
Thu, 23 Sep 2021 17:06:17 +0000 (10:06 -0700)
PSR always had a requirement to only be enabled if there is active
planes but not following that never caused any issues.
But that changes in Alderlake-P, leaving PSR enabled without
active planes causes transcoder/port underruns.

Similar behavior was fixed during the pipe disable sequence by
commit 84030adb9e27 ("drm/i915/display: Disable audio, DRRS and PSR before planes").

intel_dp_compute_psr_vsc_sdp() had to move from
intel_psr_enable_locked() to intel_psr_compute_config() because we
need to be able to disable/enable PSR from atomic states without
connector and encoder state.

Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210922215242.66683-3-jose.souza@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_psr.h

index bba0ab99836b1730b6a27356bd5b21369b05c5ad..a4667741d354891f01c09b053d972b66a4c7a5fa 100644 (file)
@@ -3034,7 +3034,6 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
                intel_dp_stop_link_train(intel_dp, crtc_state);
 
        intel_edp_backlight_on(crtc_state, conn_state);
-       intel_psr_enable(intel_dp, crtc_state, conn_state);
 
        if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
                intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
@@ -3255,7 +3254,6 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
 
        intel_ddi_set_dp_msa(crtc_state, conn_state);
 
-       intel_psr_update(intel_dp, crtc_state, conn_state);
        intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
        intel_drrs_update(intel_dp, crtc_state);
 
index ac33bb935e9bcdb6b3bb857bed9fc058317b9eec..f27c294beb9267257bb9cd18449ca38ddeb4e647 100644 (file)
@@ -8098,10 +8098,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
                if (bp_gamma)
                        PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma);
 
-               PIPE_CONF_CHECK_BOOL(has_psr);
-               PIPE_CONF_CHECK_BOOL(has_psr2);
-               PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
-               PIPE_CONF_CHECK_I(dc3co_exitline);
+               if (current_config->active_planes) {
+                       PIPE_CONF_CHECK_BOOL(has_psr);
+                       PIPE_CONF_CHECK_BOOL(has_psr2);
+                       PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
+                       PIPE_CONF_CHECK_I(dc3co_exitline);
+               }
        }
 
        PIPE_CONF_CHECK_BOOL(double_wide);
@@ -8158,7 +8160,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
                PIPE_CONF_CHECK_I(min_voltage_level);
        }
 
-       if (fastset && (current_config->has_psr || pipe_config->has_psr))
+       if (current_config->has_psr || pipe_config->has_psr)
                PIPE_CONF_CHECK_X_WITH_MASK(infoframes.enable,
                                            ~intel_hdmi_infoframe_enable(DP_SDP_VSC));
        else
@@ -10212,6 +10214,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
                intel_encoders_update_prepare(state);
 
        intel_dbuf_pre_plane_update(state);
+       intel_psr_pre_plane_update(state);
 
        for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
                if (new_crtc_state->uapi.async_flip)
@@ -10275,6 +10278,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
        }
 
        intel_dbuf_post_plane_update(state);
+       intel_psr_post_plane_update(state);
 
        for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                intel_post_plane_update(state, crtc);
index 73930c24d7fb236a4585a88cfa9f579c1751de65..9413ebae15f57df1a6f9af14beb79d44c6964d8b 100644 (file)
@@ -1054,12 +1054,14 @@ struct intel_crtc_state {
        struct intel_link_m_n dp_m2_n2;
        bool has_drrs;
 
+       /* PSR is supported but might not be enabled due the lack of enabled planes */
        bool has_psr;
        bool has_psr2;
        bool enable_psr2_sel_fetch;
        bool req_psr2_sdp_prior_scanline;
        u32 dc3co_exitline;
        u16 su_y_granularity;
+       struct drm_dp_vsc_sdp psr_vsc;
 
        /*
         * Frequence the dpll for the port should run at. Differs from the
@@ -1523,7 +1525,6 @@ struct intel_psr {
        u32 dc3co_exitline;
        u32 dc3co_exit_delay;
        struct delayed_work dc3co_work;
-       struct drm_dp_vsc_sdp vsc;
 };
 
 struct intel_dp {
index 7559911c140a71a6b6c91a526acd3435208323fe..378008873e039f4f2a3a097d883d4edbfd2c73f0 100644 (file)
@@ -1674,7 +1674,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
 {
        vsc->sdp_type = DP_SDP_VSC;
 
-       if (intel_dp->psr.psr2_enabled) {
+       if (crtc_state->has_psr2) {
                if (intel_dp->psr.colorimetry_support &&
                    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
                        /* [PSR2, +Colorimetry] */
@@ -1828,7 +1828,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                g4x_dp_set_clock(encoder, pipe_config);
 
        intel_vrr_compute_config(pipe_config, conn_state);
-       intel_psr_compute_config(intel_dp, pipe_config);
+       intel_psr_compute_config(intel_dp, pipe_config, conn_state);
        intel_drrs_compute_config(intel_dp, pipe_config, output_bpp,
                                  constant_n);
        intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
@@ -2888,7 +2888,7 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder,
 
 void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
                            const struct intel_crtc_state *crtc_state,
-                           struct drm_dp_vsc_sdp *vsc)
+                           const struct drm_dp_vsc_sdp *vsc)
 {
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
index 94b568704b22b1e23eca3dac798aa53fa40590e4..3343c25916807ea3c70182498484406f90922c32 100644 (file)
@@ -88,7 +88,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
                                  struct drm_dp_vsc_sdp *vsc);
 void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
                            const struct intel_crtc_state *crtc_state,
-                           struct drm_dp_vsc_sdp *vsc);
+                           const struct drm_dp_vsc_sdp *vsc);
 void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable,
                             const struct intel_crtc_state *crtc_state,
                             const struct drm_connector_state *conn_state);
index 868e5205dd09eb18ec89b253a3337f6367ea900c..19a96d3c4acf429014977a9813a3a69fc44e6dae 100644 (file)
@@ -950,7 +950,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
 }
 
 void intel_psr_compute_config(struct intel_dp *intel_dp,
-                             struct intel_crtc_state *crtc_state)
+                             struct intel_crtc_state *crtc_state,
+                             struct drm_connector_state *conn_state)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
        const struct drm_display_mode *adjusted_mode =
@@ -1002,7 +1003,10 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
 
        crtc_state->has_psr = true;
        crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
+
        crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC);
+       intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
+                                    &crtc_state->psr_vsc);
 }
 
 void intel_psr_get_config(struct intel_encoder *encoder,
@@ -1182,8 +1186,7 @@ static bool psr_interrupt_error_check(struct intel_dp *intel_dp)
 }
 
 static void intel_psr_enable_locked(struct intel_dp *intel_dp,
-                                   const struct intel_crtc_state *crtc_state,
-                                   const struct drm_connector_state *conn_state)
+                                   const struct intel_crtc_state *crtc_state)
 {
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1210,9 +1213,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
 
        drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n",
                    intel_dp->psr.psr2_enabled ? "2" : "1");
-       intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
-                                    &intel_dp->psr.vsc);
-       intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc);
+       intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc);
        intel_snps_phy_update_psr_power_state(dev_priv, phy, true);
        intel_psr_enable_sink(intel_dp);
        intel_psr_enable_source(intel_dp);
@@ -1222,33 +1223,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
        intel_psr_activate(intel_dp);
 }
 
-/**
- * intel_psr_enable - Enable PSR
- * @intel_dp: Intel DP
- * @crtc_state: new CRTC state
- * @conn_state: new CONNECTOR state
- *
- * This function can only be called after the pipe is fully trained and enabled.
- */
-void intel_psr_enable(struct intel_dp *intel_dp,
-                     const struct intel_crtc_state *crtc_state,
-                     const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (!CAN_PSR(intel_dp))
-               return;
-
-       if (!crtc_state->has_psr)
-               return;
-
-       drm_WARN_ON(&dev_priv->drm, dev_priv->drrs.dp);
-
-       mutex_lock(&intel_dp->psr.lock);
-       intel_psr_enable_locked(intel_dp, crtc_state, conn_state);
-       mutex_unlock(&intel_dp->psr.lock);
-}
-
 static void intel_psr_exit(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1734,48 +1708,92 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
        return 0;
 }
 
-/**
- * intel_psr_update - Update PSR state
- * @intel_dp: Intel DP
- * @crtc_state: new CRTC state
- * @conn_state: new CONNECTOR state
- *
- * This functions will update PSR states, disabling, enabling or switching PSR
- * version when executing fastsets. For full modeset, intel_psr_disable() and
- * intel_psr_enable() should be called instead.
- */
-void intel_psr_update(struct intel_dp *intel_dp,
-                     const struct intel_crtc_state *crtc_state,
-                     const struct drm_connector_state *conn_state)
+static void _intel_psr_pre_plane_update(const struct intel_atomic_state *state,
+                                       const struct intel_crtc_state *crtc_state)
 {
-       struct intel_psr *psr = &intel_dp->psr;
-       bool enable, psr2_enable;
+       struct intel_encoder *encoder;
 
-       if (!CAN_PSR(intel_dp))
+       for_each_intel_encoder_mask_with_psr(state->base.dev, encoder,
+                                            crtc_state->uapi.encoder_mask) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+               struct intel_psr *psr = &intel_dp->psr;
+               bool needs_to_disable = false;
+
+               mutex_lock(&psr->lock);
+
+               /*
+                * Reasons to disable:
+                * - PSR disabled in new state
+                * - All planes will go inactive
+                * - Changing between PSR versions
+                */
+               needs_to_disable |= !crtc_state->has_psr;
+               needs_to_disable |= !crtc_state->active_planes;
+               needs_to_disable |= crtc_state->has_psr2 != psr->psr2_enabled;
+
+               if (psr->enabled && needs_to_disable)
+                       intel_psr_disable_locked(intel_dp);
+
+               mutex_unlock(&psr->lock);
+       }
+}
+
+void intel_psr_pre_plane_update(const struct intel_atomic_state *state)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct intel_crtc_state *crtc_state;
+       struct intel_crtc *crtc;
+       int i;
+
+       if (!HAS_PSR(dev_priv))
                return;
 
-       mutex_lock(&intel_dp->psr.lock);
+       for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
+               _intel_psr_pre_plane_update(state, crtc_state);
+}
 
-       enable = crtc_state->has_psr;
-       psr2_enable = crtc_state->has_psr2;
+static void _intel_psr_post_plane_update(const struct intel_atomic_state *state,
+                                        const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct intel_encoder *encoder;
+
+       if (!crtc_state->has_psr)
+               return;
+
+       for_each_intel_encoder_mask_with_psr(state->base.dev, encoder,
+                                            crtc_state->uapi.encoder_mask) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+               struct intel_psr *psr = &intel_dp->psr;
+
+               mutex_lock(&psr->lock);
+
+               drm_WARN_ON(&dev_priv->drm, psr->enabled && !crtc_state->active_planes);
+
+               /* Only enable if there is active planes */
+               if (!psr->enabled && crtc_state->active_planes)
+                       intel_psr_enable_locked(intel_dp, crtc_state);
 
-       if (enable == psr->enabled && psr2_enable == psr->psr2_enabled &&
-           crtc_state->enable_psr2_sel_fetch == psr->psr2_sel_fetch_enabled) {
                /* Force a PSR exit when enabling CRC to avoid CRC timeouts */
                if (crtc_state->crc_enabled && psr->enabled)
                        psr_force_hw_tracking_exit(intel_dp);
 
-               goto unlock;
+               mutex_unlock(&psr->lock);
        }
+}
 
-       if (psr->enabled)
-               intel_psr_disable_locked(intel_dp);
+void intel_psr_post_plane_update(const struct intel_atomic_state *state)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct intel_crtc_state *crtc_state;
+       struct intel_crtc *crtc;
+       int i;
 
-       if (enable)
-               intel_psr_enable_locked(intel_dp, crtc_state, conn_state);
+       if (!HAS_PSR(dev_priv))
+               return;
 
-unlock:
-       mutex_unlock(&intel_dp->psr.lock);
+       for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
+               _intel_psr_post_plane_update(state, crtc_state);
 }
 
 /**
index e502964697c6200c24582867b923670de6017164..facffbacd35756cd5a43587485ee1bcafa9784c0 100644 (file)
@@ -20,14 +20,10 @@ struct intel_plane;
 struct intel_encoder;
 
 void intel_psr_init_dpcd(struct intel_dp *intel_dp);
-void intel_psr_enable(struct intel_dp *intel_dp,
-                     const struct intel_crtc_state *crtc_state,
-                     const struct drm_connector_state *conn_state);
+void intel_psr_pre_plane_update(const struct intel_atomic_state *state);
+void intel_psr_post_plane_update(const struct intel_atomic_state *state);
 void intel_psr_disable(struct intel_dp *intel_dp,
                       const struct intel_crtc_state *old_crtc_state);
-void intel_psr_update(struct intel_dp *intel_dp,
-                     const struct intel_crtc_state *crtc_state,
-                     const struct drm_connector_state *conn_state);
 int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value);
 void intel_psr_invalidate(struct drm_i915_private *dev_priv,
                          unsigned frontbuffer_bits,
@@ -37,7 +33,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
                     enum fb_op_origin origin);
 void intel_psr_init(struct intel_dp *intel_dp);
 void intel_psr_compute_config(struct intel_dp *intel_dp,
-                             struct intel_crtc_state *crtc_state);
+                             struct intel_crtc_state *crtc_state,
+                             struct drm_connector_state *conn_state);
 void intel_psr_get_config(struct intel_encoder *encoder,
                          struct intel_crtc_state *pipe_config);
 void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);