60fd626
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
60fd626
From: Lyude Paul <lyude@redhat.com>
60fd626
Date: Mon, 11 May 2020 18:41:27 -0400
60fd626
Subject: [PATCH] kms/nv50-: Share DP SST mode_valid() handling with MST
60fd626
60fd626
Currently, the nv50_mstc_mode_valid() function is happy to take any and
60fd626
all modes, even the ones we can't actually support sometimes like
60fd626
interlaced modes.
60fd626
60fd626
Luckily, the only difference between the mode validation that needs to
60fd626
be performed for MST vs. SST is that eventually we'll need to check the
60fd626
minimum PBN against the MSTB's full PBN capabilities (remember-we don't
60fd626
care about the current bw state here). Otherwise, all of the other code
60fd626
can be shared.
60fd626
60fd626
So, we move all of the common mode validation in
60fd626
nouveau_connector_mode_valid() into a separate helper,
60fd626
nv50_dp_mode_valid(), and use that from both nv50_mstc_mode_valid() and
60fd626
nouveau_connector_mode_valid(). Note that we allow for returning the
60fd626
calculated clock that nv50_dp_mode_valid() came up with, since we'll
60fd626
eventually want to use that for PBN calculation in
60fd626
nv50_mstc_mode_valid().
60fd626
60fd626
Signed-off-by: Lyude Paul <lyude@redhat.com>
60fd626
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
60fd626
---
60fd626
 drivers/gpu/drm/nouveau/dispnv50/disp.c     |  9 +++-
60fd626
 drivers/gpu/drm/nouveau/nouveau_connector.c | 46 ++++++++++++---------
60fd626
 drivers/gpu/drm/nouveau/nouveau_connector.h |  5 +++
60fd626
 drivers/gpu/drm/nouveau/nouveau_dp.c        | 31 ++++++++++++++
60fd626
 drivers/gpu/drm/nouveau/nouveau_encoder.h   |  4 ++
60fd626
 5 files changed, 75 insertions(+), 20 deletions(-)
60fd626
60fd626
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
60fd626
index e92e7bf49780..d5d69532f3c5 100644
60fd626
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
60fd626
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
60fd626
@@ -1056,7 +1056,14 @@ static enum drm_mode_status
60fd626
 nv50_mstc_mode_valid(struct drm_connector *connector,
60fd626
 		     struct drm_display_mode *mode)
60fd626
 {
60fd626
-	return MODE_OK;
60fd626
+	struct nv50_mstc *mstc = nv50_mstc(connector);
60fd626
+	struct nouveau_encoder *outp = mstc->mstm->outp;
60fd626
+
60fd626
+	/* TODO: calculate the PBN from the dotclock and validate against the
60fd626
+	 * MSTB's max possible PBN
60fd626
+	 */
60fd626
+
60fd626
+	return nv50_dp_mode_valid(connector, outp, mode, NULL);
60fd626
 }
60fd626
60fd626
 static int
60fd626
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
60fd626
index 6dae00da5d7e..1b383ae0248f 100644
60fd626
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
60fd626
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
60fd626
@@ -38,6 +38,7 @@
60fd626
 #include "nouveau_reg.h"
60fd626
 #include "nouveau_drv.h"
60fd626
 #include "dispnv04/hw.h"
60fd626
+#include "dispnv50/disp.h"
60fd626
 #include "nouveau_acpi.h"
60fd626
60fd626
 #include "nouveau_display.h"
60fd626
@@ -1033,6 +1034,29 @@ get_tmds_link_bandwidth(struct drm_connector *connector)
60fd626
 		return 112000 * duallink_scale;
60fd626
 }
60fd626
60fd626
+enum drm_mode_status
60fd626
+nouveau_conn_mode_clock_valid(const struct drm_display_mode *mode,
60fd626
+			      const unsigned min_clock,
60fd626
+			      const unsigned max_clock,
60fd626
+			      unsigned int *clock_out)
60fd626
+{
60fd626
+	unsigned int clock = mode->clock;
60fd626
+
60fd626
+	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) ==
60fd626
+	    DRM_MODE_FLAG_3D_FRAME_PACKING)
60fd626
+		clock *= 2;
60fd626
+
60fd626
+	if (clock < min_clock)
60fd626
+		return MODE_CLOCK_LOW;
60fd626
+	if (clock > max_clock)
60fd626
+		return MODE_CLOCK_HIGH;
60fd626
+
60fd626
+	if (clock_out)
60fd626
+		*clock_out = clock;
60fd626
+
60fd626
+	return MODE_OK;
60fd626
+}
60fd626
+
60fd626
 static enum drm_mode_status
60fd626
 nouveau_connector_mode_valid(struct drm_connector *connector,
60fd626
 			     struct drm_display_mode *mode)
60fd626
@@ -1041,7 +1065,6 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
60fd626
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
60fd626
 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
60fd626
 	unsigned min_clock = 25000, max_clock = min_clock;
