For DP2.1, ALPM (Advanced Link Power Management) is optional: Panel
Replay can be supported without ALPM. Until now ALPM enablement was
derived implicitly from other features - eDP Panel Replay and PSR2
always implied ALPM (intel_psr_needs_alpm()), while LOBF was tracked
separately via has_lobf - so this scattered, feature-coupled logic
cannot express "Panel Replay without ALPM".

Introduce a single crtc_state->has_alpm flag as the source of truth for
whether ALPM is enabled. It is set in one place, in the new
intel_alpm_compute_config_late(), once the final PSR, Panel Replay and
LOBF state is known:

 - eDP Panel Replay and PSR2 always use ALPM.
 - DP Panel Replay uses ALPM only if AUX-less ALPM is possible and its
   wake time fits, otherwise Panel Replay is used without ALPM.
 - Otherwise ALPM follows LOBF.

intel_alpm_compute_config_late() also does the late LOBF checks that
intel_alpm_lobf_compute_config_late() did before.

Use has_alpm in the ALPM configure and sink enable paths, and require
it in intel_alpm_is_aux_less() (renamed from
intel_alpm_is_alpm_aux_less()) so that AUX-less ALPM programming,
including the AS SDP part of PR_ALPM_CTL and the MAC transmit LFPS, is
skipped when ALPM is not used. Require the ALPM DPCD caps for AUX-less
ALPM on eDP as well.

v2:
- Set has_alpm in one place in intel_alpm_compute_config_late(). [Jouni]
- Don't let selective update overwrite has_alpm. [sashiko]
- Don't leave has_alpm set when PSR features are dropped late. [sashiko]
- Keep clearing the port ALPM registers when ALPM is not used. [sashiko]
- Require has_alpm for AUX-less ALPM programming. [sashiko]
- Keep ALPM enabled for PSR2 regardless of the ALPM DPCD caps.

Cc: Jouni Högander <[email protected]>
Signed-off-by: Animesh Manna <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_alpm.c     | 55 +++++++++++++------
 drivers/gpu/drm/i915/display/intel_alpm.h     |  8 +--
 drivers/gpu/drm/i915/display/intel_cx0_phy.c  |  2 +-
 .../drm/i915/display/intel_display_types.h    |  1 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  2 +-
 drivers/gpu/drm/i915/display/intel_lt_phy.c   |  2 +-
 drivers/gpu/drm/i915/display/intel_psr.c      | 11 +++-
 drivers/gpu/drm/i915/display/intel_psr.h      |  3 +-
 8 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c 
b/drivers/gpu/drm/i915/display/intel_alpm.c
index 65d06e8ebbe0..47263af0970c 100644
--- a/drivers/gpu/drm/i915/display/intel_alpm.c
+++ b/drivers/gpu/drm/i915/display/intel_alpm.c
@@ -37,11 +37,12 @@ bool intel_alpm_aux_less_wake_supported(struct intel_dp 
*intel_dp)
        return intel_dp->alpm_dpcd & DP_ALPM_AUX_LESS_CAP;
 }
 
-bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp,
-                                const struct intel_crtc_state *crtc_state)
+bool intel_alpm_is_aux_less(struct intel_dp *intel_dp,
+                           const struct intel_crtc_state *crtc_state)
 {
-       return intel_psr_needs_alpm_aux_less(intel_dp, crtc_state) ||
-               (crtc_state->has_lobf && 
intel_alpm_aux_less_wake_supported(intel_dp));
+       return crtc_state->has_alpm &&
+              (crtc_state->has_panel_replay ||
+               (crtc_state->has_lobf && 
intel_alpm_aux_less_wake_supported(intel_dp)));
 }
 
 static bool intel_alpm_source_supported(struct intel_dp *intel_dp)
@@ -509,8 +510,8 @@ static bool intel_alpm_lobf_is_window1_sufficient(struct 
intel_crtc_state *crtc_
        return window1 > crtc_state->alpm_state.check_entry_lines;
 }
 
