diff mbox series

[2/2] drm/atomic: Force bridge self-refresh-exit on CRTC switch

Message ID 20220215155417.2.Ic15a2ef69c540aee8732703103e2cff51fb9c399@changeid (mailing list archive)
State New, archived
Headers show
Series drm/bridge: analogix_dp: Self-refresh state machine fixes | expand

Commit Message

Brian Norris Feb. 15, 2022, 11:54 p.m. UTC
It's possible to change which CRTC is in use for a given
connector/encoder/bridge while we're in self-refresh without fully
disabling the connector/encoder/bridge along the way. This can confuse
the bridge encoder/bridge, because
(a) it needs to track the SR state (trying to perform "active"
    operations while the panel is still in SR can be Bad(TM)); and
(b) it tracks the SR state via the CRTC state (and after the switch, the
    previous SR state is lost).

Thus, we need to either somehow carry the self-refresh state over to the
new CRTC, or else force an encoder/bridge self-refresh transition during
such a switch.

I choose the latter, so we disable the encoder (and exit PSR) before
attaching it to the new CRTC (where we can continue to assume a clean
(non-self-refresh) state).

This fixes PSR issues seen on Rockchip RK3399 systems with
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c.

Cc: <stable@vger.kernel.org>
Fixes: 1452c25b0e60 ("drm: Add helpers to kick off self refresh mode in drivers")
Signed-off-by: Brian Norris <briannorris@chromium.org>
---

 drivers/gpu/drm/drm_atomic_helper.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

Comments

Liu Ying Feb. 28, 2022, 9:02 a.m. UTC | #1
Hi Brian,

On Tue, 2022-02-15 at 15:54 -0800, Brian Norris wrote:
> It's possible to change which CRTC is in use for a given
> connector/encoder/bridge while we're in self-refresh without fully
> disabling the connector/encoder/bridge along the way. This can confuse
> the bridge encoder/bridge, because
> (a) it needs to track the SR state (trying to perform "active"
>     operations while the panel is still in SR can be Bad(TM)); and
> (b) it tracks the SR state via the CRTC state (and after the switch, the
>     previous SR state is lost).
> 
> Thus, we need to either somehow carry the self-refresh state over to the
> new CRTC, or else force an encoder/bridge self-refresh transition during
> such a switch.
> 
> I choose the latter, so we disable the encoder (and exit PSR) before
> attaching it to the new CRTC (where we can continue to assume a clean
> (non-self-refresh) state).
> 
> This fixes PSR issues seen on Rockchip RK3399 systems with
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c.
> 
> Cc: <stable@vger.kernel.org>
> Fixes: 1452c25b0e60 ("drm: Add helpers to kick off self refresh mode in drivers")
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> ---
> 
>  drivers/gpu/drm/drm_atomic_helper.c | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 9603193d2fa1..74161d007894 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1011,9 +1011,19 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
>  		return drm_atomic_crtc_effectively_active(old_state);
>  
>  	/*
> -	 * We need to run through the crtc_funcs->disable() function if the CRTC
> -	 * is currently on, if it's transitioning to self refresh mode, or if
> -	 * it's in self refresh mode and needs to be fully disabled.
> +	 * We need to disable bridge(s) and CRTC if we're transitioning out of
> +	 * self-refresh and changing CRTCs at the same time, because the
> +	 * bridge tracks self-refresh status via CRTC state.
> +	 */
> +	if (old_state->self_refresh_active && new_state->enable &&
> +	    old_state->crtc != new_state->crtc)
> +		return true;

I think 'new_state->enable' should be changed to 'new_state->active',
because 'active' is the one to enable/disable the CRTC while 'enable'
reflects whether a mode blob is set to CRTC state.  The overall logic
added above is ok to me. Let's see if others have any comments.

Regards,
Liu Ying

> +
> +	/*
> +	 * We also need to run through the crtc_funcs->disable() function if
> +	 * the CRTC is currently on, if it's transitioning to self refresh
> +	 * mode, or if it's in self refresh mode and needs to be fully
> +	 * disabled.
>  	 */
>  	return old_state->active ||
>  	       (old_state->self_refresh_active && !new_state->active) ||
Brian Norris Feb. 28, 2022, 7:59 p.m. UTC | #2
Hi Liu,

On Mon, Feb 28, 2022 at 1:02 AM Liu Ying <victor.liu@oss.nxp.com> wrote:
> On Tue, 2022-02-15 at 15:54 -0800, Brian Norris wrote:
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -1011,9 +1011,19 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
> >               return drm_atomic_crtc_effectively_active(old_state);
> >
> >       /*
> > -      * We need to run through the crtc_funcs->disable() function if the CRTC
> > -      * is currently on, if it's transitioning to self refresh mode, or if
> > -      * it's in self refresh mode and needs to be fully disabled.
> > +      * We need to disable bridge(s) and CRTC if we're transitioning out of
> > +      * self-refresh and changing CRTCs at the same time, because the
> > +      * bridge tracks self-refresh status via CRTC state.
> > +      */
> > +     if (old_state->self_refresh_active && new_state->enable &&
> > +         old_state->crtc != new_state->crtc)
> > +             return true;
>
> I think 'new_state->enable' should be changed to 'new_state->active',
> because 'active' is the one to enable/disable the CRTC while 'enable'
> reflects whether a mode blob is set to CRTC state.  The overall logic
> added above is ok to me. Let's see if others have any comments.

Thanks for the review, and good catch. This actually shows that most
of my development was before commit 69e630016ef4 ("drm/atomic: Check
new_crtc_state->active to determine if CRTC needs disable in self
refresh mode"). In fact, the "state->enable" condition was included
here mostly as a complement to the "!state->enable" condition that was
present previously, and I didn't adapt it properly upon rebase.

In practice, this portion of the condition is not needed at all; we
really want to exit PSR on CRTC-switch regardless of the new-CRTC
state. So rather than change "enable" to "active", I plan to remove it
entirely.

I'll give it some local tests and send v2 eventually.

Thanks,
Brian
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 9603193d2fa1..74161d007894 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1011,9 +1011,19 @@  crtc_needs_disable(struct drm_crtc_state *old_state,
 		return drm_atomic_crtc_effectively_active(old_state);
 
 	/*
-	 * We need to run through the crtc_funcs->disable() function if the CRTC
-	 * is currently on, if it's transitioning to self refresh mode, or if
-	 * it's in self refresh mode and needs to be fully disabled.
+	 * We need to disable bridge(s) and CRTC if we're transitioning out of
+	 * self-refresh and changing CRTCs at the same time, because the
+	 * bridge tracks self-refresh status via CRTC state.
+	 */
+	if (old_state->self_refresh_active && new_state->enable &&
+	    old_state->crtc != new_state->crtc)
+		return true;
+
+	/*
+	 * We also need to run through the crtc_funcs->disable() function if
+	 * the CRTC is currently on, if it's transitioning to self refresh
+	 * mode, or if it's in self refresh mode and needs to be fully
+	 * disabled.
 	 */
 	return old_state->active ||
 	       (old_state->self_refresh_active && !new_state->active) ||