Ivan T. Ivanov f23bc5
From: Maxime Ripard <maxime@cerno.tech>
Ivan T. Ivanov f23bc5
Date: Fri, 7 May 2021 17:05:08 +0200
Ivan T. Ivanov f23bc5
Subject: drm/vc4: crtc: Lookup the encoder from the register at boot
Ivan T. Ivanov f23bc5
Git-commit: b601c16b7ba8f3bb7a7e773b238da6b63657fa1d
Ivan T. Ivanov f23bc5
Patch-mainline: v5.14-rc1
Ivan T. Ivanov f23bc5
References: bsc#1198534
Ivan T. Ivanov f23bc5
Ivan T. Ivanov f23bc5
At boot, we can't rely on the vc4_get_crtc_encoder since we don't have a
Ivan T. Ivanov f23bc5
state yet and thus will not be able to figure out which connector is
Ivan T. Ivanov f23bc5
attached to our CRTC.
Ivan T. Ivanov f23bc5
Ivan T. Ivanov f23bc5
However, we have a muxing bit in the CRTC register we can use to get the
Ivan T. Ivanov f23bc5
encoder currently connected to the pixelvalve. We can thus read that
Ivan T. Ivanov f23bc5
register, lookup the associated register through the vc4_pv_data
Ivan T. Ivanov f23bc5
structure, and then pass it to vc4_crtc_disable so that we can perform
Ivan T. Ivanov f23bc5
the proper operations.
Ivan T. Ivanov f23bc5
Ivan T. Ivanov f23bc5
Fixes: 875a4d536842 ("drm/vc4: drv: Disable the CRTC at boot time")
Ivan T. Ivanov f23bc5
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Ivan T. Ivanov f23bc5
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Ivan T. Ivanov f23bc5
Link: https://patchwork.freedesktop.org/patch/msgid/20210507150515.257424-6-maxime@cerno.tech
Ivan T. Ivanov f23bc5
[iivanov: adapted on top of SLE15-SP3]
Ivan T. Ivanov f23bc5
Acked-by: Ivan T. Ivanov <iivanov@suse.de>
Ivan T. Ivanov f23bc5
---
Ivan T. Ivanov f23bc5
 drivers/gpu/drm/vc4/vc4_crtc.c |   39 +++++++++++++++++++++++++++++++++++----
Ivan T. Ivanov f23bc5
 1 file changed, 35 insertions(+), 4 deletions(-)
Ivan T. Ivanov f23bc5
Ivan T. Ivanov f23bc5
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
Ivan T. Ivanov f23bc5
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
Ivan T. Ivanov f23bc5
@@ -420,9 +420,10 @@ static void require_hvs_enabled(struct d
Ivan T. Ivanov f23bc5
 		     SCALER_DISPCTRL_ENABLE);
Ivan T. Ivanov f23bc5
 }
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
-static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel)
Ivan T. Ivanov f23bc5
+static int vc4_crtc_disable(struct drm_crtc *crtc,
Ivan T. Ivanov f23bc5
+			    struct drm_encoder *encoder,
Ivan T. Ivanov f23bc5
+			    unsigned int channel)
Ivan T. Ivanov f23bc5
 {
Ivan T. Ivanov f23bc5
-	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
Ivan T. Ivanov f23bc5
 	struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
Ivan T. Ivanov f23bc5
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
Ivan T. Ivanov f23bc5
 	struct drm_device *dev = crtc->dev;
Ivan T. Ivanov f23bc5
@@ -463,10 +464,29 @@ static int vc4_crtc_disable(struct drm_c
Ivan T. Ivanov f23bc5
 	return 0;
Ivan T. Ivanov f23bc5
 }
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
+static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
Ivan T. Ivanov f23bc5
+							enum vc4_encoder_type type)
Ivan T. Ivanov f23bc5
+{
Ivan T. Ivanov f23bc5
+	struct drm_encoder *encoder;
Ivan T. Ivanov f23bc5
+
Ivan T. Ivanov f23bc5
+	drm_for_each_encoder(encoder, crtc->dev) {
Ivan T. Ivanov f23bc5
+		struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
Ivan T. Ivanov f23bc5
+
Ivan T. Ivanov f23bc5
+		if (vc4_encoder->type == type)
Ivan T. Ivanov f23bc5
+			return encoder;
Ivan T. Ivanov f23bc5
+	}
Ivan T. Ivanov f23bc5
+
Ivan T. Ivanov f23bc5
+	return NULL;
Ivan T. Ivanov f23bc5
+}
Ivan T. Ivanov f23bc5
+
Ivan T. Ivanov f23bc5
 int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
