drm/i915: Initial implementation of PSR2 selective fetch
authorJosé Roberto de Souza <jose.souza@intel.com>
Mon, 10 Aug 2020 17:41:43 +0000 (10:41 -0700)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Mon, 17 Aug 2020 20:17:15 +0000 (16:17 -0400)
All GEN12 platforms supports PSR2 selective fetch but not all GEN12
platforms supports PSR2 hardware tracking(aka RKL).

This feature consists in software programming registers with the
damaged area of each plane this way hardware will only fetch from
memory those areas and sent the PSR2 selective update blocks to panel,
saving even more power.

But as initial step it is only enabling the full frame fetch at
every flip, the actual selective fetch part will come in a future
patch.

Also this is only handling the page flip side, it is still completely
missing frontbuffer modifications, that is why the
enable_psr2_sel_fetch parameter was added.

v3:
- calling intel_psr2_sel_fetch_update() during the atomic check phase
(Ville)

BSpec: 55229
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Reviewed-by: 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/20200810174144.76761-1-jose.souza@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_psr.h
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_params.h

index 522c772a2111714216e53797da3c0830d5303466..2ddabf92adde1ce1cfd2c060714fa2731263cf3a 100644 (file)
@@ -12770,6 +12770,9 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
 
        }
 
+       if (!mode_changed)
+               intel_psr2_sel_fetch_update(state, crtc);
+
        return 0;
 }
 
@@ -15146,6 +15149,8 @@ static void commit_pipe_config(struct intel_atomic_state *state,
 
                if (new_crtc_state->update_pipe)
                        intel_pipe_fastset(old_crtc_state, new_crtc_state);
+
+               intel_psr2_program_trans_man_trk_ctl(new_crtc_state);
        }
 
        if (dev_priv->display.atomic_update_watermarks)
index 5a5cfe25085b4aa33b584bc43bc2a617580880cd..f549381048b3c612b8370e7edb9718ba85d8ab50 100644 (file)
@@ -417,6 +417,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
                        su_blocks = su_blocks >> PSR2_SU_STATUS_SHIFT(frame);
                        seq_printf(m, "%d\t%d\n", frame, su_blocks);
                }
+
+               seq_printf(m, "PSR2 selective fetch: %s\n",
+                          enableddisabled(psr->psr2_sel_fetch_enabled));
        }
 
 unlock:
index f581260e8dbfd9671c0dd1d2fcbae67bdef190b3..9349b15afff679345c3a76a9ffc07340e4ccfb5e 100644 (file)
@@ -931,6 +931,7 @@ struct intel_crtc_state {
 
        bool has_psr;
        bool has_psr2;
+       bool enable_psr2_sel_fetch;
        u32 dc3co_exitline;
 
        /*
@@ -1073,6 +1074,8 @@ struct intel_crtc_state {
 
        /* For DSB related info */
        struct intel_dsb *dsb;
+
+       u32 psr2_man_track_ctl;
 };
 
 enum intel_pipe_crc_source {
index bf9e320c547da67ab937b797fbb4fb16eda67787..d30a3560b7942b049a2466145ea619c37c498ae0 100644 (file)
@@ -553,6 +553,14 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
                val |= EDP_PSR2_FAST_WAKE(7);
        }
 
+       if (dev_priv->psr.psr2_sel_fetch_enabled)
+               intel_de_write(dev_priv,
+                              PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder),
+                              PSR2_MAN_TRK_CTL_ENABLE);
+       else if (HAS_PSR2_SEL_FETCH(dev_priv))
+               intel_de_write(dev_priv,
+                              PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder), 0);
+
        /*
         * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is
         * recommending keep this bit unset while PSR2 is enabled.
@@ -663,6 +671,38 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp,
        crtc_state->dc3co_exitline = crtc_vdisplay - exit_scanlines;
 }
 
+static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp,
+                                             struct intel_crtc_state *crtc_state)
+{
+       struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state);
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
+       int i;
+
+       if (!dev_priv->params.enable_psr2_sel_fetch) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "PSR2 sel fetch not enabled, disabled by parameter\n");
+               return false;
+       }
+
+       if (crtc_state->uapi.async_flip) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "PSR2 sel fetch not enabled, async flip enabled\n");
+               return false;
+       }
+
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               if (plane_state->uapi.rotation != DRM_MODE_ROTATE_0) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "PSR2 sel fetch not enabled, plane rotated\n");
+                       return false;
+               }
+       }
+
+       return crtc_state->enable_psr2_sel_fetch = true;
+}
+
 static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
                                    struct intel_crtc_state *crtc_state)
 {
@@ -732,22 +772,17 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
                return false;
        }
 
-       /*
-        * Some platforms lack PSR2 HW tracking and instead require manual
-        * tracking by software.  In this case, the driver is required to track
-        * the areas that need updates and program hardware to send selective
-        * updates.
-        *
-        * So until the software tracking is implemented, PSR2 needs to be
-        * disabled for platforms without PSR2 HW tracking.
-        */
-       if (!HAS_PSR_HW_TRACKING(dev_priv)) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "No PSR2 HW tracking in the platform\n");
-               return false;
+       if (HAS_PSR2_SEL_FETCH(dev_priv)) {
+               if (!intel_psr2_sel_fetch_config_valid(intel_dp, crtc_state) &&
+                   !HAS_PSR_HW_TRACKING(dev_priv)) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "PSR2 not enabled, selective fetch not valid and no HW tracking available\n");
+                       return false;
+               }
        }
 
