Takashi Iwai 429927
From ca871659ec1606d33b1e76de8d4cf924cf627e34 Mon Sep 17 00:00:00 2001
Takashi Iwai 429927
From: Brian Norris <briannorris@chromium.org>
Takashi Iwai 429927
Date: Mon, 28 Feb 2022 12:25:31 -0800
Takashi Iwai 429927
Subject: [PATCH] drm/bridge: analogix_dp: Support PSR-exit to disable transition
Takashi Iwai 429927
Git-commit: ca871659ec1606d33b1e76de8d4cf924cf627e34
Takashi Iwai 429927
Patch-mainline: v5.19-rc2
Takashi Iwai 429927
References: git-fixes
Takashi Iwai 429927
Takashi Iwai 429927
Most eDP panel functions only work correctly when the panel is not in
Takashi Iwai 429927
self-refresh. In particular, analogix_dp_bridge_disable() tends to hit
Takashi Iwai 429927
AUX channel errors if the panel is in self-refresh.
Takashi Iwai 429927
Takashi Iwai 429927
Given the above, it appears that so far, this driver assumes that we are
Takashi Iwai 429927
never in self-refresh when it comes time to fully disable the bridge.
Takashi Iwai 429927
Prior to commit 846c7dfc1193 ("drm/atomic: Try to preserve the crtc
Takashi Iwai 429927
enabled state in drm_atomic_remove_fb, v2."), this tended to be true,
Takashi Iwai 429927
because we would automatically disable the pipe when framebuffers were
Takashi Iwai 429927
removed, and so we'd typically disable the bridge shortly after the last
Takashi Iwai 429927
display activity.
Takashi Iwai 429927
Takashi Iwai 429927
However, that is not guaranteed: an idle (self-refresh) display pipe may
Takashi Iwai 429927
be disabled, e.g., when switching CRTCs. We need to exit PSR first.
Takashi Iwai 429927
Takashi Iwai 429927
Stable notes: this is definitely a bugfix, and the bug has likely
Takashi Iwai 429927
existed in some form for quite a while. It may predate the "PSR helpers"
Takashi Iwai 429927
refactor, but the code looked very different before that, and it's
Takashi Iwai 429927
probably not worth rewriting the fix.
Takashi Iwai 429927
Takashi Iwai 429927
Cc: <stable@vger.kernel.org>
Takashi Iwai 429927
Fixes: 6c836d965bad ("drm/rockchip: Use the helpers for PSR")
Takashi Iwai 429927
Signed-off-by: Brian Norris <briannorris@chromium.org>
Takashi Iwai 429927
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Takashi Iwai 429927
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Takashi Iwai 429927
Link: https://patchwork.freedesktop.org/patch/msgid/20220228122522.v2.1.I161904be17ba14526f78536ccd78b85818449b51@changeid
Takashi Iwai 429927
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 429927
Takashi Iwai 429927
---
Takashi Iwai 429927
 .../drm/bridge/analogix/analogix_dp_core.c    | 42 +++++++++++++++++--
Takashi Iwai 429927
 1 file changed, 38 insertions(+), 4 deletions(-)
Takashi Iwai 429927
Takashi Iwai 429927
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
Takashi Iwai 429927
index eb590fb8e8d0..0300f670a4fd 100644
Takashi Iwai 429927
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
Takashi Iwai 429927
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
Takashi Iwai 429927
@@ -1268,6 +1268,25 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
Takashi Iwai 429927
 	return 0;
Takashi Iwai 429927
 }
Takashi Iwai 429927
 
Takashi Iwai 429927
+static
Takashi Iwai 429927
+struct drm_crtc *analogix_dp_get_old_crtc(struct analogix_dp_device *dp,
Takashi Iwai 429927
+					  struct drm_atomic_state *state)
Takashi Iwai 429927
+{
Takashi Iwai 429927
+	struct drm_encoder *encoder = dp->encoder;
Takashi Iwai 429927
+	struct drm_connector *connector;
Takashi Iwai 429927
+	struct drm_connector_state *conn_state;
Takashi Iwai 429927
+
Takashi Iwai 429927
+	connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
Takashi Iwai 429927
+	if (!connector)
Takashi Iwai 429927
+		return NULL;
Takashi Iwai 429927
+
Takashi Iwai 429927
+	conn_state = drm_atomic_get_old_connector_state(state, connector);
Takashi Iwai 429927
+	if (!conn_state)
Takashi Iwai 429927
+		return NULL;
Takashi Iwai 429927
+
Takashi Iwai 429927
+	return conn_state->crtc;
Takashi Iwai 429927
+}
Takashi Iwai 429927
+
Takashi Iwai 429927
 static
Takashi Iwai 429927
 struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
Takashi Iwai 429927
 					  struct drm_atomic_state *state)
Takashi Iwai 429927
@@ -1448,14 +1467,16 @@ analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
Takashi Iwai 429927
 {
Takashi Iwai 429927
 	struct drm_atomic_state *old_state = old_bridge_state->base.state;
Takashi Iwai 429927
 	struct analogix_dp_device *dp = bridge->driver_private;
Takashi Iwai 429927
-	struct drm_crtc *crtc;
Takashi Iwai 429927
+	struct drm_crtc *old_crtc, *new_crtc;
Takashi Iwai 429927
+	struct drm_crtc_state *old_crtc_state = NULL;
Takashi Iwai 429927
 	struct drm_crtc_state *new_crtc_state = NULL;
Takashi Iwai 429927
+	int ret;
Takashi Iwai 429927
 
Takashi Iwai 429927
-	crtc = analogix_dp_get_new_crtc(dp, old_state);
Takashi Iwai 429927
-	if (!crtc)
Takashi Iwai 429927
+	new_crtc = analogix_dp_get_new_crtc(dp, old_state);
Takashi Iwai 429927
+	if (!new_crtc)
Takashi Iwai 429927
 		goto out;
Takashi Iwai 429927
 
Takashi Iwai 429927
-	new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
Takashi Iwai 429927
+	new_crtc_state = drm_atomic_get_new_crtc_state(old_state, new_crtc);
Takashi Iwai 429927
 	if (!new_crtc_state)
Takashi Iwai 429927
 		goto out;
Takashi Iwai 429927
 
Takashi Iwai 429927
@@ -1464,6 +1485,19 @@ analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
Takashi Iwai 429927
 		return;
Takashi Iwai 429927
 
Takashi Iwai 429927
 out:
Takashi Iwai 429927
+	old_crtc = analogix_dp_get_old_crtc(dp, old_state);
Takashi Iwai 429927
+	if (old_crtc) {
Takashi Iwai 429927
+		old_crtc_state = drm_atomic_get_old_crtc_state(old_state,
Takashi Iwai 429927
+							       old_crtc);
Takashi Iwai 429927
+
Takashi Iwai 429927
+		/* When moving from PSR to fully disabled, exit PSR first. */
Takashi Iwai 429927
+		if (old_crtc_state && old_crtc_state->self_refresh_active) {
Takashi Iwai 429927
+			ret = analogix_dp_disable_psr(dp);
Takashi Iwai 429927
+			if (ret)
Takashi Iwai 429927
+				DRM_ERROR("Failed to disable psr (%d)\n", ret);
Takashi Iwai 429927
+		}
Takashi Iwai 429927
+	}
Takashi Iwai 429927
+
Takashi Iwai 429927
 	analogix_dp_bridge_disable(bridge);
Takashi Iwai 429927
 }
Takashi Iwai 429927
 
Takashi Iwai 429927
-- 
Takashi Iwai 429927
2.35.3
Takashi Iwai 429927