Thank you for your contribution! Sashiko AI review found 2 potential issue(s) 
to consider:
- [High] drm/i915/alpm: ALPM left enabled on DP Panel Replay disable or 
!has_alpm
- [Medium] drm/i915/alpm: intel_psr_min_guardband() skips DP Panel Replay ALPM 
wake lines
--

commit 599e7704f4924a7a5dd73754cb1a7ffd13dae956
Author: Animesh Manna <[email protected]>

drm/i915/alpm: Introduce has_alpm to decouple from pr/psr2/lobf

This patch introduces crtc_state->has_alpm in intel_alpm_compute_config_late()
to decouple ALPM enablement from Panel Replay, PSR2, and LOBF so that DP 2.1
Panel Replay can operate with or without ALPM.

> diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c 
> b/drivers/gpu/drm/i915/display/intel_alpm.c
> index 65d06e8ebbe06..47263af0970cf 100644
> --- a/drivers/gpu/drm/i915/display/intel_alpm.c
> +++ b/drivers/gpu/drm/i915/display/intel_alpm.c
[ ... ]
> @@ -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));

[Severity: Medium]
Can intel_psr_wake_lines_fit_into_vblank() fail to enable crtc_state->has_alpm
on external DP Panel Replay because intel_psr_min_guardband() does not reserve
aux_less_wake_lines for non-eDP outputs?

On DISPLAY_VER(display) >= 35, intel_vrr_always_use_vrr_tg() and
intel_vrr_use_optimized_guardband() are used, so before
intel_dp_compute_config_late() -> intel_alpm_compute_config_late() runs,
intel_crtc_compute_config() -> intel_vrr_compute_guardband() ->
intel_vrr_compute_optimized_guardband() computes crtc_state->vrr.guardband and
adjusts crtc_vblank_start:

drivers/gpu/drm/i915/display/intel_vrr.c:intel_vrr_compute_optimized_guardband()
 {
        ...
        if (intel_crtc_has_dp_encoder(crtc_state)) {
                guardband = max(guardband, intel_psr_min_guardband(crtc_state));
                guardband = max(guardband, 
intel_dp_sdp_min_guardband(crtc_state, true));
                guardband = max(guardband, 
intel_alpm_lobf_min_guardband(crtc_state));
        }
        ...
}

drivers/gpu/drm/i915/display/intel_vrr.c:intel_vrr_compute_guardband() {
        ...
        if (intel_vrr_always_use_vrr_tg(display)) {
                adjusted_mode->crtc_vblank_start  =
                        adjusted_mode->crtc_vtotal - crtc_state->vrr.guardband;
        ...
}

However, intel_psr_min_guardband() in drivers/gpu/drm/i915/display/intel_psr.c
currently skips non-eDP encoders:

drivers/gpu/drm/i915/display/intel_psr.c:intel_psr_min_guardband() {
        ...
        if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
                return 0;

        if (crtc_state->has_panel_replay)
                wake_lines = crtc_state->alpm_state.aux_less_wake_lines;
        ...
}

When crtc_state->has_lobf is false (for example, when 
!intel_dp->as_sdp_supported,
intel_dp->alpm.lobf_disable_debug is set, or intel_dp->alpm.sink_alpm_error is
set), intel_alpm_lobf_min_guardband() also returns 0. That shrinks
crtc_state->vrr.guardband (and therefore intel_crtc_vblank_length(crtc_state))
to the prefill/SDP guardband, which can be smaller than aux_less_wake_lines
even when the mode's full vblank is large enough.

Should intel_psr_min_guardband() also reserve aux_less_wake_lines for external
DP Panel Replay when crtc_state->alpm_state.aux_less_possible is true?

> +     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;
> +}
[ ... ]
> @@ -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;
[ ... ]
> @@ -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);

[Severity: High]
With crtc_state->has_alpm now enabling ALPM in lnl_alpm_configure() and
intel_alpm_enable_sink() for non-eDP Panel Replay, can ALPM remain enabled on
both the source and sink when DP Panel Replay is later disabled or reconfigured
to !crtc_state->has_alpm?

In drivers/gpu/drm/i915/display/intel_psr.c, intel_psr_disable_locked() still
guards intel_alpm_disable() with intel_dp_is_edp() and only clears
DP_RECEIVER_ALPM_CONFIG when !intel_dp->psr.panel_replay_enabled:

drivers/gpu/drm/i915/display/intel_psr.c:intel_psr_disable_locked() {
        ...
        if (intel_dp->psr.panel_replay_enabled && intel_dp_is_edp(intel_dp))
                intel_alpm_disable(intel_dp);

        /* Disable PSR on Sink */
        if (!intel_dp->psr.panel_replay_enabled) {
                drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PSR_EN_CFG, 0);

                if (intel_dp->psr.sel_update_enabled)
                        drm_dp_dpcd_write_byte(&intel_dp->aux,
                                               DP_RECEIVER_ALPM_CONFIG, 0);
        }
}

When external DP Panel Replay (!intel_dp_is_edp(intel_dp)) with ALPM is
disabled without a full encoder disable (such as in
intel_psr_pre_plane_update() when all planes become inactive, during fastsets,
or on a sink error in intel_psr_short_pulse()), intel_alpm_disable() is skipped
and ALPM_CTL_ALPM_ENABLE stays set in ALPM_CTL. Subsequent re-enables in
intel_psr_post_plane_update() -> intel_psr_enable_locked() ->
intel_psr_enable_source() -> intel_alpm_configure() -> lnl_alpm_configure()
then rewrite ALPM_CTL, ALPM_CTL2, and PR_ALPM_CTL while ALPM is still enabled
in hardware.

Furthermore, because neither intel_psr_disable_locked() nor
intel_alpm_enable_sink() clears DP_RECEIVER_ALPM_CONFIG for Panel Replay when
transitioning to !crtc_state->has_alpm, won't DP_RECEIVER_ALPM_CONFIG remain
enabled on the sink (and ALPM_CTL remain enabled on the source across a
fastset) if a subsequent commit runs Panel Replay without ALPM?

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=19

Reply via email to