-       if (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v) {
+       if (!crtc_state->enable_psr2_sel_fetch &&
+           (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v)) {
                drm_dbg_kms(&dev_priv->drm,
                            "PSR2 not enabled, resolution %dx%d > max supported %dx%d\n",
                            crtc_hdisplay, crtc_vdisplay,
@@ -898,6 +933,11 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
                val |= EXITLINE_ENABLE;
                intel_de_write(dev_priv, EXITLINE(cpu_transcoder), val);
        }
+
+       if (HAS_PSR_HW_TRACKING(dev_priv))
+               intel_de_rmw(dev_priv, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING,
+                            dev_priv->psr.psr2_sel_fetch_enabled ?
+                            IGNORE_PSR2_HW_TRACKING : 0);
 }
 
 static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
@@ -919,6 +959,7 @@ static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
        /* DC5/DC6 requires at least 6 idle frames */
        val = usecs_to_jiffies(intel_get_frame_time_us(crtc_state) * 6);
        dev_priv->psr.dc3co_exit_delay = val;
+       dev_priv->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch;
 
        /*
         * If a PSR error happened and the driver is reloaded, the EDP_PSR_IIR
@@ -1115,6 +1156,32 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv)
                intel_psr_exit(dev_priv);
 }
 
+void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct i915_psr *psr = &dev_priv->psr;
+
+       if (!HAS_PSR2_SEL_FETCH(dev_priv) ||
+           !crtc_state->enable_psr2_sel_fetch)
+               return;
+
+       intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(psr->transcoder),
+                      crtc_state->psr2_man_track_ctl);
+}
+
+void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+                                struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
+
+       if (!crtc_state->enable_psr2_sel_fetch)
+               return;
+
+       crtc_state->psr2_man_track_ctl = PSR2_MAN_TRK_CTL_ENABLE |
+                                        PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
+}
+
 /**
  * intel_psr_update - Update PSR state
  * @intel_dp: Intel DP
index b4515186d5f46cc4e4e024e2f9a734e4601db603..6a83c8e682e6dbe819782f6aec3aca0a4bac1ef7 100644 (file)
@@ -13,6 +13,8 @@ struct drm_connector_state;
 struct drm_i915_private;
 struct intel_crtc_state;
 struct intel_dp;
+struct intel_crtc;
+struct intel_atomic_state;
 
 #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
 void intel_psr_init_dpcd(struct intel_dp *intel_dp);
@@ -43,5 +45,8 @@ void intel_psr_atomic_check(struct drm_connector *connector,
                            struct drm_connector_state *old_state,
                            struct drm_connector_state *new_state);
 void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp);
+void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+                                struct intel_crtc *crtc);
+void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state);
 
 #endif /* __INTEL_PSR_H__ */
index 023eb28ea4eca588a11f76903591a47bcfd74c7f..4b5c25a018b7f578a22f8167b8d1c0864a2b3da6 100644 (file)
@@ -506,6 +506,7 @@ struct i915_psr {
        bool link_standby;
        bool colorimetry_support;
        bool psr2_enabled;
+       bool psr2_sel_fetch_enabled;
        u8 sink_sync_latency;
        ktime_t last_entry_attempt;
        ktime_t last_exit;
@@ -1699,6 +1700,7 @@ extern const struct i915_rev_steppings kbl_revids[];
 #define HAS_PSR(dev_priv)               (INTEL_INFO(dev_priv)->display.has_psr)
 #define HAS_PSR_HW_TRACKING(dev_priv) \
        (INTEL_INFO(dev_priv)->display.has_psr_hw_tracking)
+#define HAS_PSR2_SEL_FETCH(dev_priv)    (INTEL_GEN(dev_priv) >= 12)
 #define HAS_TRANSCODER(dev_priv, trans)         ((INTEL_INFO(dev_priv)->cpu_transcoder_mask & BIT(trans)) != 0)
 
 #define HAS_RC6(dev_priv)               (INTEL_INFO(dev_priv)->has_rc6)
index 8d8db9ff0a484ccc62a07270d2ce172b4ac3c2cc..7f139ea4a90b205832791269a19b95569978dc41 100644 (file)
@@ -102,6 +102,11 @@ i915_param_named(psr_safest_params, bool, 0400,
        "is helpful to detect if PSR issues are related to bad values set in "
        " VBT. (0=use VBT parameters, 1=use safest parameters)");
 
+i915_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400,
+       "Enable PSR2 selective fetch "
+       "(0=disabled, 1=enabled) "
+       "Default: 0");
+
 i915_param_named_unsafe(force_probe, charp, 0400,
        "Force probe the driver for specified devices. "
        "See CONFIG_DRM_I915_FORCE_PROBE for details.");
index 53fb5ba8fbed6bcdef15e510677ac85ffc4cb996..330c03e2b4f7051a2dae20e0912a4c930c997f1f 100644 (file)
@@ -54,6 +54,7 @@ struct drm_printer;
        param(int, enable_fbc, -1, 0600) \
        param(int, enable_psr, -1, 0600) \
        param(bool, psr_safest_params, false, 0600) \
+       param(bool, enable_psr2_sel_fetch, false, 0600) \
        param(int, disable_power_well, -1, 0400) \
        param(int, enable_ips, 1, 0600) \
        param(int, invert_brightness, 0, 0600) \