60fd626
-	unsigned clock = mode->clock;
60fd626
60fd626
 	switch (nv_encoder->dcb->type) {
60fd626
 	case DCB_OUTPUT_LVDS:
60fd626
@@ -1064,29 +1087,14 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
60fd626
 	case DCB_OUTPUT_TV:
60fd626
 		return get_slave_funcs(encoder)->mode_valid(encoder, mode);
60fd626
 	case DCB_OUTPUT_DP:
60fd626
-		if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
60fd626
-		    !nv_encoder->caps.dp_interlace)
60fd626
-			return MODE_NO_INTERLACE;
60fd626
-
60fd626
-		max_clock  = nv_encoder->dp.link_nr;
60fd626
-		max_clock *= nv_encoder->dp.link_bw;
60fd626
-		clock = clock * (connector->display_info.bpc * 3) / 10;
60fd626
-		break;
60fd626
+		return nv50_dp_mode_valid(connector, nv_encoder, mode, NULL);
60fd626
 	default:
60fd626
 		BUG();
60fd626
 		return MODE_BAD;
60fd626
 	}
60fd626
60fd626
-	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
60fd626
-		clock *= 2;
60fd626
-
60fd626
-	if (clock < min_clock)
60fd626
-		return MODE_CLOCK_LOW;
60fd626
-
60fd626
-	if (clock > max_clock)
60fd626
-		return MODE_CLOCK_HIGH;
60fd626
-
60fd626
-	return MODE_OK;
60fd626
+	return nouveau_conn_mode_clock_valid(mode, min_clock, max_clock,
60fd626
+					     NULL);
60fd626
 }
60fd626
60fd626
 static struct drm_encoder *
60fd626
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
60fd626
index de84fb4708c7..9e062c7adec8 100644
60fd626
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
60fd626
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
60fd626
@@ -195,6 +195,11 @@ int nouveau_conn_atomic_get_property(struct drm_connector *,
60fd626
 				     const struct drm_connector_state *,
60fd626
 				     struct drm_property *, u64 *);
60fd626
 struct drm_display_mode *nouveau_conn_native_mode(struct drm_connector *);
60fd626
+enum drm_mode_status
60fd626
+nouveau_conn_mode_clock_valid(const struct drm_display_mode *,
60fd626
+			      const unsigned min_clock,
60fd626
+			      const unsigned max_clock,
60fd626
+			      unsigned *clock);
60fd626
60fd626
 #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
60fd626
 extern int nouveau_backlight_init(struct drm_connector *);
60fd626
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
60fd626
index 2674f1587457..8a0f7994e1ae 100644
60fd626
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
60fd626
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
60fd626
@@ -98,3 +98,34 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
60fd626
 		return NOUVEAU_DP_SST;
60fd626
 	return ret;
60fd626
 }
60fd626
+
60fd626
+/* TODO:
60fd626
+ * - Use the minimum possible BPC here, once we add support for the max bpc
60fd626
+ *   property.
60fd626
+ * - Validate the mode against downstream port caps (see
60fd626
+ *   drm_dp_downstream_max_clock())
60fd626
+ * - Validate against the DP caps advertised by the GPU (we don't check these
60fd626
+ *   yet)
60fd626
+ */
60fd626
+enum drm_mode_status
60fd626
+nv50_dp_mode_valid(struct drm_connector *connector,
60fd626
+		   struct nouveau_encoder *outp,
60fd626
+		   const struct drm_display_mode *mode,
60fd626
+		   unsigned *out_clock)
60fd626
+{
60fd626
+	const unsigned min_clock = 25000;
60fd626
+	unsigned max_clock, clock;
60fd626
+	enum drm_mode_status ret;
60fd626
+
60fd626
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace)
60fd626
+		return MODE_NO_INTERLACE;
60fd626
+
60fd626
+	max_clock = outp->dp.link_nr * outp->dp.link_bw;
60fd626
+	clock = mode->clock * (connector->display_info.bpc * 3) / 10;
60fd626
+
60fd626
+	ret = nouveau_conn_mode_clock_valid(mode, min_clock, max_clock,
60fd626
+					    &clock);
60fd626
+	if (out_clock)
60fd626
+		*out_clock = clock;
60fd626
+	return ret;
60fd626
+}
60fd626
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
60fd626
index 3217f587eceb..de51733b0476 100644
60fd626
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
60fd626
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
60fd626
@@ -104,6 +104,10 @@ enum nouveau_dp_status {
60fd626
 };
60fd626
60fd626
 int nouveau_dp_detect(struct nouveau_encoder *);
60fd626
+enum drm_mode_status nv50_dp_mode_valid(struct drm_connector *,
60fd626
+					struct nouveau_encoder *,
60fd626
+					const struct drm_display_mode *,
60fd626
+					unsigned *clock);
60fd626
60fd626
 struct nouveau_connector *
60fd626
 nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
60fd626
-- 
60fd626
2.26.2
60fd626