drm/nouveau/disp: identity-map display paths to output resources
authorBen Skeggs <bskeggs@redhat.com>
Fri, 19 May 2017 13:59:35 +0000 (23:59 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 16 Jun 2017 04:04:49 +0000 (14:04 +1000)
This essentially replicates our current behaviour in a way that's
compatible with the new model that's emerging, so that we're able
to start porting the hw-specific functions to it.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h

index d62e93bb0f7090e058b5c51d33193a3beeaf7ada..601fa625e440d184f93a05a81a1f13d3596126b0 100644 (file)
@@ -562,7 +562,10 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
        u32 data;
        int ret;
 
-       nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp);
+       ret = nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp);
+       if (ret)
+               return ret;
+
        dp->aux = aux;
        if (!dp->aux) {
                OUTP_ERR(&dp->outp, "no aux");
index 2abba07ae63283a9a9071cb2f0f7b1cc4bc4d253..a8d80eb8d89380b2f56a3912e5e3949548f7d263 100644 (file)
@@ -14,6 +14,16 @@ struct nvkm_ior {
        char name[8];
 
        struct list_head head;
+
+       struct nvkm_ior_state {
+               enum nvkm_ior_proto {
+                       CRT,
+                       TMDS,
+                       LVDS,
+                       DP,
+                       UNKNOWN
+               } proto:3;
+       } arm, asy;
 };
 
 struct nvkm_ior_func {
index f030ff51d076ca89e26bf8763cb93abad7fa7ea0..895a84ca1501aa78df10903f4d15db21663ae83e 100644 (file)
  * Authors: Ben Skeggs
  */
 #include "outp.h"
+#include "ior.h"
 
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
 #include <subdev/i2c.h>
 
+static enum nvkm_ior_proto
+nvkm_outp_xlat(struct nvkm_output *outp, enum nvkm_ior_type *type)
+{
+       switch (outp->info.location) {
+       case 0:
+               switch (outp->info.type) {
+               case DCB_OUTPUT_ANALOG: *type = DAC; return  CRT;
+               case DCB_OUTPUT_TMDS  : *type = SOR; return TMDS;
+               case DCB_OUTPUT_LVDS  : *type = SOR; return LVDS;
+               case DCB_OUTPUT_DP    : *type = SOR; return   DP;
+               default:
+                       break;
+               }
+               break;
+       case 1:
+               switch (outp->info.type) {
+               case DCB_OUTPUT_TMDS: *type = PIOR; return TMDS;
+               case DCB_OUTPUT_DP  : *type = PIOR; return TMDS; /* not a bug */
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       WARN_ON(1);
+       return UNKNOWN;
+}
+
 void
 nvkm_outp_fini(struct nvkm_outp *outp)
 {
@@ -34,9 +64,38 @@ nvkm_outp_fini(struct nvkm_outp *outp)
                outp->func->fini(outp);
 }
 
+static void
+nvkm_outp_init_route(struct nvkm_output *outp)
+{
+       struct nvkm_disp *disp = outp->disp;
+       enum nvkm_ior_proto proto;
+       enum nvkm_ior_type type;
+       struct nvkm_ior *ior;
+       int id;
+
+       proto = nvkm_outp_xlat(outp, &type);
+       if (proto == UNKNOWN)
+               return;
+
+       /* Determine the specific OR, if any, this device is attached to. */
+       if (1) {
+               /* Prior to DCB 4.1, this is hardwired like so. */
+               id = ffs(outp->info.or) - 1;
+       }
+
+       ior = nvkm_ior_find(disp, type, id);
+       if (!ior) {
+               WARN_ON(1);
+               return;
+       }
+
+       outp->ior = ior;
+}
+
 void
 nvkm_outp_init(struct nvkm_outp *outp)
 {
+       nvkm_outp_init_route(outp);
        if (outp->func->init)
                outp->func->init(outp);
 }
@@ -53,11 +112,13 @@ nvkm_outp_del(struct nvkm_outp **poutp)
        }
 }
 
-void
+int
 nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp,
               int index, struct dcb_output *dcbE, struct nvkm_outp *outp)
 {
        struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
+       enum nvkm_ior_proto proto;
+       enum nvkm_ior_type type;
 
        outp->func = func;
        outp->disp = disp;
@@ -72,6 +133,13 @@ nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp,
                 outp->info.type >= 2 ? outp->info.sorconf.link : 0,
                 outp->info.connector, outp->info.i2c_index,
                 outp->info.bus, outp->info.heads);
+
+       /* Cull output paths we can't map to an output resource. */
+       proto = nvkm_outp_xlat(outp, &type);
+       if (proto == UNKNOWN)
+               return -ENODEV;
+
+       return 0;
 }
 
 int
@@ -81,7 +149,5 @@ nvkm_outp_new_(const struct nvkm_outp_func *func,
 {
        if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL)))
                return -ENOMEM;
-
-       nvkm_outp_ctor(func, disp, index, dcbE, *poutp);
-       return 0;
+       return nvkm_outp_ctor(func, disp, index, dcbE, *poutp);
 }
index 682fc99c935130d3b195e90eada9c80083597791..e48251c378227e219311fc1f44894bc639db9119 100644 (file)
@@ -11,16 +11,18 @@ struct nvkm_outp {
        int index;
        struct dcb_output info;
 
-       // whatever (if anything) is pointed at by the dcb device entry
        struct nvkm_i2c_bus *i2c;
        int or;
 
        struct list_head head;
        struct nvkm_conn *conn;
+
+       /* Assembly state. */
+       struct nvkm_ior *ior;
 };
 
-void nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *,
-                   int index, struct dcb_output *, struct nvkm_outp *);
+int nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *,
+                  int index, struct dcb_output *, struct nvkm_outp *);
 void nvkm_outp_del(struct nvkm_outp **);
 void nvkm_outp_init(struct nvkm_outp *);
 void nvkm_outp_fini(struct nvkm_outp *);