Ivan T. Ivanov f23bc5
 {
Ivan T. Ivanov f23bc5
 	struct drm_device *drm = crtc->dev;
Ivan T. Ivanov f23bc5
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
Ivan T. Ivanov f23bc5
+	enum vc4_encoder_type encoder_type;
Ivan T. Ivanov f23bc5
+	const struct vc4_pv_data *pv_data;
Ivan T. Ivanov f23bc5
+	struct drm_encoder *encoder;
Ivan T. Ivanov f23bc5
+	unsigned encoder_sel;
Ivan T. Ivanov f23bc5
 	int channel;
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
 	if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
Ivan T. Ivanov f23bc5
@@ -485,13 +505,24 @@ int vc4_crtc_disable_at_boot(struct drm_
Ivan T. Ivanov f23bc5
 	if (channel < 0)
Ivan T. Ivanov f23bc5
 		return 0;
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
-	return vc4_crtc_disable(crtc, channel);
Ivan T. Ivanov f23bc5
+	encoder_sel = VC4_GET_FIELD(CRTC_READ(PV_CONTROL), PV_CONTROL_CLK_SELECT);
Ivan T. Ivanov f23bc5
+	if (WARN_ON(encoder_sel != 0))
Ivan T. Ivanov f23bc5
+		return 0;
Ivan T. Ivanov f23bc5
+
Ivan T. Ivanov f23bc5
+	pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
Ivan T. Ivanov f23bc5
+	encoder_type = pv_data->encoder_types[encoder_sel];
Ivan T. Ivanov f23bc5
+	encoder = vc4_crtc_get_encoder_by_type(crtc, encoder_type);
Ivan T. Ivanov f23bc5
+	if (WARN_ON(!encoder))
Ivan T. Ivanov f23bc5
+		return 0;
Ivan T. Ivanov f23bc5
+
Ivan T. Ivanov f23bc5
+	return vc4_crtc_disable(crtc, encoder, channel);
Ivan T. Ivanov f23bc5
 }
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
 static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
Ivan T. Ivanov f23bc5
 				    struct drm_crtc_state *old_state)
Ivan T. Ivanov f23bc5
 {
Ivan T. Ivanov f23bc5
 	struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
Ivan T. Ivanov f23bc5
+	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
Ivan T. Ivanov f23bc5
 	struct drm_device *dev = crtc->dev;
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
 	require_hvs_enabled(dev);
Ivan T. Ivanov f23bc5
@@ -499,7 +530,7 @@ static void vc4_crtc_atomic_disable(stru
Ivan T. Ivanov f23bc5
 	/* Disable vblank irq handling before crtc is disabled. */
Ivan T. Ivanov f23bc5
 	drm_crtc_vblank_off(crtc);
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
-	vc4_crtc_disable(crtc, old_vc4_state->assigned_channel);
Ivan T. Ivanov f23bc5
+	vc4_crtc_disable(crtc, encoder, old_vc4_state->assigned_channel);
Ivan T. Ivanov f23bc5
 
Ivan T. Ivanov f23bc5
 	/*
Ivan T. Ivanov f23bc5
 	 * Make sure we issue a vblank event after disabling the CRTC if