-void intel_alpm_lobf_compute_config_late(struct intel_dp *intel_dp,
-                                        struct intel_crtc_state *crtc_state)
+static void intel_alpm_lobf_compute_config_late(struct intel_dp *intel_dp,
+                                               struct intel_crtc_state 
*crtc_state)
 {
        struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
        int waketime_in_lines, first_sdp_position;
@@ -598,14 +599,34 @@ void intel_alpm_compute_config(struct intel_dp *intel_dp,
 
        crtc_state->alpm_state.aux_wake_possible = true;
        crtc_state->alpm_state.aux_less_possible =
-               DISPLAY_VER(display) >= 20 &&
-               (intel_dp_is_edp(intel_dp) ||
-                (intel_alpm_is_possible(intel_dp, crtc_state) &&
-                 intel_alpm_aux_less_wake_supported(intel_dp)));
+               DISPLAY_VER(display) >= 20 && intel_alpm_is_possible(intel_dp, 
crtc_state) &&
+               (intel_dp_is_edp(intel_dp) || 
intel_alpm_aux_less_wake_supported(intel_dp));
 
        intel_alpm_lobf_compute_config(intel_dp, crtc_state);
 }
 
+/*
+ * Decide whether ALPM is enabled once PSR, Panel Replay and LOBF have been
+ * finalized. eDP Panel Replay and PSR2 always use ALPM, for DP Panel Replay
+ * ALPM is optional and used only if the AUX-less wake time fits.
+ */
+void intel_alpm_compute_config_late(struct intel_dp *intel_dp,
+                                   struct intel_crtc_state *crtc_state)
+{
+       int aux_less_wake_lines = crtc_state->alpm_state.aux_less_wake_lines;
+
+       intel_alpm_lobf_compute_config_late(intel_dp, crtc_state);
+
+       if (crtc_state->has_psr && crtc_state->has_panel_replay)
+               crtc_state->has_alpm = intel_dp_is_edp(intel_dp) ||
+                       (crtc_state->alpm_state.aux_less_possible &&
+                        intel_psr_wake_lines_fit_into_vblank(crtc_state, 
aux_less_wake_lines));
+       else if (crtc_state->has_psr && crtc_state->has_sel_update)
+               crtc_state->has_alpm = intel_dp_is_edp(intel_dp);
+       else
+               crtc_state->has_alpm = crtc_state->has_lobf;
+}
+
 static u32 get_pr_alpm_as_sdp_transmission_time(const struct intel_crtc_state 
*crtc_state)
 {
        u8 as_sdp_setup_time = intel_dp_as_sdp_transmission_time();
@@ -750,7 +771,7 @@ void intel_alpm_pr_as_sdp_update(const struct 
intel_crtc_state *crtc_state)
                intel_dp = enc_to_intel_dp(encoder);
 
                if (!intel_dp->as_sdp_supported ||
-                   !intel_alpm_is_alpm_aux_less(intel_dp, crtc_state))
+                   !intel_alpm_is_aux_less(intel_dp, crtc_state))
                        continue;
 
                mutex_lock(&intel_dp->alpm.lock);
@@ -767,8 +788,7 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp,
        u32 alpm_ctl, alpm_ctl2;
        int lttpr_count;
 
-       if (DISPLAY_VER(display) < 20 || (!intel_psr_needs_alpm(intel_dp, 
crtc_state) &&
-                                         !crtc_state->has_lobf))
+       if (DISPLAY_VER(display) < 20 || !crtc_state->has_alpm)
                return;
 
        mutex_lock(&intel_dp->alpm.lock);
@@ -776,7 +796,7 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp,
         * Panel Replay on eDP is always using ALPM aux less. I.e. no need to
         * check panel support at this point.
         */
-       if (intel_alpm_is_alpm_aux_less(intel_dp, crtc_state)) {
+       if (intel_alpm_is_aux_less(intel_dp, crtc_state)) {
                int wake_lines = crtc_state->alpm_state.aux_less_wake_lines;
 
                alpm_ctl = ALPM_CTL_ALPM_ENABLE |
@@ -832,7 +852,7 @@ void intel_alpm_port_configure(struct intel_dp *intel_dp,
        if (DISPLAY_VER(display) < 20)
                return;
 
-       if (intel_alpm_is_alpm_aux_less(intel_dp, crtc_state)) {
+       if (intel_alpm_is_aux_less(intel_dp, crtc_state)) {
                int lfps_cycle = get_lfps_cycle_count(crtc_state);
                u32 lfps_cycle_val;
 
@@ -888,13 +908,12 @@ void intel_alpm_enable_sink(struct intel_dp *intel_dp,
 {
        u8 val;
 
-       if (!intel_psr_needs_alpm(intel_dp, crtc_state) && 
!crtc_state->has_lobf)
+       if (!crtc_state->has_alpm)
                return;
 
        val = DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE;
 
-       if (crtc_state->has_panel_replay || (crtc_state->has_lobf &&
-                                            
intel_alpm_aux_less_wake_supported(intel_dp)))
+       if (intel_alpm_is_aux_less(intel_dp, crtc_state))
                val |= DP_ALPM_MODE_AUX_LESS;
 
        drm_dp_dpcd_write_byte(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, val);
diff --git a/drivers/gpu/drm/i915/display/intel_alpm.h 
b/drivers/gpu/drm/i915/display/intel_alpm.h
index be9b4d761c13..a35a98a55a8d 100644
--- a/drivers/gpu/drm/i915/display/intel_alpm.h
+++ b/drivers/gpu/drm/i915/display/intel_alpm.h
@@ -31,14 +31,14 @@ void intel_alpm_lobf_enable(const struct intel_crtc_state 
*new_crtc_state);
 void intel_alpm_lobf_debugfs_add(struct intel_connector *connector);
 bool intel_alpm_aux_wake_supported(struct intel_dp *intel_dp);
 bool intel_alpm_aux_less_wake_supported(struct intel_dp *intel_dp);
-bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp,
-                                const struct intel_crtc_state *crtc_state);
+bool intel_alpm_is_aux_less(struct intel_dp *intel_dp,
+                           const struct intel_crtc_state *crtc_state);
 bool intel_alpm_pr_as_sdp_skip_frames_enabled(struct intel_dp *intel_dp,
                                              const struct intel_crtc_state 
*crtc_state);
 void intel_alpm_pr_as_sdp_update(const struct intel_crtc_state *crtc_state);
 void intel_alpm_disable(struct intel_dp *intel_dp);
 bool intel_alpm_get_error(struct intel_dp *intel_dp);
-void intel_alpm_lobf_compute_config_late(struct intel_dp *intel_dp,
-                                        struct intel_crtc_state *crtc_state);
+void intel_alpm_compute_config_late(struct intel_dp *intel_dp,
+                                   struct intel_crtc_state *crtc_state);
 int intel_alpm_lobf_min_guardband(struct intel_crtc_state *crtc_state);
 #endif
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c 
b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index 814615fe9951..453526c4b3a9 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -3453,7 +3453,7 @@ void intel_lnl_mac_transmit_lfps(struct intel_encoder 
*encoder,
        u8 owned_lane_mask;
 
        if (DISPLAY_VER(display) < 20 ||
-           !intel_alpm_is_alpm_aux_less(enc_to_intel_dp(encoder), crtc_state))
+           !intel_alpm_is_aux_less(enc_to_intel_dp(encoder), crtc_state))
                return;
 
        owned_lane_mask = intel_cx0_get_owned_lane_mask(encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index ce7dc3375f2e..73d82df2ff92 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1475,6 +1475,7 @@ struct intel_crtc_state {
                bool aux_wake_possible;
                bool aux_less_possible;
        } alpm_state;
+       bool has_alpm;
 
        /* to track changes in plane color blocks */
        bool plane_color_changed;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 7827de39e826..43b17d2ed93f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -7594,7 +7594,7 @@ int intel_dp_compute_config_late(struct intel_encoder 
*encoder,
        if (ret)
                return ret;
 
-       intel_alpm_lobf_compute_config_late(intel_dp, crtc_state);
+       intel_alpm_compute_config_late(intel_dp, crtc_state);
 
        return 0;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c 
b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index 5b26957d7fb9..74ef0d29756c 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -2371,7 +2371,7 @@ void intel_lt_mac_transmit_lfps(struct intel_encoder 
*encoder,
        struct ref_tracker *wakeref;
        u8 owned_lane_mask;
 
-       if (!intel_alpm_is_alpm_aux_less(intel_dp, crtc_state))
+       if (!intel_alpm_is_aux_less(intel_dp, crtc_state))
                return;
 
        wakeref = intel_lt_phy_transaction_begin(encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c 
b/drivers/gpu/drm/i915/display/intel_psr.c
index c00ec3f64202..4c429a14b50e 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1426,6 +1426,14 @@ static bool _wake_lines_fit_into_vblank(const struct 
intel_crtc_state *crtc_stat
        return true;
 }
 
+bool intel_psr_wake_lines_fit_into_vblank(const struct intel_crtc_state 
*crtc_state,
+                                         int wake_lines)
+{
+       return _wake_lines_fit_into_vblank(crtc_state,
+                                          intel_crtc_vblank_length(crtc_state),
+                                          wake_lines);
+}
+
 static bool wake_lines_fit_into_vblank(struct intel_dp *intel_dp,
                                       const struct intel_crtc_state 
*crtc_state,
                                       bool aux_less,
@@ -4547,7 +4555,8 @@ void intel_psr_connector_debugfs_add(struct 
intel_connector *connector)
                                    connector, &i915_psr_status_fops);
 }
 
-bool intel_psr_needs_alpm(struct intel_dp *intel_dp, const struct 
intel_crtc_state *crtc_state)
+static bool intel_psr_needs_alpm(struct intel_dp *intel_dp,
+                                const struct intel_crtc_state *crtc_state)
 {
        /*
         * eDP Panel Replay uses always ALPM
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h 
b/drivers/gpu/drm/i915/display/intel_psr.h
index d545fdaa0de7..2557776a402b 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -79,9 +79,10 @@ void intel_psr_trigger_frame_change_event(struct intel_dsb 
*dsb,
 int intel_psr_min_set_context_latency(const struct intel_crtc_state 
*crtc_state);
 void intel_psr_connector_debugfs_add(struct intel_connector *connector);
 void intel_psr_debugfs_register(struct intel_display *display);
-bool intel_psr_needs_alpm(struct intel_dp *intel_dp, const struct 
intel_crtc_state *crtc_state);
 bool intel_psr_needs_alpm_aux_less(struct intel_dp *intel_dp,
                                   const struct intel_crtc_state *crtc_state);
+bool intel_psr_wake_lines_fit_into_vblank(const struct intel_crtc_state 
*crtc_state,
+                                         int wake_lines);
 void intel_psr_compute_config_late(struct intel_dp *intel_dp,
                                   struct intel_crtc_state *crtc_state);
 int intel_psr_min_guardband(struct intel_crtc_state *crtc_state);
-- 
2.43.0

Reply via email to