From: Ben Skeggs <bske...@redhat.com>

- preparation for GSP-RM

Signed-off-by: Ben Skeggs <bske...@redhat.com>
Reviewed-by: Lyude Paul <ly...@redhat.com>
Acked-by: Danilo Krummrich <m...@dakr.org>
Signed-off-by: Lyude Paul <ly...@redhat.com>
---
 drivers/gpu/drm/nouveau/dispnv50/disp.c       | 97 ++++++++++---------
 drivers/gpu/drm/nouveau/dispnv50/disp.h       |  2 -
 drivers/gpu/drm/nouveau/include/nvif/if0012.h | 31 +++++-
 drivers/gpu/drm/nouveau/include/nvif/outp.h   | 40 ++++++++
 drivers/gpu/drm/nouveau/nouveau_connector.c   |  2 +-
 drivers/gpu/drm/nouveau/nvif/outp.c           | 44 +++++++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c |  5 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/outp.h   |  2 +
 .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c  | 50 ++++++++++
 9 files changed, 223 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c 
b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index e2fa748e66f16..dcd19c4183894 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -66,8 +66,6 @@
 #include "nouveau_fence.h"
 #include "nv50_display.h"
 
-#include <subdev/bios/dp.h>
-
 /******************************************************************************
  * EVO channel
  *****************************************************************************/
@@ -1704,7 +1702,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, 
struct drm_atomic_state *sta
        }
 
        if (head->func->display_id)
-               head->func->display_id(head, BIT(nv_encoder->dcb->id));
+               head->func->display_id(head, BIT(nv_encoder->outp.id));
 
        nv_encoder->update(nv_encoder, nv_crtc->index, asyh, proto, depth);
 }
@@ -1736,16 +1734,6 @@ nv50_sor_func = {
        .destroy = nv50_sor_destroy,
 };
 
-bool nv50_has_mst(struct nouveau_drm *drm)
-{
-       struct nvkm_bios *bios = nvxx_bios(&drm->client.device);
-       u32 data;
-       u8 ver, hdr, cnt, len;
-
-       data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len);
-       return data && ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 0x04);
-}
-
 static int
 nv50_sor_create(struct nouveau_encoder *nv_encoder)
 {
@@ -1798,15 +1786,15 @@ nv50_sor_create(struct nouveau_encoder *nv_encoder)
                        nv_encoder->i2c = &nv_connector->aux.ddc;
                }
 
-               if (nv_connector->type != DCB_CONNECTOR_eDP &&
-                   nv50_has_mst(drm)) {
+               if (nv_connector->type != DCB_CONNECTOR_eDP && 
nv_encoder->outp.info.dp.mst) {
                        ret = nv50_mstm_new(nv_encoder, &nv_connector->aux,
                                            16, nv_connector->base.base.id,
                                            &nv_encoder->dp.mstm);
                        if (ret)
                                return ret;
                }
-       } else {
+       } else
+       if (nv_encoder->outp.info.ddc != NVIF_OUTP_DDC_INVALID) {
                struct nvkm_i2c_bus *bus =
                        nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
                if (bus)
@@ -1927,12 +1915,12 @@ nv50_pior_create(struct nouveau_encoder *nv_encoder)
 
        switch (dcbe->type) {
        case DCB_OUTPUT_TMDS:
-               bus  = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev));
+               bus  = nvkm_i2c_bus_find(i2c, nv_encoder->outp.info.ddc);
                ddc  = bus ? &bus->i2c : NULL;
                type = DRM_MODE_ENCODER_TMDS;
                break;
        case DCB_OUTPUT_DP:
-               aux  = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev));
+               aux  = nvkm_i2c_aux_find(i2c, nv_encoder->outp.info.dp.aux);
                ddc  = aux ? &aux->i2c : NULL;
                type = DRM_MODE_ENCODER_TMDS;
                break;
@@ -2693,12 +2681,10 @@ int
 nv50_display_create(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct dcb_table *dcb = &drm->vbios.dcb;
        struct drm_connector *connector, *tmp;
        struct nv50_disp *disp;
-       struct dcb_output *dcbe;
        int ret, i;
-       bool has_mst = nv50_has_mst(drm);
+       bool has_mst = false;
 
        disp = kzalloc(sizeof(*disp), GFP_KERNEL);
        if (!disp)
@@ -2775,54 +2761,75 @@ nv50_display_create(struct drm_device *dev)
        }
 
        /* create encoder/connector objects based on VBIOS DCB table */
