summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/engine/disp
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2022-06-01 20:46:33 +1000
committerBen Skeggs <bskeggs@redhat.com>2022-11-09 08:22:02 +1000
commit8134437213316a58d1844b87e2042ebf1fd9962c (patch)
tree59edc70bc07bdce83fbba76abc25238b634b7596 /drivers/gpu/drm/nouveau/nvkm/engine/disp
parenta9f5d7721923f6016578167640b8dd5cb0c5a698 (diff)
downloadlinux-stable-8134437213316a58d1844b87e2042ebf1fd9962c.tar.gz
linux-stable-8134437213316a58d1844b87e2042ebf1fd9962c.tar.bz2
linux-stable-8134437213316a58d1844b87e2042ebf1fd9962c.zip
drm/nouveau/disp: move DP link config into acquire
Aside from fixing MST->SST switching (KMS never turned off MST link config), this should preserve existing behaviour for the moment, but provide a path for the KMS driver to have more explicit control of the DP link, which has been requested by Lyude. More research into modeset/supervisor interactions is needed before we can have fully explicit control from the KMS driver. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Reviewed-by: Lyude Paul <lyude@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c29
4 files changed, 46 insertions, 19 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index c1b3206f27e6..f1887b58f472 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -287,7 +287,7 @@ nvkm_dp_train_links(struct nvkm_outp *outp, int rate)
u8 sink[2], data;
int ret;
- OUTP_DBG(outp, "training %d x %d MB/s", ior->dp.nr, ior->dp.bw * 27);
+ OUTP_DBG(outp, "training %dx%02x", ior->dp.nr, ior->dp.bw);
/* Intersect misc. capabilities of the OR and sink. */
if (disp->engine.subdev.device->chipset < 0x110)
@@ -455,6 +455,21 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
/* Link training. */
OUTP_DBG(outp, "training");
nvkm_dp_train_init(outp);
+
+ /* Validate and train at configuration requested (if any) on ACQUIRE. */
+ if (outp->dp.lt.nr) {
+ for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
+ for (rate = 0; nr == outp->dp.lt.nr && rate < outp->dp.rates; rate++) {
+ if (outp->dp.rate[rate].rate / 27000 == outp->dp.lt.bw) {
+ ior->dp.bw = outp->dp.rate[rate].rate / 27000;
+ ior->dp.nr = nr;
+ ret = nvkm_dp_train_links(outp, rate);
+ }
+ }
+ }
+ }
+
+ /* Otherwise, loop through all valid link configurations that support the data rate. */
for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
for (rate = 0; ret < 0 && rate < outp->dp.rates; rate++) {
if (outp->dp.rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) {
@@ -465,6 +480,8 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
}
}
}
+
+ /* Finish up. */
nvkm_dp_train_fini(outp);
if (ret < 0)
OUTP_ERR(outp, "training failed");
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index eb9cd1146825..d7c989e1cd01 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -54,6 +54,8 @@ struct nvkm_outp {
struct mutex mutex;
struct {
atomic_t done;
+ u8 nr;
+ u8 bw;
bool mst;
} lt;
} dp;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
index a5bb15b62a0c..2f42940367a0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
@@ -91,21 +91,6 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
}
switch (mthd * !!outp) {
- case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
- union {
- struct nv50_disp_sor_dp_mst_link_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
- nvif_ioctl(object, "disp sor dp mst link size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n",
- args->v0.version, args->v0.state);
- outp->dp.lt.mst = !!args->v0.state;
- return 0;
- } else
- return ret;
- }
- break;
case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: {
union {
struct nv50_disp_sor_dp_mst_vcpi_v0 v0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index 052b2d14f47a..61d41b326f43 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -101,6 +101,23 @@ nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc)
}
static int
+nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[16],
+ u8 link_nr, u8 link_bw, bool hda, bool mst)
+{
+ int ret;
+
+ ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda);
+ if (ret)
+ return ret;
+
+ memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd));
+ outp->dp.lt.nr = link_nr;
+ outp->dp.lt.bw = link_bw;
+ outp->dp.lt.mst = mst;
+ return 0;
+}
+
+static int
nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet,
u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda)
{
@@ -152,6 +169,8 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
+ if (outp->ior)
+ return -EBUSY;
switch (args->v0.proto) {
case NVIF_OUTP_ACQUIRE_V0_RGB_CRT:
@@ -165,12 +184,16 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
args->v0.tmds.hdmi_scdc,
args->v0.tmds.hdmi_hda);
break;
- case NVIF_OUTP_ACQUIRE_V0_DP:
- ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, args->v0.dp.hda);
- break;
case NVIF_OUTP_ACQUIRE_V0_LVDS:
ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8);
break;
+ case NVIF_OUTP_ACQUIRE_V0_DP:
+ ret = nvkm_uoutp_mthd_acquire_dp(outp, args->v0.dp.dpcd,
+ args->v0.dp.link_nr,
+ args->v0.dp.link_bw,
+ args->v0.dp.hda != 0,
+ args->v0.dp.mst != 0);
+ break;
default:
ret = -EINVAL;
break;