Files
omarchy-pkgs/pkgbuilds/linux-omarchy/0401-drm-i915-psr-exit-panel-replay-for-alpm-lag.patch
T

197 lines
7.1 KiB
Diff

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index c21e0c0ef0b1..e62788328bfd 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1780,6 +1780,7 @@ struct intel_psr {
u32 dc3co_exitline;
u32 dc3co_exit_delay;
struct delayed_work dc3co_work;
+ struct delayed_work panel_replay_reenable_work;
u8 entry_setup_frames;
u8 io_wake_lines;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index beaa1d62613d..644ab9b1bee9 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -2475,6 +2475,7 @@ void intel_psr_disable(struct intel_dp *intel_dp,
mutex_unlock(&intel_dp->psr.lock);
cancel_work_sync(&intel_dp->psr.work);
cancel_delayed_work_sync(&intel_dp->psr.dc3co_work);
+ cancel_delayed_work_sync(&intel_dp->psr.panel_replay_reenable_work);
}
/**
@@ -2506,6 +2507,7 @@ void intel_psr_pause(struct intel_dp *intel_dp)
cancel_work_sync(&psr->work);
cancel_delayed_work_sync(&psr->dc3co_work);
+ cancel_delayed_work_sync(&psr->panel_replay_reenable_work);
}
/**
@@ -3539,6 +3541,17 @@ static void intel_psr_handle_irq(struct intel_dp *intel_dp)
drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
}
+#define PANEL_REPLAY_REENABLE_DELAY_MS 50
+
+static bool panel_replay_alpm_cursor_lag_workaround_enabled(struct intel_dp *intel_dp)
+{
+ return intel_dp_is_edp(intel_dp) &&
+ intel_dp->psr.panel_replay_enabled &&
+ intel_dp->psr.sel_update_enabled &&
+ intel_has_dpcd_quirk(intel_dp,
+ QUIRK_PANEL_REPLAY_ALPM_CURSOR_LAG);
+}
+
static void intel_psr_work(struct work_struct *work)
{
struct intel_dp *intel_dp =
@@ -3557,6 +3570,11 @@ static void intel_psr_work(struct work_struct *work)
if (intel_dp->psr.pause_counter)
goto unlock;
+ /* The dedicated delayed work owns re-entry while the workaround is armed. */
+ if (panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp) &&
+ delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work))
+ goto unlock;
+
/*
* We have to make sure PSR is ready for re-enable
* otherwise it keeps disabled until next full enable/disable cycle.
@@ -3566,6 +3584,10 @@ static void intel_psr_work(struct work_struct *work)
if (!__psr_wait_for_idle_locked(intel_dp))
goto unlock;
+ if (panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp) &&
+ delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work))
+ 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
@@ -3579,6 +3601,33 @@ static void intel_psr_work(struct work_struct *work)
mutex_unlock(&intel_dp->psr.lock);
}
+static void panel_replay_reenable_work(struct work_struct *work)
+{
+ struct intel_dp *intel_dp =
+ container_of(work, typeof(*intel_dp),
+ psr.panel_replay_reenable_work.work);
+
+ mutex_lock(&intel_dp->psr.lock);
+
+ if (!intel_dp->psr.enabled ||
+ !panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp) ||
+ intel_dp->psr.pause_counter ||
+ READ_ONCE(intel_dp->psr.irq_aux_error))
+ goto unlock;
+
+ if (!__psr_wait_for_idle_locked(intel_dp))
+ goto unlock;
+
+ /* Recheck for activity or a newer deadline after the unlocked wait. */
+ if (delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work) ||
+ intel_dp->psr.busy_frontbuffer_bits || intel_dp->psr.active)
+ goto unlock;
+
+ intel_psr_activate(intel_dp);
+unlock:
+ mutex_unlock(&intel_dp->psr.lock);
+}
+
static void intel_psr_configure_full_frame_update(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
@@ -3650,8 +3699,11 @@ void intel_psr_invalidate(struct intel_display *display,
INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe);
intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits;
- if (pipe_frontbuffer_bits)
+ if (pipe_frontbuffer_bits) {
+ if (panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp))
+ cancel_delayed_work(&intel_dp->psr.panel_replay_reenable_work);
_psr_invalidate_handle(intel_dp);
+ }
mutex_unlock(&intel_dp->psr.lock);
}
@@ -3767,6 +3819,15 @@ void intel_psr_flush(struct intel_display *display,
if (intel_dp->psr.pause_counter)
goto unlock;
+ if (pipe_frontbuffer_bits &&
+ panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp)) {
+ intel_psr_exit(intel_dp);
+ mod_delayed_work(display->wq.unordered,
+ &intel_dp->psr.panel_replay_reenable_work,
+ msecs_to_jiffies(PANEL_REPLAY_REENABLE_DELAY_MS));
+ goto unlock;
+ }
+
if (origin == ORIGIN_FLIP ||
(origin == ORIGIN_CURSOR_UPDATE &&
!intel_dp->psr.psr2_sel_fetch_enabled)) {
@@ -3830,6 +3891,8 @@ void intel_psr_init(struct intel_dp *intel_dp)
INIT_WORK(&intel_dp->psr.work, intel_psr_work);
INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, tgl_dc3co_disable_work);
+ INIT_DELAYED_WORK(&intel_dp->psr.panel_replay_reenable_work,
+ panel_replay_reenable_work);
mutex_init(&intel_dp->psr.lock);
}
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
index 33245f44c0d5..dc6576016400 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -86,12 +86,13 @@ static void quirk_edp_limit_rate_hbr2(struct intel_display *display)
drm_info(display->drm, "Applying eDP Limit rate to HBR2 quirk\n");
}
-static void quirk_disable_edp_panel_replay(struct intel_dp *intel_dp)
+static void quirk_panel_replay_alpm_cursor_lag(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_set_dpcd_quirk(intel_dp, QUIRK_DISABLE_EDP_PANEL_REPLAY);
- drm_info(display->drm, "Applying disable Panel Replay quirk\n");
+ intel_set_dpcd_quirk(intel_dp, QUIRK_PANEL_REPLAY_ALPM_CURSOR_LAG);
+ drm_info(display->drm,
+ "Applying Panel Replay ALPM cursor lag workaround\n");
}
static void quirk_disable_psr2(struct intel_display *display)
@@ -276,7 +277,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.subsystem_vendor = 0x1028,
.subsystem_device = 0x0db9,
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
- .hook = quirk_disable_edp_panel_replay,
+ .hook = quirk_panel_replay_alpm_cursor_lag,
},
/* Dell XPS 16 DA16260 */
{
@@ -284,7 +285,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.subsystem_vendor = 0x1028,
.subsystem_device = 0x0dba,
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
- .hook = quirk_disable_edp_panel_replay,
+ .hook = quirk_panel_replay_alpm_cursor_lag,
},
};
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h
index 970a4fe52faf..50ef333b87a9 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.h
+++ b/drivers/gpu/drm/i915/display/intel_quirks.h
@@ -23,6 +23,7 @@ enum intel_quirk_id {
QUIRK_EDP_LIMIT_RATE_HBR2,
QUIRK_DISABLE_EDP_PANEL_REPLAY,
QUIRK_DISABLE_PSR2,
+ QUIRK_PANEL_REPLAY_ALPM_CURSOR_LAG,
};
void intel_init_quirks(struct intel_display *display);