OSDN Git Service

drm/nouveau/disp: move DP link config into acquire
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:46:33 +0000 (20:46 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 8 Nov 2022 22:22:02 +0000 (08:22 +1000)
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>
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/include/nvif/cl5070.h
drivers/gpu/drm/nouveau/include/nvif/if0012.h
drivers/gpu/drm/nouveau/include/nvif/outp.h
drivers/gpu/drm/nouveau/nvif/outp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c

index c61617a..ca58c6b 100644 (file)
@@ -1014,7 +1014,7 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
 
        if (!mstm->links++) {
                /*XXX: MST audio. */
-               nvif_outp_acquire_dp(&mstm->outp->outp, false);
+               nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true);
        }
 
        if (mstm->outp->outp.or.link & 1)
@@ -1380,26 +1380,6 @@ nv50_mstm_remove(struct nv50_mstm *mstm)
        drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false);
 }
 
-static int
-nv50_mstm_enable(struct nv50_mstm *mstm, int state)
-{
-       struct nouveau_encoder *outp = mstm->outp;
-       struct {
-               struct nv50_disp_mthd_v1 base;
-               struct nv50_disp_sor_dp_mst_link_v0 mst;
-       } args = {
-               .base.version = 1,
-               .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK,
-               .base.hasht = outp->dcb->hasht,
-               .base.hashm = outp->dcb->hashm,
-               .mst.state = state,
-       };
-       struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
-       struct nvif_object *disp = &drm->display->disp.object;
-
-       return nvif_mthd(disp, 0, &args, sizeof(args));
-}
-
 int
 nv50_mstm_detect(struct nouveau_encoder *outp)
 {
@@ -1420,15 +1400,9 @@ nv50_mstm_detect(struct nouveau_encoder *outp)
                return ret;
 
        /* And start enabling */
-       ret = nv50_mstm_enable(mstm, true);
-       if (ret)
-               return ret;
-
        ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, true);
-       if (ret) {
-               nv50_mstm_enable(mstm, false);
+       if (ret)
                return ret;
-       }
 
        mstm->is_mst = true;
        return 1;
@@ -1660,7 +1634,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
                nvif_outp_acquire_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc);
                break;
        case DCB_OUTPUT_DP:
-               nvif_outp_acquire_dp(&nv_encoder->outp, hda);
+               nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false);
                depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
 
                if (nv_encoder->outp.or.link & 1)
@@ -1858,7 +1832,7 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
                break;
        case DCB_OUTPUT_DP:
                ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
-               nvif_outp_acquire_dp(&nv_encoder->outp, false);
+               nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false);
                break;
        default:
                BUG();
index a713177..15e30fb 100644 (file)
@@ -28,7 +28,6 @@ struct nv50_disp_scanoutpos_v0 {
 
 struct nv50_disp_mthd_v1 {
        __u8  version;
-#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK                                  0x25
 #define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI                                  0x26
        __u8  method;
        __u16 hasht;
@@ -36,12 +35,6 @@ struct nv50_disp_mthd_v1 {
        __u8  pad06[2];
 };
 
-struct nv50_disp_sor_dp_mst_link_v0 {
-       __u8  version;
-       __u8  state;
-       __u8  pad02[6];
-};
-
 struct nv50_disp_sor_dp_mst_vcpi_v0 {
        __u8  version;
        __u8  pad01[1];
index 938d384..c67f03d 100644 (file)
@@ -55,8 +55,12 @@ union nvif_outp_acquire_args {
                                __u8 pad02[6];
                        } lvds;
                        struct {
+                               __u8 link_nr; /* 0 = highest possible. */
+                               __u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */
                                __u8 hda;
-                               __u8 pad01[7];
+                               __u8 mst;
+                               __u8 pad04[4];
+                               __u8 dpcd[16];
                        } dp;
                };
        } v0;
index c8879d3..88fd2b9 100644 (file)
@@ -21,7 +21,8 @@ int nvif_outp_acquire_rgb_crt(struct nvif_outp *);
 int nvif_outp_acquire_tmds(struct nvif_outp *, int head,
                           bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda);
 int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8);
-int nvif_outp_acquire_dp(struct nvif_outp *, bool hda);
+int nvif_outp_acquire_dp(struct nvif_outp *, u8 dpcd[16],
+                        int link_nr, int link_bw, bool hda, bool mst);
 void nvif_outp_release(struct nvif_outp *);
 int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
 int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
index 3a7c2d5..1ae5b19 100644 (file)
@@ -84,16 +84,22 @@ nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0
 }
 
 int
-nvif_outp_acquire_dp(struct nvif_outp *outp,  bool hda)
+nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[16],
+                    int link_nr, int link_bw, bool hda, bool mst)
 {
        struct nvif_outp_acquire_v0 args;
        int ret;
 
+       args.dp.link_nr = link_nr;
+       args.dp.link_bw = link_bw;
        args.dp.hda = hda;
+       args.dp.mst = mst;
+       memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd));
 
        ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args);
        NVIF_ERRON(ret, &outp->object,
-                  "[ACQUIRE proto:DP hda:%d] or:%d link:%d", args.dp.hda, args.or, args.link);
+                  "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d",
+                  args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link);
        return ret;
 }
 
index c1b3206..f1887b5 100644 (file)
@@ -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");
index eb9cd11..d7c989e 100644 (file)
@@ -54,6 +54,8 @@ struct nvkm_outp {
                        struct mutex mutex;
                        struct {
                                atomic_t done;
+                               u8 nr;
+                               u8 bw;
                                bool mst;
                        } lt;
                } dp;
index a5bb15b..2f42940 100644 (file)
@@ -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;
index 052b2d1..61d41b3 100644 (file)
@@ -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;