-       for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
+       for_each_set_bit(i, &disp->disp->outp_mask, 
sizeof(disp->disp->outp_mask) * 8) {
                struct nouveau_encoder *outp;
 
                outp = kzalloc(sizeof(*outp), GFP_KERNEL);
                if (!outp)
                        break;
 
-               ret = nvif_outp_ctor(disp->disp, "kmsOutp", dcbe->id, 
&outp->outp);
+               ret = nvif_outp_ctor(disp->disp, "kmsOutp", i, &outp->outp);
                if (ret) {
                        kfree(outp);
                        continue;
                }
 
-               connector = nouveau_connector_create(dev, dcbe->connector);
+               connector = nouveau_connector_create(dev, outp->outp.info.conn);
                if (IS_ERR(connector)) {
                        nvif_outp_dtor(&outp->outp);
                        kfree(outp);
                        continue;
                }
 
-               outp->base.base.possible_crtcs = dcbe->heads;
+               outp->base.base.possible_crtcs = outp->outp.info.heads;
                outp->base.base.possible_clones = 0;
-               outp->dcb = dcbe;
                outp->conn = nouveau_connector(connector);
 
-               if (dcbe->location == DCB_LOC_ON_CHIP) {
-                       switch (dcbe->type) {
-                       case DCB_OUTPUT_TMDS:
-                       case DCB_OUTPUT_LVDS:
-                       case DCB_OUTPUT_DP:
-                               ret = nv50_sor_create(outp);
-                               break;
-                       case DCB_OUTPUT_ANALOG:
-                               ret = nv50_dac_create(outp);
-                               break;
-                       default:
-                               ret = -ENODEV;
-                               break;
-                       }
-               } else {
-                       ret = nv50_pior_create(outp);
+               outp->dcb = kzalloc(sizeof(*outp->dcb), GFP_KERNEL);
+               if (!outp->dcb)
+                       break;
+
+               switch (outp->outp.info.proto) {
+               case NVIF_OUTP_RGB_CRT:
+                       outp->dcb->type = DCB_OUTPUT_ANALOG;
+                       outp->dcb->crtconf.maxfreq = 
outp->outp.info.rgb_crt.freq_max;
+                       break;
+               case NVIF_OUTP_TMDS:
+                       outp->dcb->type = DCB_OUTPUT_TMDS;
+                       outp->dcb->duallink_possible = 
outp->outp.info.tmds.dual;
+                       break;
+               case NVIF_OUTP_LVDS:
+                       outp->dcb->type = DCB_OUTPUT_LVDS;
+                       outp->dcb->lvdsconf.use_acpi_for_edid = 
outp->outp.info.lvds.acpi_edid;
+                       break;
+               case NVIF_OUTP_DP:
+                       outp->dcb->type = DCB_OUTPUT_DP;
+                       outp->dcb->dpconf.link_nr = outp->outp.info.dp.link_nr;
+                       outp->dcb->dpconf.link_bw = outp->outp.info.dp.link_bw;
+                       if (outp->outp.info.dp.mst)
+                               has_mst = true;
+                       break;
+               default:
+                       WARN_ON(1);
+                       continue;
+               }
+
+               outp->dcb->heads = outp->outp.info.heads;
+               outp->dcb->connector = outp->outp.info.conn;
+               outp->dcb->i2c_index = outp->outp.info.ddc;
+
+               switch (outp->outp.info.type) {
+               case NVIF_OUTP_DAC : ret = nv50_dac_create(outp); break;
+               case NVIF_OUTP_SOR : ret = nv50_sor_create(outp); break;
+               case NVIF_OUTP_PIOR: ret = nv50_pior_create(outp); break;
+               default:
+                       WARN_ON(1);
+                       continue;
                }
 
                if (ret) {
                        NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n",
-                                    dcbe->location, dcbe->type,
-                                    ffs(dcbe->or) - 1, ret);
-                       ret = 0;
+                               i, outp->outp.info.type, outp->outp.info.proto, 
ret);
                }
        }
 
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h 
b/drivers/gpu/drm/nouveau/dispnv50/disp.h
index 1e5601223c753..5508a7cfd4924 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h
@@ -108,8 +108,6 @@ void nv50_dmac_destroy(struct nv50_dmac *);
  */
 struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder);
 
