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