@@ -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)
@@ -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:
@@ -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 {
@@ -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
@@ -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__ */
@@ -501,6 +501,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;
@@ -1669,6 +1670,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#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)
@@ -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.");
@@ -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) \