Message ID | 20220228122522.v2.2.Ic15a2ef69c540aee8732703103e2cff51fb9c399@changeid (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/bridge: analogix_dp: Self-refresh state machine fixes | expand |
On Mon, 2022-02-28 at 12:25 -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. > > Change in v2: > > - Drop "->enable" condition; this could possibly be "->active" to > reflect the intended hardware state, but it also is a little > over-specific. We want to make a transition through "disabled" any > time we're exiting PSR at the same time as a CRTC switch. Cool. I don't see any particular issue regarding the drop. Liu Ying > (Thanks Liu Ying) > > Cc: Liu Ying <victor.liu@oss.nxp.com> > 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..987e4b212e9f 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 && > + 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) ||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 9603193d2fa1..987e4b212e9f 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 && + 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) ||
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. Change in v2: - Drop "->enable" condition; this could possibly be "->active" to reflect the intended hardware state, but it also is a little over-specific. We want to make a transition through "disabled" any time we're exiting PSR at the same time as a CRTC switch. (Thanks Liu Ying) Cc: Liu Ying <victor.liu@oss.nxp.com> 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(-)