-bool nv50_has_mst(struct nouveau_drm *drm);
-
 u32 *evo_wait(struct nv50_dmac *, int nr);
 void evo_kick(u32 *, struct nv50_dmac *);
 
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h 
b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
index 502f342e0d775..bde9bfae8d11f 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
@@ -8,7 +8,36 @@ union nvif_outp_args {
        struct nvif_outp_v0 {
                __u8 version;
                __u8 id;        /* DCB device index. */
-               __u8 pad02[6];
+#define NVIF_OUTP_V0_TYPE_DAC  0x00
+#define NVIF_OUTP_V0_TYPE_SOR  0x01
+#define NVIF_OUTP_V0_TYPE_PIOR 0x02
+               __u8 type;
+#define NVIF_OUTP_V0_PROTO_RGB_CRT 0x00
+#define NVIF_OUTP_V0_PROTO_TMDS    0x01
+#define NVIF_OUTP_V0_PROTO_LVDS    0x02
+#define NVIF_OUTP_V0_PROTO_DP      0x03
+               __u8 proto;
+               __u8 heads;
+               __u8 ddc;
+               __u8 conn;
+               union {
+                       struct {
+                               __u32 freq_max;
+                       } rgb_crt;
+                       struct {
+                               __u8  dual;
+                       } tmds;
+                       struct {
+                               __u8  acpi_edid;
+                       } lvds;
+                       struct {
+                               __u8  aux;
+                               __u8  mst;
+                               __u8  increased_wm;
+                               __u8  link_nr;
+                               __u32 link_bw;
+                       } dp;
+               };
        } v0;
 };
 
diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h 
b/drivers/gpu/drm/nouveau/include/nvif/outp.h
index 2d86838ed5598..bc122a5ba7df7 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/outp.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h
@@ -8,6 +8,46 @@ struct nvif_disp;
 
 struct nvif_outp {
        struct nvif_object object;
+       u32 id;
+
+       struct {
+               enum {
+                       NVIF_OUTP_DAC,
+                       NVIF_OUTP_SOR,
+                       NVIF_OUTP_PIOR,
+               } type;
+
+               enum {
+                       NVIF_OUTP_RGB_CRT,
+                       NVIF_OUTP_TMDS,
+                       NVIF_OUTP_LVDS,
+                       NVIF_OUTP_DP,
+               } proto;
+
+               u8 heads;
+#define NVIF_OUTP_DDC_INVALID 0xff
+               u8 ddc;
+               u8 conn;
+
+               union {
+                       struct {
+                               u32 freq_max;
+                       } rgb_crt;
+                       struct {
+                               bool dual;
+                       } tmds;
+                       struct {
+                               bool acpi_edid;
+                       } lvds;
+                       struct {
+                               u8   aux;
+                               bool mst;
+                               bool increased_wm;
+                               u8   link_nr;
+                               u32  link_bw;
+                       } dp;
+               };
+       } info;
 
        struct {
                int id;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 21cc8dfcb7add..94498c15b50e3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -1135,7 +1135,7 @@ nouveau_connector_atomic_check(struct drm_connector 
*connector, struct drm_atomi
        struct drm_connector_state *conn_state =
                drm_atomic_get_new_connector_state(state, connector);
 
-       if (!nv_conn->dp_encoder || !nv50_has_mst(nouveau_drm(connector->dev)))
+       if (!nv_conn->dp_encoder || !nv_conn->dp_encoder->dp.mstm)
                return 0;
 
        return drm_dp_mst_root_conn_atomic_check(conn_state, 
&nv_conn->dp_encoder->dp.mstm->mgr);
diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c 
b/drivers/gpu/drm/nouveau/nvif/outp.c
index 97e5855c2cf54..5d3190c05250a 100644
--- a/drivers/gpu/drm/nouveau/nvif/outp.c
+++ b/drivers/gpu/drm/nouveau/nvif/outp.c
@@ -511,6 +511,50 @@ nvif_outp_ctor(struct nvif_disp *disp, const char *name, 
int id, struct nvif_out
        if (ret)
                return ret;
 
+       outp->id = args.id;
+
+       switch (args.type) {
+       case NVIF_OUTP_V0_TYPE_DAC : outp->info.type = NVIF_OUTP_DAC; break;
+       case NVIF_OUTP_V0_TYPE_SOR : outp->info.type = NVIF_OUTP_SOR; break;
+       case NVIF_OUTP_V0_TYPE_PIOR: outp->info.type = NVIF_OUTP_PIOR; break;
+               break;
+       default:
+               WARN_ON(1);
+               nvif_outp_dtor(outp);
+               return -EINVAL;
+       }
+
+       switch (args.proto) {
+       case NVIF_OUTP_V0_PROTO_RGB_CRT:
+               outp->info.proto = NVIF_OUTP_RGB_CRT;
+               outp->info.rgb_crt.freq_max = args.rgb_crt.freq_max;
+               break;
+       case NVIF_OUTP_V0_PROTO_TMDS:
+               outp->info.proto = NVIF_OUTP_TMDS;
+               outp->info.tmds.dual = args.tmds.dual;
+               break;
+       case NVIF_OUTP_V0_PROTO_LVDS:
+               outp->info.proto = NVIF_OUTP_LVDS;
+               outp->info.lvds.acpi_edid = args.lvds.acpi_edid;
+               break;
+       case NVIF_OUTP_V0_PROTO_DP:
+               outp->info.proto = NVIF_OUTP_DP;
+               outp->info.dp.aux = args.dp.aux;
+               outp->info.dp.mst = args.dp.mst;
+               outp->info.dp.increased_wm = args.dp.increased_wm;
+               outp->info.dp.link_nr = args.dp.link_nr;
+               outp->info.dp.link_bw = args.dp.link_bw;
+               break;
+       default:
+               WARN_ON(1);
+               nvif_outp_dtor(outp);
+               return -EINVAL;
+       }
+
+       outp->info.heads = args.heads;
+       outp->info.ddc = args.ddc;
+       outp->info.conn = args.conn;
+
        outp->or.id = -1;
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index b35fae96d855d..a109348bd63b7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -639,7 +639,7 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct 
dcb_output *dcbE, struct n
        struct nvkm_bios *bios = device->bios;
        struct nvkm_i2c *i2c = device->i2c;
        struct nvkm_outp *outp;
-       u8  hdr, cnt, len;
+       u8  ver, hdr, cnt, len;
        u32 data;
        int ret;
 
@@ -667,6 +667,9 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct 
dcb_output *dcbE, struct n
 
        OUTP_DBG(outp, "bios dp %02x %02x %02x %02x", outp->dp.version, hdr, 
cnt, len);
 
+       data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len);
+       outp->dp.mst = data && ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 
0x04);
+
        mutex_init(&outp->dp.mutex);
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index 3ec7318d9144e..ebd2f499b4b1d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -35,6 +35,8 @@ struct nvkm_outp {
                struct {
                        struct nvbios_dpout info;
                        u8 version;
+                       bool mst;
+                       bool increased_wm;
 
                        struct nvkm_i2c_aux *aux;
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index ad52d9ed594af..e4279f1772a1b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -606,10 +606,60 @@ nvkm_uoutp_new(const struct nvkm_oclass *oclass, void 
*argv, u32 argc, struct nv
        ret = -EBUSY;
        spin_lock(&disp->client.lock);
        if (!outp->object.func) {
+               switch (outp->info.type) {
+               case DCB_OUTPUT_ANALOG:
+                       args->v0.type = NVIF_OUTP_V0_TYPE_DAC;
+                       args->v0.proto = NVIF_OUTP_V0_PROTO_RGB_CRT;
+                       args->v0.rgb_crt.freq_max = outp->info.crtconf.maxfreq;
+                       break;
+               case DCB_OUTPUT_TMDS:
+                       if (!outp->info.location) {
+                               args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
+                               args->v0.tmds.dual = 
(outp->info.tmdsconf.sor.link == 3);
+                       } else {
+                               args->v0.type = NVIF_OUTP_V0_TYPE_PIOR;
+                               args->v0.tmds.dual = 0;
+                       }
+                       args->v0.proto = NVIF_OUTP_V0_PROTO_TMDS;
+                       break;
+               case DCB_OUTPUT_LVDS:
+                       args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
+                       args->v0.proto = NVIF_OUTP_V0_PROTO_LVDS;
+                       args->v0.lvds.acpi_edid = 
outp->info.lvdsconf.use_acpi_for_edid;
+                       break;
+               case DCB_OUTPUT_DP:
+                       if (!outp->info.location) {
+                               args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
+                               args->v0.dp.aux = outp->info.i2c_index;
+                       } else {
+                               args->v0.type = NVIF_OUTP_V0_TYPE_PIOR;
+                               args->v0.dp.aux = 
NVKM_I2C_AUX_EXT(outp->info.extdev);
+                       }
+                       args->v0.proto = NVIF_OUTP_V0_PROTO_DP;
+                       args->v0.dp.mst = outp->dp.mst;
+                       args->v0.dp.increased_wm = outp->dp.increased_wm;
+                       args->v0.dp.link_nr = outp->info.dpconf.link_nr;
+                       args->v0.dp.link_bw = outp->info.dpconf.link_bw * 27000;
+                       break;
+               default:
+                       WARN_ON(1);
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               if (outp->info.location)
+                       args->v0.ddc = NVKM_I2C_BUS_EXT(outp->info.extdev);
+               else
+                       args->v0.ddc = outp->info.i2c_index;
+               args->v0.heads = outp->info.heads;
+               args->v0.conn = outp->info.connector;
+
                nvkm_object_ctor(&nvkm_uoutp, oclass, &outp->object);
                *pobject = &outp->object;
                ret = 0;
        }
+
+done:
        spin_unlock(&disp->client.lock);
        return ret;
 }
-- 
2.41.0

Reply via email to