drm/nouveau/disp: transition outp/conn away from being based on nvkm_object
authorBen Skeggs <bskeggs@redhat.com>
Thu, 20 Aug 2015 04:54:15 +0000 (14:54 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 28 Aug 2015 02:40:30 +0000 (12:40 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
28 files changed:
drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c

index 24bce1a..cc2ea61 100644 (file)
@@ -7,6 +7,7 @@ struct nvkm_disp {
        struct nvkm_engine engine;
 
        struct list_head outp;
+       struct list_head conn;
 
        struct nvkm_event hpd;
        struct nvkm_event vblank;
index 16a4e2a..38a8724 100644 (file)
@@ -1,7 +1,4 @@
 nvkm-y += nvkm/engine/disp/base.o
-nvkm-y += nvkm/engine/disp/conn.o
-nvkm-y += nvkm/engine/disp/outp.o
-nvkm-y += nvkm/engine/disp/outpdp.o
 nvkm-y += nvkm/engine/disp/nv04.o
 nvkm-y += nvkm/engine/disp/nv50.o
 nvkm-y += nvkm/engine/disp/g84.o
@@ -13,17 +10,25 @@ nvkm-y += nvkm/engine/disp/gk104.o
 nvkm-y += nvkm/engine/disp/gk110.o
 nvkm-y += nvkm/engine/disp/gm107.o
 nvkm-y += nvkm/engine/disp/gm204.o
+
+nvkm-y += nvkm/engine/disp/outp.o
+nvkm-y += nvkm/engine/disp/outpdp.o
 nvkm-y += nvkm/engine/disp/dacnv50.o
+nvkm-y += nvkm/engine/disp/piornv50.o
+nvkm-y += nvkm/engine/disp/sornv50.o
+nvkm-y += nvkm/engine/disp/sorg94.o
+nvkm-y += nvkm/engine/disp/sorgf110.o
+nvkm-y += nvkm/engine/disp/sorgm204.o
 nvkm-y += nvkm/engine/disp/dport.o
+
+nvkm-y += nvkm/engine/disp/conn.o
+
 nvkm-y += nvkm/engine/disp/hdagt215.o
 nvkm-y += nvkm/engine/disp/hdagf110.o
+
 nvkm-y += nvkm/engine/disp/hdmig84.o
 nvkm-y += nvkm/engine/disp/hdmigt215.o
 nvkm-y += nvkm/engine/disp/hdmigf110.o
 nvkm-y += nvkm/engine/disp/hdmigk104.o
-nvkm-y += nvkm/engine/disp/piornv50.o
-nvkm-y += nvkm/engine/disp/sornv50.o
-nvkm-y += nvkm/engine/disp/sorg94.o
-nvkm-y += nvkm/engine/disp/sorgf110.o
-nvkm-y += nvkm/engine/disp/sorgm204.o
+
 nvkm-y += nvkm/engine/disp/vga.o
index 2090e90..7e67445 100644 (file)
@@ -118,29 +118,25 @@ int
 _nvkm_disp_fini(struct nvkm_object *object, bool suspend)
 {
        struct nvkm_disp *disp = (void *)object;
+       struct nvkm_connector *conn;
        struct nvkm_output *outp;
-       int ret;
 
        list_for_each_entry(outp, &disp->outp, head) {
-               ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
-               if (ret && suspend)
-                       goto fail_outp;
+               nvkm_output_fini(outp);
        }
 
-       return nvkm_engine_fini(&disp->engine, suspend);
-
-fail_outp:
-       list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
-               nv_ofuncs(outp)->init(nv_object(outp));
+       list_for_each_entry(conn, &disp->conn, head) {
+               nvkm_connector_fini(conn);
        }
 
-       return ret;
+       return nvkm_engine_fini(&disp->engine, suspend);
 }
 
 int
 _nvkm_disp_init(struct nvkm_object *object)
 {
        struct nvkm_disp *disp = (void *)object;
+       struct nvkm_connector *conn;
        struct nvkm_output *outp;
        int ret;
 
@@ -148,17 +144,12 @@ _nvkm_disp_init(struct nvkm_object *object)
        if (ret)
                return ret;
 
-       list_for_each_entry(outp, &disp->outp, head) {
-               ret = nv_ofuncs(outp)->init(nv_object(outp));
-               if (ret)
-                       goto fail_outp;
+       list_for_each_entry(conn, &disp->conn, head) {
+               nvkm_connector_init(conn);
        }
 
-       return ret;
-
-fail_outp:
-       list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
-               nv_ofuncs(outp)->fini(nv_object(outp), false);
+       list_for_each_entry(outp, &disp->outp, head) {
+               nvkm_output_init(outp);
        }
 
        return ret;
@@ -168,15 +159,22 @@ void
 _nvkm_disp_dtor(struct nvkm_object *object)
 {
        struct nvkm_disp *disp = (void *)object;
-       struct nvkm_output *outp, *outt;
+       struct nvkm_connector *conn;
+       struct nvkm_output *outp;
 
        nvkm_event_fini(&disp->vblank);
        nvkm_event_fini(&disp->hpd);
 
-       if (disp->outp.next) {
-               list_for_each_entry_safe(outp, outt, &disp->outp, head) {
-                       nvkm_object_ref(NULL, (struct nvkm_object **)&outp);
-               }
+       while (!list_empty(&disp->outp)) {
+               outp = list_first_entry(&disp->outp, typeof(*outp), head);
+               list_del(&outp->head);
+               nvkm_output_del(&outp);
+       }
+
+       while (!list_empty(&disp->conn)) {
+               conn = list_first_entry(&disp->conn, typeof(*conn), head);
+               list_del(&conn->head);
+               nvkm_connector_del(&conn);
        }
 
        nvkm_engine_destroy(&disp->engine);
@@ -188,10 +186,12 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
                  const char *extname, int length, void **pobject)
 {
        struct nvkm_disp_impl *impl = (void *)oclass;
-       struct nvkm_bios *bios = nvkm_bios(parent);
+       struct nvkm_device *device = (void *)parent;
+       struct nvkm_bios *bios = device->bios;
        struct nvkm_disp *disp;
-       struct nvkm_oclass **sclass;
-       struct nvkm_object *object;
+       struct nvkm_connector *conn;
+       struct nvkm_output *outp, *outt, *pair;
+       struct nvbios_connE connE;
        struct dcb_output dcbE;
        u8  hpd = 0, ver, hdr;
        u32 data;
@@ -204,30 +204,124 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
                return ret;
 
        INIT_LIST_HEAD(&disp->outp);
+       INIT_LIST_HEAD(&disp->conn);
 
        /* create output objects for each display path in the vbios */
        i = -1;
        while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
+               const struct nvkm_disp_func_outp *outps;
+               int (*ctor)(struct nvkm_disp *, int, struct dcb_output *,
+                           struct nvkm_output **);
+
                if (dcbE.type == DCB_OUTPUT_UNUSED)
                        continue;
                if (dcbE.type == DCB_OUTPUT_EOL)
                        break;
-               data = dcbE.location << 4 | dcbE.type;
+               outp = NULL;
+
+               switch (dcbE.location) {
+               case 0: outps = &impl->outp.internal; break;
+               case 1: outps = &impl->outp.external; break;
+               default:
+                       nvkm_warn(&disp->engine.subdev,
+                                 "dcb %d locn %d unknown\n", i, dcbE.location);
+                       continue;
+               }
 
-               oclass = nvkm_output_oclass;
-               sclass = impl->outp;
-               while (sclass && sclass[0]) {
-                       if (sclass[0]->handle == data) {
-                               oclass = sclass[0];
-                               break;
+               switch (dcbE.type) {
+               case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break;
+               case DCB_OUTPUT_TV    : ctor = outps->tv  ; break;
+               case DCB_OUTPUT_TMDS  : ctor = outps->tmds; break;
+               case DCB_OUTPUT_LVDS  : ctor = outps->lvds; break;
+               case DCB_OUTPUT_DP    : ctor = outps->dp  ; break;
+               default:
+                       nvkm_warn(&disp->engine.subdev,
+                                 "dcb %d type %d unknown\n", i, dcbE.type);
+                       continue;
+               }
+
+               if (ctor)
+                       ret = ctor(disp, i, &dcbE, &outp);
+               else
+                       ret = -ENODEV;
+
+               if (ret) {
+                       if (ret == -ENODEV) {
+                               nvkm_debug(&disp->engine.subdev,
+                                          "dcb %d %d/%d not supported\n",
+                                          i, dcbE.location, dcbE.type);
+                               continue;
                        }
-                       sclass++;
+                       nvkm_error(&disp->engine.subdev,
+                                  "failed to create output %d\n", i);
+                       nvkm_output_del(&outp);
+                       continue;
                }
 
-               nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object);
+               list_add_tail(&outp->head, &disp->outp);
                hpd = max(hpd, (u8)(dcbE.connector + 1));
        }
 
+       /* create connector objects based on the outputs we support */
+       list_for_each_entry_safe(outp, outt, &disp->outp, head) {
+               /* bios data *should* give us the most useful information */
+               data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
+                                    &connE);
+
+               /* no bios connector data... */
+               if (!data) {
+                       /* heuristic: anything with the same ccb index is
+                        * considered to be on the same connector, any
+                        * output path without an associated ccb entry will
+                        * be put on its own connector
+                        */
+                       int ccb_index = outp->info.i2c_index;
+                       if (ccb_index != 0xf) {
+                               list_for_each_entry(pair, &disp->outp, head) {
+                                       if (pair->info.i2c_index == ccb_index) {
+                                               outp->conn = pair->conn;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       /* connector shared with another output path */
+                       if (outp->conn)
+                               continue;
+
+                       memset(&connE, 0x00, sizeof(connE));
+                       connE.type = DCB_CONNECTOR_NONE;
+                       i = -1;
+               } else {
+                       i = outp->info.connector;
+               }
+
+               /* check that we haven't already created this connector */
+               list_for_each_entry(conn, &disp->conn, head) {
+                       if (conn->index == outp->info.connector) {
+                               outp->conn = conn;
+                               break;
+                       }
+               }
+
+               if (outp->conn)
+                       continue;
+
+               /* apparently we need to create a new one! */
+               ret = nvkm_connector_new(disp, i, &connE, &outp->conn);
+               if (ret) {
+                       nvkm_error(&disp->engine.subdev,
+                                  "failed to create output %d conn: %d\n",
+                                  outp->index, ret);
+                       nvkm_connector_del(&outp->conn);
+                       list_del(&outp->head);
+                       nvkm_output_del(&outp);
+                       continue;
+               }
+
+               list_add_tail(&outp->conn->head, &disp->conn);
+       }
+
        ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
        if (ret)
                return ret;
index cf03e02..2eb55be 100644 (file)
@@ -33,13 +33,13 @@ static int
 nvkm_connector_hpd(struct nvkm_notify *notify)
 {
        struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
-       struct nvkm_disp *disp = nvkm_disp(conn);
-       struct nvkm_gpio *gpio = nvkm_gpio(conn);
+       struct nvkm_disp *disp = conn->disp;
+       struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
        const struct nvkm_gpio_ntfy_rep *line = notify->data;
        struct nvif_notify_conn_rep_v0 rep;
        int index = conn->index;
 
-       DBG("HPD: %d\n", line->mask);
+       CONN_DBG(conn, "HPD: %d", line->mask);
 
        if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
                rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
@@ -51,78 +51,58 @@ nvkm_connector_hpd(struct nvkm_notify *notify)
        return NVKM_NOTIFY_KEEP;
 }
 
-int
-_nvkm_connector_fini(struct nvkm_object *object, bool suspend)
+void
+nvkm_connector_fini(struct nvkm_connector *conn)
 {
-       struct nvkm_connector *conn = (void *)object;
        nvkm_notify_put(&conn->hpd);
-       return nvkm_object_fini(&conn->base, suspend);
 }
 
-int
-_nvkm_connector_init(struct nvkm_object *object)
+void
+nvkm_connector_init(struct nvkm_connector *conn)
 {
-       struct nvkm_connector *conn = (void *)object;
-       int ret = nvkm_object_init(&conn->base);
-       if (ret == 0)
-               nvkm_notify_get(&conn->hpd);
-       return ret;
+       nvkm_notify_get(&conn->hpd);
 }
 
 void
-_nvkm_connector_dtor(struct nvkm_object *object)
+nvkm_connector_del(struct nvkm_connector **pconn)
 {
-       struct nvkm_connector *conn = (void *)object;
-       nvkm_notify_fini(&conn->hpd);
-       nvkm_object_destroy(&conn->base);
+       struct nvkm_connector *conn = *pconn;
+       if (conn) {
+               nvkm_notify_fini(&conn->hpd);
+               kfree(*pconn);
+               *pconn = NULL;
+       }
 }
 
-int
-nvkm_connector_create_(struct nvkm_object *parent,
-                      struct nvkm_object *engine,
-                      struct nvkm_oclass *oclass,
-                      struct nvbios_connE *info, int index,
-                      int length, void **pobject)
+static void
+nvkm_connector_ctor(struct nvkm_disp *disp, int index,
+                   struct nvbios_connE *info, struct nvkm_connector *conn)
 {
        static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
-       struct nvkm_disp *disp = nvkm_disp(parent);
-       struct nvkm_gpio *gpio = nvkm_gpio(parent);
-       struct nvkm_connector *conn;
-       struct nvkm_output *outp;
+       struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
        struct dcb_gpio_func func;
        int ret;
 
-       list_for_each_entry(outp, &disp->outp, head) {
-               if (outp->conn && outp->conn->index == index) {
-                       atomic_inc(&nv_object(outp->conn)->refcount);
-                       *pobject = outp->conn;
-                       return 1;
-               }
-       }
-
-       ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
-       conn = *pobject;
-       if (ret)
-               return ret;
-
-       conn->info = *info;
+       conn->disp = disp;
        conn->index = index;
+       conn->info = *info;
 
-       DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
-           info->type, info->location, info->hpd, info->dp,
-           info->di, info->sr, info->lcdid);
+       CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x",
+                info->type, info->location, info->hpd, info->dp,
+                info->di, info->sr, info->lcdid);
 
        if ((info->hpd = ffs(info->hpd))) {
                if (--info->hpd >= ARRAY_SIZE(hpd)) {
-                       ERR("hpd %02x unknown\n", info->hpd);
-                       return 0;
+                       CONN_ERR(conn, "hpd %02x unknown", info->hpd);
+                       return;
                }
                info->hpd = hpd[info->hpd];
 
                ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
                if (ret) {
-                       ERR("func %02x lookup failed, %d\n", info->hpd, ret);
-                       return 0;
+                       CONN_ERR(conn, "func %02x lookup failed, %d",
+                                info->hpd, ret);
+                       return;
                }
 
                ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
@@ -134,41 +114,19 @@ nvkm_connector_create_(struct nvkm_object *parent,
                                       sizeof(struct nvkm_gpio_ntfy_rep),
                                       &conn->hpd);
                if (ret) {
-                       ERR("func %02x failed, %d\n", info->hpd, ret);
+                       CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret);
                } else {
-                       DBG("func %02x (HPD)\n", info->hpd);
+                       CONN_DBG(conn, "func %02x (HPD)", info->hpd);
                }
        }
-
-       return 0;
 }
 
 int
-_nvkm_connector_ctor(struct nvkm_object *parent,
-                    struct nvkm_object *engine,
-                    struct nvkm_oclass *oclass, void *info, u32 index,
-                    struct nvkm_object **pobject)
+nvkm_connector_new(struct nvkm_disp *disp, int index,
+                  struct nvbios_connE *info, struct nvkm_connector **pconn)
 {
-       struct nvkm_connector *conn;
-       int ret;
-
-       ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
-       *pobject = nv_object(conn);
-       if (ret)
-               return ret;
-
+       if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL)))
+               return -ENOMEM;
+       nvkm_connector_ctor(disp, index, info, *pconn);
        return 0;
 }
-
-struct nvkm_oclass *
-nvkm_connector_oclass = &(struct nvkm_connector_impl) {
-       .base = {
-               .handle = 0,
-               .ofuncs = &(struct nvkm_ofuncs) {
-                       .ctor = _nvkm_connector_ctor,
-                       .dtor = _nvkm_connector_dtor,
-                       .init = _nvkm_connector_init,
-                       .fini = _nvkm_connector_fini,
-               },
-       },
-}.base;
index 7789f70..ed32fe7 100644 (file)
@@ -1,58 +1,33 @@
 #ifndef __NVKM_DISP_CONN_H__
 #define __NVKM_DISP_CONN_H__
-#include <core/object.h>
-#include <core/notify.h>
+#include <engine/disp.h>
 
+#include <core/notify.h>
 #include <subdev/bios.h>
 #include <subdev/bios/conn.h>
 
 struct nvkm_connector {
-       struct nvkm_object base;
-       struct list_head head;
-
-       struct nvbios_connE info;
+       struct nvkm_disp *disp;
        int index;
+       struct nvbios_connE info;
 
        struct nvkm_notify hpd;
-};
 
-#define nvkm_connector_create(p,e,c,b,i,d)                                     \
-       nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_connector_destroy(d) ({                                           \
-       struct nvkm_connector *disp = (d);                                     \
-       _nvkm_connector_dtor(nv_object(disp));                                 \
-})
-#define nvkm_connector_init(d) ({                                              \
-       struct nvkm_connector *disp = (d);                                     \
-       _nvkm_connector_init(nv_object(disp));                                 \
-})
-#define nvkm_connector_fini(d,s) ({                                            \
-       struct nvkm_connector *disp = (d);                                     \
-       _nvkm_connector_fini(nv_object(disp), (s));                            \
-})
-
-int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *,
-                          struct nvkm_oclass *, struct nvbios_connE *,
-                          int, int, void **);
-
-int  _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *,
-                         struct nvkm_oclass *, void *, u32,
-                         struct nvkm_object **);
-void _nvkm_connector_dtor(struct nvkm_object *);
-int  _nvkm_connector_init(struct nvkm_object *);
-int  _nvkm_connector_fini(struct nvkm_object *, bool);
-
-struct nvkm_connector_impl {
-       struct nvkm_oclass base;
+       struct list_head head;
 };
 
-#ifndef MSG
-#define MSG(l,f,a...) do {                                                     \
-       struct nvkm_connector *_conn = (void *)conn;                           \
-       nvkm_##l(&nvkm_disp(_conn)->engine.subdev, "%02x:%02x%02x: "f, _conn->index,                      \
-                _conn->info.location, _conn->info.type, ##a);                 \
+int  nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *,
+                       struct nvkm_connector **);
+void nvkm_connector_del(struct nvkm_connector **);
+void nvkm_connector_init(struct nvkm_connector *);
+void nvkm_connector_fini(struct nvkm_connector *);
+
+#define CONN_MSG(c,l,f,a...) do {                                              \
+       struct nvkm_connector *_conn = (c);                                    \
+       nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n",     \
+                _conn->index, _conn->info.location, _conn->info.type, ##a);   \
 } while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
+#define CONN_ERR(c,f,a...) CONN_MSG((c), error, f, ##a)
+#define CONN_DBG(c,f,a...) CONN_MSG((c), debug, f, ##a)
+#define CONN_TRACE(c,f,a...) CONN_MSG((c), trace, f, ##a)
 #endif
index ddd4144..9bfa9e7 100644 (file)
@@ -112,3 +112,15 @@ nv50_dac_sense(NV50_DISP_MTHD_V1)
        args->v0.load = (loadval & 0x38000000) >> 27;
        return 0;
 }
+
+static const struct nvkm_output_func
+nv50_dac_output_func = {
+};
+
+int
+nv50_dac_output_new(struct nvkm_disp *disp, int index,
+                   struct dcb_output *dcbE, struct nvkm_output **poutp)
+{
+       return nvkm_output_new_(&nv50_dac_output_func, disp,
+                               index, dcbE, poutp);
+}
index d671da6..cf1ec5f 100644 (file)
@@ -48,12 +48,12 @@ struct dp_state {
 static int
 dp_set_link_config(struct dp_state *dp)
 {
-       struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
        struct nvkm_output_dp *outp = dp->outp;
-       struct nvkm_disp *disp = nvkm_disp(outp);
-       struct nvkm_bios *bios = nvkm_bios(disp);
+       struct nvkm_disp *disp = outp->base.disp;
+       struct nvkm_subdev *subdev = &disp->engine.subdev;
+       struct nvkm_bios *bios = subdev->device->bios;
        struct nvbios_init init = {
-               .subdev = nv_subdev(disp),
+               .subdev = subdev,
                .bios = bios,
                .offset = 0x0000,
                .outp = &outp->base.info,
@@ -64,7 +64,7 @@ dp_set_link_config(struct dp_state *dp)
        u8 sink[2];
        int ret;
 
-       DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
+       OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw);
 
        /* set desired link configuration on the source */
        if ((lnkcmp = dp->outp->info.lnkcmp)) {
@@ -81,16 +81,16 @@ dp_set_link_config(struct dp_state *dp)
                nvbios_exec(&init);
        }
 
-       ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
-                           outp->dpcd[DPCD_RC02] &
-                                      DPCD_RC02_ENHANCED_FRAME_CAP);
+       ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
+                                 outp->dpcd[DPCD_RC02] &
+                                            DPCD_RC02_ENHANCED_FRAME_CAP);
        if (ret) {
                if (ret < 0)
-                       ERR("lnk_ctl failed with %d\n", ret);
+                       OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret);
                return ret;
        }
 
-       impl->lnk_pwr(outp, dp->link_nr);
+       outp->func->lnk_pwr(outp, dp->link_nr);
 
        /* set desired link configuration on the sink */
        sink[0] = dp->link_bw / 27000;
@@ -104,12 +104,11 @@ dp_set_link_config(struct dp_state *dp)
 static void
 dp_set_training_pattern(struct dp_state *dp, u8 pattern)
 {
-       struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
        struct nvkm_output_dp *outp = dp->outp;
        u8 sink_tp;
 
-       DBG("training pattern %d\n", pattern);
-       impl->pattern(outp, pattern);
+       OUTP_DBG(&outp->base, "training pattern %d", pattern);
+       outp->func->pattern(outp, pattern);
 
        nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1);
        sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
@@ -120,7 +119,6 @@ dp_set_training_pattern(struct dp_state *dp, u8 pattern)
 static int
 dp_link_train_commit(struct dp_state *dp, bool pc)
 {
-       struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
        struct nvkm_output_dp *outp = dp->outp;
        int ret, i;
 
@@ -146,8 +144,9 @@ dp_link_train_commit(struct dp_state *dp, bool pc)
                dp->conf[i] = (lpre << 3) | lvsw;
                dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
 
-               DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
-               impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
+               OUTP_DBG(&outp->base, "config lane %d %02x %02x",
+                        i, dp->conf[i], lpc2);
+               outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
        }
 
        ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4);
@@ -182,9 +181,10 @@ dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
                ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1);
                if (ret)
                        dp->pc2stat = 0x00;
-               DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
+               OUTP_DBG(&outp->base, "status %6ph pc2 %02x",
+                        dp->stat, dp->pc2stat);
        } else {
-               DBG("status %6ph\n", dp->stat);
+               OUTP_DBG(&outp->base, "status %6ph", dp->stat);
        }
 
        return 0;
@@ -260,11 +260,11 @@ static void
 dp_link_train_init(struct dp_state *dp, bool spread)
 {
        struct nvkm_output_dp *outp = dp->outp;
-       struct nvkm_disp *disp = nvkm_disp(outp);
-       struct nvkm_bios *bios = nvkm_bios(disp);
+       struct nvkm_disp *disp = outp->base.disp;
+       struct nvkm_subdev *subdev = &disp->engine.subdev;
        struct nvbios_init init = {
-               .subdev = nv_subdev(disp),
-               .bios = bios,
+               .subdev = subdev,
+               .bios = subdev->device->bios,
                .outp = &outp->base.info,
                .crtc = -1,
                .execute = 1,
@@ -286,11 +286,11 @@ static void
 dp_link_train_fini(struct dp_state *dp)
 {
        struct nvkm_output_dp *outp = dp->outp;
-       struct nvkm_disp *disp = nvkm_disp(outp);
-       struct nvkm_bios *bios = nvkm_bios(disp);
+       struct nvkm_disp *disp = outp->base.disp;
+       struct nvkm_subdev *subdev = &disp->engine.subdev;
        struct nvbios_init init = {
-               .subdev = nv_subdev(disp),
-               .bios = bios,
+               .subdev = subdev,
+               .bios = subdev->device->bios,
                .outp = &outp->base.info,
                .crtc = -1,
                .execute = 1,
@@ -322,7 +322,7 @@ void
 nvkm_dp_train(struct work_struct *w)
 {
        struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
+       struct nv50_disp *disp = (void *)outp->base.disp;
        const struct dp_rates *cfg = nvkm_dp_rates;
        struct dp_state _dp = {
                .outp = outp,
@@ -334,7 +334,7 @@ nvkm_dp_train(struct work_struct *w)
                disp->sor.magic(&outp->base);
 
        /* bring capabilities within encoder limits */
-       if (nv_mclass(disp) < GF110_DISP)
+       if (disp->base.engine.subdev.device->chipset < 0xd0)
                outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
        if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
                outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
@@ -386,12 +386,12 @@ nvkm_dp_train(struct work_struct *w)
        /* finish link training and execute post-train script from vbios */
        dp_set_training_pattern(dp, 0);
        if (ret < 0)
-               ERR("link training failed\n");
+               OUTP_ERR(&outp->base, "link training failed");
 
        dp_link_train_fini(dp);
 
        /* signal completion and enable link interrupt handling */
-       DBG("training complete\n");
+       OUTP_DBG(&outp->base, "training complete");
        atomic_set(&outp->lt.done, 1);
        wake_up(&outp->lt.wait);
        nvkm_notify_get(&outp->irq);
index a080184..c8d3093 100644 (file)
@@ -262,8 +262,12 @@ g84_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.external.tmds = nv50_pior_output_new,
+       .base.outp.external.dp = nv50_pior_dp_new,
        .base.vblank = &nv50_disp_vblank_func,
-       .base.outp =  nv50_disp_outp_sclass,
        .mthd.core = &g84_disp_core_mthd_chan,
        .mthd.base = &g84_disp_base_mthd_chan,
        .mthd.ovly = &g84_disp_ovly_mthd_chan,
index 9082fb7..b190a07 100644 (file)
@@ -114,13 +114,6 @@ g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 }
 
 struct nvkm_oclass *
-g94_disp_outp_sclass[] = {
-       &nv50_pior_dp_impl.base.base,
-       &g94_sor_dp_impl.base.base,
-       NULL
-};
-
-struct nvkm_oclass *
 g94_disp_oclass = &(struct nv50_disp_impl) {
        .base.base.handle = NV_ENGINE(DISP, 0x88),
        .base.base.ofuncs = &(struct nvkm_ofuncs) {
@@ -129,8 +122,13 @@ g94_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = g94_sor_dp_new,
+       .base.outp.external.lvds = nv50_pior_output_new,
+       .base.outp.external.dp = nv50_pior_dp_new,
        .base.vblank = &nv50_disp_vblank_func,
-       .base.outp =  g94_disp_outp_sclass,
        .mthd.core = &g94_disp_core_mthd_chan,
        .mthd.base = &g84_disp_base_mthd_chan,
        .mthd.ovly = &g84_disp_ovly_mthd_chan,
index bf72996..4161326 100644 (file)
@@ -988,7 +988,7 @@ gf110_disp_intr_unk2_0(struct nv50_disp *disp, int head)
 
        /* see note in nv50_disp_intr_unk20_0() */
        if (outp && outp->info.type == DCB_OUTPUT_DP) {
-               struct nvkm_output_dp *outpdp = (void *)outp;
+               struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
                struct nvbios_init init = {
                        .subdev = nv_subdev(disp),
                        .bios = nvkm_bios(disp),
@@ -1101,7 +1101,7 @@ gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head)
                }
 
                if (nvkm_output_dp_train(outp, pclk, true))
-                       ERR("link not trained before attach\n");
+                       OUTP_ERR(outp, "link not trained before attach");
        } else {
                if (disp->sor.magic)
                        disp->sor.magic(outp);
@@ -1340,12 +1340,6 @@ gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 }
 
 struct nvkm_oclass *
-gf110_disp_outp_sclass[] = {
-       &gf110_sor_dp_impl.base.base,
-       NULL
-};
-
-struct nvkm_oclass *
 gf110_disp_oclass = &(struct nv50_disp_impl) {
        .base.base.handle = NV_ENGINE(DISP, 0x90),
        .base.base.ofuncs = &(struct nvkm_ofuncs) {
@@ -1354,8 +1348,11 @@ gf110_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = gf110_sor_dp_new,
        .base.vblank = &gf110_disp_vblank_func,
-       .base.outp =  gf110_disp_outp_sclass,
        .mthd.core = &gf110_disp_core_mthd_chan,
        .mthd.base = &gf110_disp_base_mthd_chan,
        .mthd.ovly = &gf110_disp_ovly_mthd_chan,
index baf2c28..ffd8e77 100644 (file)
@@ -259,8 +259,11 @@ gk104_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = gf110_sor_dp_new,
        .base.vblank = &gf110_disp_vblank_func,
-       .base.outp =  gf110_disp_outp_sclass,
        .mthd.core = &gk104_disp_core_mthd_chan,
        .mthd.base = &gf110_disp_base_mthd_chan,
        .mthd.ovly = &gk104_disp_ovly_mthd_chan,
index ee51b4f..ca2d6f1 100644 (file)
@@ -94,8 +94,11 @@ gk110_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = gf110_sor_dp_new,
        .base.vblank = &gf110_disp_vblank_func,
-       .base.outp =  gf110_disp_outp_sclass,
        .mthd.core = &gk104_disp_core_mthd_chan,
        .mthd.base = &gf110_disp_base_mthd_chan,
        .mthd.ovly = &gk104_disp_ovly_mthd_chan,
index 13a02ac..f841d82 100644 (file)
@@ -94,8 +94,11 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = gf110_sor_dp_new,
        .base.vblank = &gf110_disp_vblank_func,
-       .base.outp =  gf110_disp_outp_sclass,
        .mthd.core = &gk104_disp_core_mthd_chan,
        .mthd.base = &gf110_disp_base_mthd_chan,
        .mthd.ovly = &gk104_disp_ovly_mthd_chan,
index 89d9839..8da3174 100644 (file)
@@ -88,12 +88,6 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 }
 
 struct nvkm_oclass *
-gm204_disp_outp_sclass[] = {
-       &gm204_sor_dp_impl.base.base,
-       NULL
-};
-
-struct nvkm_oclass *
 gm204_disp_oclass = &(struct nv50_disp_impl) {
        .base.base.handle = NV_ENGINE(DISP, 0x07),
        .base.base.ofuncs = &(struct nvkm_ofuncs) {
@@ -102,8 +96,11 @@ gm204_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = gm204_sor_dp_new,
        .base.vblank = &gf110_disp_vblank_func,
-       .base.outp =  gm204_disp_outp_sclass,
        .mthd.core = &gk104_disp_core_mthd_chan,
        .mthd.base = &gf110_disp_base_mthd_chan,
        .mthd.ovly = &gk104_disp_ovly_mthd_chan,
index 65cf51f..7f9f3a0 100644 (file)
@@ -138,8 +138,12 @@ gt200_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.external.tmds = nv50_pior_output_new,
+       .base.outp.external.dp = nv50_pior_dp_new,
        .base.vblank = &nv50_disp_vblank_func,
-       .base.outp =  nv50_disp_outp_sclass,
        .mthd.core = &g84_disp_core_mthd_chan,
        .mthd.base = &g84_disp_base_mthd_chan,
        .mthd.ovly = &gt200_disp_ovly_mthd_chan,
index 0a2b794..ef6c713 100644 (file)
@@ -94,8 +94,13 @@ gt215_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.internal.dp = g94_sor_dp_new,
+       .base.outp.external.lvds = nv50_pior_output_new,
+       .base.outp.external.dp = nv50_pior_dp_new,
        .base.vblank = &nv50_disp_vblank_func,
-       .base.outp =  g94_disp_outp_sclass,
        .mthd.core = &g94_disp_core_mthd_chan,
        .mthd.base = &g84_disp_base_mthd_chan,
        .mthd.ovly = &g84_disp_ovly_mthd_chan,
index b07cb06..5079ea3 100644 (file)
@@ -1109,7 +1109,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
        }
                break;
        case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
-               struct nvkm_output_dp *outpdp = (void *)outp;
+               struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
                union {
                        struct nv50_disp_sor_dp_pwr_v0 v0;
                } *args = data;
@@ -1119,8 +1119,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
                                   args->v0.version, args->v0.state);
                        if (args->v0.state == 0) {
                                nvkm_notify_put(&outpdp->irq);
-                               ((struct nvkm_output_dp_impl *)nv_oclass(outp))
-                                       ->lnk_pwr(outpdp, 0);
+                               outpdp->func->lnk_pwr(outpdp, 0);
                                atomic_set(&outpdp->lt.done, 0);
                                return 0;
                        } else
@@ -1655,7 +1654,7 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head)
         * in a blank screen (SOR_PWR off/on can restore it)
         */
        if (outp && outp->info.type == DCB_OUTPUT_DP) {
-               struct nvkm_output_dp *outpdp = (void *)outp;
+               struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
                struct nvbios_init init = {
                        .subdev = nv_subdev(disp),
                        .bios = nvkm_bios(disp),
@@ -1855,7 +1854,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head)
                }
 
                if (nvkm_output_dp_train(outp, datarate / soff, true))
-                       ERR("link not trained before attach\n");
+                       OUTP_ERR(outp, "link not trained before attach");
        }
 
        exec_clkcmp(disp, head, 0, pclk, &conf);
@@ -2048,12 +2047,6 @@ nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 }
 
 struct nvkm_oclass *
-nv50_disp_outp_sclass[] = {
-       &nv50_pior_dp_impl.base.base,
-       NULL
-};
-
-struct nvkm_oclass *
 nv50_disp_oclass = &(struct nv50_disp_impl) {
        .base.base.handle = NV_ENGINE(DISP, 0x50),
        .base.base.ofuncs = &(struct nvkm_ofuncs) {
@@ -2062,8 +2055,12 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nvkm_disp_init,
                .fini = _nvkm_disp_fini,
        },
+       .base.outp.internal.crt = nv50_dac_output_new,
+       .base.outp.internal.tmds = nv50_sor_output_new,
+       .base.outp.internal.lvds = nv50_sor_output_new,
+       .base.outp.external.tmds = nv50_pior_output_new,
+       .base.outp.external.dp = nv50_pior_dp_new,
        .base.vblank = &nv50_disp_vblank_func,
-       .base.outp =  nv50_disp_outp_sclass,
        .mthd.core = &nv50_disp_core_mthd_chan,
        .mthd.base = &nv50_disp_base_mthd_chan,
        .mthd.ovly = &nv50_disp_ovly_mthd_chan,
index 24d3413..0d495d2 100644 (file)
@@ -214,7 +214,7 @@ extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
 extern struct nvkm_oclass *nv50_disp_outp_sclass[];
 
 extern struct nvkm_output_dp_impl g94_sor_dp_impl;
-u32 g94_sor_dp_lane_map(struct nv50_disp *, u8 lane);
+u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane);
 int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
 extern struct nvkm_oclass *g94_disp_outp_sclass[];
 
index 88a990e..bbe5ec0 100644 (file)
  * Authors: Ben Skeggs
  */
 #include "outp.h"
-#include "priv.h"
 
 #include <subdev/bios.h>
-#include <subdev/bios/conn.h>
 #include <subdev/bios/dcb.h>
 #include <subdev/i2c.h>
 
-int
-_nvkm_output_fini(struct nvkm_object *object, bool suspend)
+void
+nvkm_output_fini(struct nvkm_output *outp)
 {
-       struct nvkm_output *outp = (void *)object;
-       nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
-       return nvkm_object_fini(&outp->base, suspend);
+       if (outp->func->fini)
+               outp->func->fini(outp);
 }
 
-int
-_nvkm_output_init(struct nvkm_object *object)
+void
+nvkm_output_init(struct nvkm_output *outp)
 {
-       struct nvkm_output *outp = (void *)object;
-       int ret = nvkm_object_init(&outp->base);
-       if (ret == 0)
-               nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
-       return 0;
+       if (outp->func->init)
+               outp->func->init(outp);
 }
 
 void
-_nvkm_output_dtor(struct nvkm_object *object)
+nvkm_output_del(struct nvkm_output **poutp)
 {
-       struct nvkm_output *outp = (void *)object;
-       list_del(&outp->head);
-       nvkm_object_ref(NULL, (void *)&outp->conn);
-       nvkm_object_destroy(&outp->base);
+       struct nvkm_output *outp = *poutp;
+       if (outp && !WARN_ON(!outp->func)) {
+               if (outp->func->dtor)
+                       *poutp = outp->func->dtor(outp);
+               kfree(*poutp);
+               *poutp = NULL;
+       }
 }
 
-int
-nvkm_output_create_(struct nvkm_object *parent,
-                   struct nvkm_object *engine,
-                   struct nvkm_oclass *oclass,
-                   struct dcb_output *dcbE, int index,
-                   int length, void **pobject)
+void
+nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp,
+                int index, struct dcb_output *dcbE, struct nvkm_output *outp)
 {
-       struct nvkm_disp *disp = nvkm_disp(parent);
-       struct nvkm_bios *bios = nvkm_bios(parent);
-       struct nvkm_i2c *i2c = nvkm_i2c(parent);
-       struct nvbios_connE connE;
-       struct nvkm_output *outp;
-       u8  ver, hdr;
-       u32 data;
-       int ret;
+       struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
 
-       ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
-       outp = *pobject;
-       if (ret)
-               return ret;
-
-       outp->info = *dcbE;
+       outp->func = func;
+       outp->disp = disp;
        outp->index = index;
+       outp->info = *dcbE;
+       outp->i2c = nvkm_i2c_bus_find(i2c, dcbE->i2c_index);
        outp->or = ffs(outp->info.or) - 1;
 
-       DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
-           dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
-           dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
-           dcbE->bus, dcbE->heads);
-
-       outp->i2c = nvkm_i2c_bus_find(i2c, outp->info.i2c_index);
-
-       data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
-       if (!data) {
-               DBG("vbios connector data not found\n");
-               memset(&connE, 0x00, sizeof(connE));
-               connE.type = DCB_CONNECTOR_NONE;
-       }
-
-       ret = nvkm_object_ctor(parent, NULL, nvkm_connector_oclass,
-                              &connE, outp->info.connector,
-                              (struct nvkm_object **)&outp->conn);
-       if (ret < 0) {
-               ERR("error %d creating connector, disabling\n", ret);
-               return ret;
-       }
-
-       list_add_tail(&outp->head, &disp->outp);
-       return 0;
+       OUTP_DBG(outp, "type %02x loc %d or %d link %d con %x "
+                      "edid %x bus %d head %x",
+                outp->info.type, outp->info.location, outp->info.or,
+                outp->info.type >= 2 ? outp->info.sorconf.link : 0,
+                outp->info.connector, outp->info.i2c_index,
+                outp->info.bus, outp->info.heads);
 }
 
 int
-_nvkm_output_ctor(struct nvkm_object *parent,
-                 struct nvkm_object *engine,
-                 struct nvkm_oclass *oclass, void *dcbE, u32 index,
-                 struct nvkm_object **pobject)
+nvkm_output_new_(const struct nvkm_output_func *func,
+                struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
+                struct nvkm_output **poutp)
 {
-       struct nvkm_output *outp;
-       int ret;
-
-       ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
-       *pobject = nv_object(outp);
-       if (ret)
-               return ret;
+       if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL)))
+               return -ENOMEM;
 
+       nvkm_output_ctor(func, disp, index, dcbE, *poutp);
        return 0;
 }
-
-struct nvkm_oclass *
-nvkm_output_oclass = &(struct nvkm_output_impl) {
-       .base = {
-               .handle = 0,
-               .ofuncs = &(struct nvkm_ofuncs) {
-                       .ctor = _nvkm_output_ctor,
-                       .dtor = _nvkm_output_dtor,
-                       .init = _nvkm_output_init,
-                       .fini = _nvkm_output_fini,
-               },
-       },
-}.base;
index fb2ce7c..83d9d3f 100644 (file)
@@ -1,61 +1,51 @@
 #ifndef __NVKM_DISP_OUTP_H__
 #define __NVKM_DISP_OUTP_H__
-#include <core/object.h>
+#include <engine/disp.h>
 
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
 
 struct nvkm_output {
-       struct nvkm_object base;
-       struct list_head head;
-
-       struct dcb_output info;
+       const struct nvkm_output_func *func;
+       struct nvkm_disp *disp;
        int index;
-       int or;
+       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_connector *conn;
 };
 
-#define nvkm_output_create(p,e,c,b,i,d)                                        \
-       nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_output_destroy(d) ({                                              \
-       struct nvkm_output *_outp = (d);                                       \
-       _nvkm_output_dtor(nv_object(_outp));                                   \
-})
-#define nvkm_output_init(d) ({                                                 \
-       struct nvkm_output *_outp = (d);                                       \
-       _nvkm_output_init(nv_object(_outp));                                   \
-})
-#define nvkm_output_fini(d,s) ({                                               \
-       struct nvkm_output *_outp = (d);                                       \
-       _nvkm_output_fini(nv_object(_outp), (s));                              \
-})
-
-int nvkm_output_create_(struct nvkm_object *, struct nvkm_object *,
-                       struct nvkm_oclass *, struct dcb_output *,
-                       int, int, void **);
-
-int  _nvkm_output_ctor(struct nvkm_object *, struct nvkm_object *,
-                      struct nvkm_oclass *, void *, u32,
-                      struct nvkm_object **);
-void _nvkm_output_dtor(struct nvkm_object *);
-int  _nvkm_output_init(struct nvkm_object *);
-int  _nvkm_output_fini(struct nvkm_object *, bool);
-
-struct nvkm_output_impl {
-       struct nvkm_oclass base;
+struct nvkm_output_func {
+       void *(*dtor)(struct nvkm_output *);
+       void (*init)(struct nvkm_output *);
+       void (*fini)(struct nvkm_output *);
 };
 
-#ifndef MSG
-#define MSG(l,f,a...) do {                                                     \
-       struct nvkm_output *_outp = (void *)outp;                              \
-       nvkm_##l(&nvkm_disp(_outp)->engine.subdev, "%02x:%04x:%04x: "f, _outp->index,                       \
-              _outp->info.hasht, _outp->info.hashm, ##a);                     \
+void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *,
+                     int index, struct dcb_output *, struct nvkm_output *);
+int  nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *,
+                     int index, struct dcb_output *, struct nvkm_output **);
+void nvkm_output_del(struct nvkm_output **);
+void nvkm_output_init(struct nvkm_output *);
+void nvkm_output_fini(struct nvkm_output *);
+
+int  nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *,
+                        struct nvkm_output **);
+int  nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *,
+                        struct nvkm_output **);
+int  nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *,
+                         struct nvkm_output **);
+
+#define OUTP_MSG(o,l,f,a...) do {                                              \
+       struct nvkm_output *_outp = (o);                                       \
+       nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n",    \
+                _outp->index, _outp->info.hasht, _outp->info.hashm, ##a);     \
 } while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
+#define OUTP_ERR(o,f,a...) OUTP_MSG((o), error, f, ##a)
+#define OUTP_DBG(o,f,a...) OUTP_MSG((o), debug, f, ##a)
+#define OUTP_TRACE(o,f,a...) OUTP_MSG((o), trace, f, ##a)
 #endif
index dac6f17..3b7a9e7 100644 (file)
@@ -33,7 +33,7 @@
 int
 nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
 {
-       struct nvkm_output_dp *outp = (void *)base;
+       struct nvkm_output_dp *outp = nvkm_output_dp(base);
        bool retrain = true;
        u8 link[2], stat[3];
        u32 linkrate;
@@ -42,7 +42,8 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
        /* check that the link is trained at a high enough rate */
        ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2);
        if (ret) {
-               DBG("failed to read link config, assuming no sink\n");
+               OUTP_DBG(&outp->base,
+                        "failed to read link config, assuming no sink");
                goto done;
        }
 
@@ -50,14 +51,15 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
        linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */
        datarate = (datarate + 9) / 10; /* -> decakilobits */
        if (linkrate < datarate) {
-               DBG("link not trained at sufficient rate\n");
+               OUTP_DBG(&outp->base, "link not trained at sufficient rate");
                goto done;
        }
 
        /* check that link is still trained */
        ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3);
        if (ret) {
-               DBG("failed to read link status, assuming no sink\n");
+               OUTP_DBG(&outp->base,
+                        "failed to read link status, assuming no sink");
                goto done;
        }
 
@@ -67,13 +69,14 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
                        if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
                            !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
                            !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
-                               DBG("lane %d not equalised\n", lane);
+                               OUTP_DBG(&outp->base,
+                                        "lane %d not equalised", lane);
                                goto done;
                        }
                }
                retrain = false;
        } else {
-               DBG("no inter-lane alignment\n");
+               OUTP_DBG(&outp->base, "no inter-lane alignment");
        }
 
 done:
@@ -108,7 +111,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable)
 
        if (enable) {
                if (!outp->present) {
-                       DBG("aux power -> always\n");
+                       OUTP_DBG(&outp->base, "aux power -> always");
                        nvkm_i2c_aux_monitor(aux, true);
                        outp->present = true;
                }
@@ -121,7 +124,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable)
        }
 
        if (outp->present) {
-               DBG("aux power -> demand\n");
+               OUTP_DBG(&outp->base, "aux power -> demand");
                nvkm_i2c_aux_monitor(aux, false);
                outp->present = false;
        }
@@ -132,116 +135,108 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable)
 static int
 nvkm_output_dp_hpd(struct nvkm_notify *notify)
 {
-       struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
-       struct nvkm_output_dp *outp;
-       struct nvkm_disp *disp = nvkm_disp(conn);
        const struct nvkm_i2c_ntfy_rep *line = notify->data;
+       struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd);
+       struct nvkm_connector *conn = outp->base.conn;
+       struct nvkm_disp *disp = outp->base.disp;
        struct nvif_notify_conn_rep_v0 rep = {};
 
-       list_for_each_entry(outp, &disp->outp, base.head) {
-               if (outp->base.conn == conn &&
-                   outp->info.type == DCB_OUTPUT_DP) {
-                       DBG("HPD: %d\n", line->mask);
-                       nvkm_output_dp_enable(outp, true);
-
-                       if (line->mask & NVKM_I2C_UNPLUG)
-                               rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
-                       if (line->mask & NVKM_I2C_PLUG)
-                               rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
+       OUTP_DBG(&outp->base, "HPD: %d", line->mask);
+       nvkm_output_dp_enable(outp, true);
 
-                       nvkm_event_send(&disp->hpd, rep.mask, conn->index,
-                                       &rep, sizeof(rep));
-                       return NVKM_NOTIFY_KEEP;
-               }
-       }
+       if (line->mask & NVKM_I2C_UNPLUG)
+               rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
+       if (line->mask & NVKM_I2C_PLUG)
+               rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
 
-       WARN_ON(1);
-       return NVKM_NOTIFY_DROP;
+       nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep));
+       return NVKM_NOTIFY_KEEP;
 }
 
 static int
 nvkm_output_dp_irq(struct nvkm_notify *notify)
 {
-       struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
-       struct nvkm_disp *disp = nvkm_disp(outp);
        const struct nvkm_i2c_ntfy_rep *line = notify->data;
+       struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
+       struct nvkm_connector *conn = outp->base.conn;
+       struct nvkm_disp *disp = outp->base.disp;
        struct nvif_notify_conn_rep_v0 rep = {
                .mask = NVIF_NOTIFY_CONN_V0_IRQ,
        };
-       int index = outp->base.info.connector;
 
-       DBG("IRQ: %d\n", line->mask);
+       OUTP_DBG(&outp->base, "IRQ: %d", line->mask);
        nvkm_output_dp_train(&outp->base, 0, true);
 
-       nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+       nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep));
        return NVKM_NOTIFY_DROP;
 }
 
-int
-_nvkm_output_dp_fini(struct nvkm_object *object, bool suspend)
+static void
+nvkm_output_dp_fini(struct nvkm_output *base)
 {
-       struct nvkm_output_dp *outp = (void *)object;
+       struct nvkm_output_dp *outp = nvkm_output_dp(base);
+       nvkm_notify_put(&outp->hpd);
        nvkm_notify_put(&outp->irq);
+       flush_work(&outp->lt.work);
        nvkm_output_dp_enable(outp, false);
-       return nvkm_output_fini(&outp->base, suspend);
 }
 
-int
-_nvkm_output_dp_init(struct nvkm_object *object)
+static void
+nvkm_output_dp_init(struct nvkm_output *base)
 {
-       struct nvkm_output_dp *outp = (void *)object;
+       struct nvkm_output_dp *outp = nvkm_output_dp(base);
+       nvkm_notify_put(&outp->base.conn->hpd);
        nvkm_output_dp_enable(outp, true);
-       return nvkm_output_init(&outp->base);
+       nvkm_notify_get(&outp->hpd);
 }
 
-void
-_nvkm_output_dp_dtor(struct nvkm_object *object)
+static void *
+nvkm_output_dp_dtor(struct nvkm_output *base)
 {
-       struct nvkm_output_dp *outp = (void *)object;
+       struct nvkm_output_dp *outp = nvkm_output_dp(base);
+       nvkm_notify_fini(&outp->hpd);
        nvkm_notify_fini(&outp->irq);
-       nvkm_output_destroy(&outp->base);
+       return outp;
 }
 
+static const struct nvkm_output_func
+nvkm_output_dp_func = {
+       .dtor = nvkm_output_dp_dtor,
+       .init = nvkm_output_dp_init,
+       .fini = nvkm_output_dp_fini,
+};
+
 int
-nvkm_output_dp_create_(struct nvkm_object *parent,
-                      struct nvkm_object *engine,
-                      struct nvkm_oclass *oclass,
-                      struct dcb_output *info, int index,
-                      int length, void **pobject)
+nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func,
+                   struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
+                   struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp)
 {
-       struct nvkm_bios *bios = nvkm_bios(parent);
-       struct nvkm_i2c *i2c = nvkm_i2c(parent);
-       struct nvkm_output_dp *outp;
+       struct nvkm_device *device = disp->engine.subdev.device;
+       struct nvkm_bios *bios = device->bios;
+       struct nvkm_i2c *i2c = device->i2c;
        u8  hdr, cnt, len;
        u32 data;
        int ret;
 
-       ret = nvkm_output_create_(parent, engine, oclass, info, index,
-                                 length, pobject);
-       outp = *pobject;
-       if (ret)
-               return ret;
-
-       nvkm_notify_fini(&outp->base.conn->hpd);
-
-       /* access to the aux channel is not optional... */
-       //XXX: breaks anx support
-       outp->aux = nvkm_i2c_aux_find(i2c, outp->base.info.i2c_index);
+       nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base);
+       outp->func = func;
+       outp->aux = aux;
        if (!outp->aux) {
-               ERR("aux channel not found\n");
+               OUTP_ERR(&outp->base, "no aux");
                return -ENODEV;
        }
 
-       /* nor is the bios data for this output... */
+       /* bios data is not optional */
        data = nvbios_dpout_match(bios, outp->base.info.hasht,
                                  outp->base.info.hashm, &outp->version,
                                  &hdr, &cnt, &len, &outp->info);
        if (!data) {
-               ERR("no bios dp data\n");
+               OUTP_ERR(&outp->base, "no bios dp data");
                return -ENODEV;
        }
 
-       DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
+       OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x",
+                outp->version, hdr, cnt, len);
 
        /* link training */
        INIT_WORK(&outp->lt.work, nvkm_dp_train);
@@ -258,7 +253,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent,
                               sizeof(struct nvkm_i2c_ntfy_rep),
                               &outp->irq);
        if (ret) {
-               ERR("error monitoring aux irq event: %d\n", ret);
+               OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret);
                return ret;
        }
 
@@ -270,9 +265,9 @@ nvkm_output_dp_create_(struct nvkm_object *parent,
                               },
                               sizeof(struct nvkm_i2c_ntfy_req),
                               sizeof(struct nvkm_i2c_ntfy_rep),
-                              &outp->base.conn->hpd);
+                              &outp->hpd);
        if (ret) {
-               ERR("error monitoring aux hpd events: %d\n", ret);
+               OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret);
                return ret;
        }
 
@@ -280,18 +275,17 @@ nvkm_output_dp_create_(struct nvkm_object *parent,
 }
 
 int
-_nvkm_output_dp_ctor(struct nvkm_object *parent,
-                    struct nvkm_object *engine,
-                    struct nvkm_oclass *oclass, void *info, u32 index,
-                    struct nvkm_object **pobject)
+nvkm_output_dp_new_(const struct nvkm_output_dp_func *func,
+                   struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
+                   struct nvkm_output **poutp)
 {
+       struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
+       struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index);
        struct nvkm_output_dp *outp;
-       int ret;
 
-       ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
-       *pobject = nv_object(outp);
-       if (ret)
-               return ret;
+       if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL)))
+               return -ENOMEM;
+       *poutp = &outp->base;
 
-       return 0;
+       return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp);
 }
index f90e84c..1c1bd38 100644 (file)
@@ -1,5 +1,14 @@
 #ifndef __NVKM_DISP_OUTP_DP_H__
 #define __NVKM_DISP_OUTP_DP_H__
+#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base)
+#ifndef MSG
+#define MSG(l,f,a...)                                                          \
+       nvkm_##l(&outp->base.disp->engine.subdev, "%02x:%04x:%04x: "f,         \
+                outp->base.index, outp->base.info.hasht,                      \
+                outp->base.info.hashm, ##a)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
 #include "outp.h"
 
 #include <core/notify.h>
@@ -7,6 +16,7 @@
 #include <subdev/bios/dp.h>
 
 struct nvkm_output_dp {
+       const struct nvkm_output_dp_func *func;
        struct nvkm_output base;
 
        struct nvbios_dpout info;
@@ -15,6 +25,7 @@ struct nvkm_output_dp {
        struct nvkm_i2c_aux *aux;
 
        struct nvkm_notify irq;
+       struct nvkm_notify hpd;
        bool present;
        u8 dpcd[16];
 
@@ -25,34 +36,7 @@ struct nvkm_output_dp {
        } lt;
 };
 
-#define nvkm_output_dp_create(p,e,c,b,i,d)                                     \
-       nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_output_dp_destroy(d) ({                                           \
-       struct nvkm_output_dp *_outp = (d);                                    \
-       _nvkm_output_dp_dtor(nv_object(_outp));                                \
-})
-#define nvkm_output_dp_init(d) ({                                              \
-       struct nvkm_output_dp *_outp = (d);                                    \
-       _nvkm_output_dp_init(nv_object(_outp));                                \
-})
-#define nvkm_output_dp_fini(d,s) ({                                            \
-       struct nvkm_output_dp *_outp = (d);                                    \
-       _nvkm_output_dp_fini(nv_object(_outp), (s));                           \
-})
-
-int nvkm_output_dp_create_(struct nvkm_object *, struct nvkm_object *,
-                          struct nvkm_oclass *, struct dcb_output *,
-                          int, int, void **);
-
-int  _nvkm_output_dp_ctor(struct nvkm_object *, struct nvkm_object *,
-                         struct nvkm_oclass *, void *, u32,
-                         struct nvkm_object **);
-void _nvkm_output_dp_dtor(struct nvkm_object *);
-int  _nvkm_output_dp_init(struct nvkm_object *);
-int  _nvkm_output_dp_fini(struct nvkm_object *, bool);
-
-struct nvkm_output_dp_impl {
-       struct nvkm_output_impl base;
+struct nvkm_output_dp_func {
        int (*pattern)(struct nvkm_output_dp *, int);
        int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
        int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
@@ -60,4 +44,23 @@ struct nvkm_output_dp_impl {
 };
 
 int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
+
+int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *,
+                       int index, struct dcb_output *, struct nvkm_i2c_aux *,
+                       struct nvkm_output_dp *);
+int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *,
+                       int index, struct dcb_output *,
+                       struct nvkm_output **);
+
+int  nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *,
+                     struct nvkm_output **);
+
+int  g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
+                   struct nvkm_output **);
+
+int  gf110_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
+                     struct nvkm_output **);
+
+int  gm204_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
+                     struct nvkm_output **);
 #endif
index ac122d7..ab524bd 100644 (file)
@@ -21,8 +21,8 @@
  *
  * Authors: Ben Skeggs
  */
-#include "nv50.h"
 #include "outpdp.h"
+#include "nv50.h"
 
 #include <core/client.h>
 #include <subdev/i2c.h>
 #include <nvif/class.h>
 #include <nvif/unpack.h>
 
-/******************************************************************************
- * TMDS
- *****************************************************************************/
-
-static int
-nv50_pior_tmds_ctor(struct nvkm_object *parent,
-                   struct nvkm_object *engine,
-                   struct nvkm_oclass *oclass, void *info, u32 index,
-                   struct nvkm_object **pobject)
+int
+nv50_pior_power(NV50_DISP_MTHD_V1)
 {
-       struct nvkm_output *outp;
+       struct nvkm_device *device = disp->base.engine.subdev.device;
+       const u32 soff = outp->or * 0x800;
+       union {
+               struct nv50_disp_pior_pwr_v0 v0;
+       } *args = data;
+       u32 ctrl, type;
        int ret;
 
-       ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
-       *pobject = nv_object(outp);
-       if (ret)
+       nvif_ioctl(object, "disp pior pwr size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
+                          args->v0.version, args->v0.state, args->v0.type);
+               if (args->v0.type > 0x0f)
+                       return -EINVAL;
+               ctrl = !!args->v0.state;
+               type = args->v0.type;
+       } else
                return ret;
 
+       nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
+                       break;
+       );
+       nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
+       nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
+                       break;
+       );
+       disp->pior.type[outp->or] = type;
        return 0;
 }
 
-struct nvkm_output_impl
-nv50_pior_tmds_impl = {
-       .base.handle = DCB_OUTPUT_TMDS | 0x0100,
-       .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv50_pior_tmds_ctor,
-               .dtor = _nvkm_output_dtor,
-               .init = _nvkm_output_init,
-               .fini = _nvkm_output_fini,
-       },
-};
-
 /******************************************************************************
- * DisplayPort
+ * TMDS
  *****************************************************************************/
+static const struct nvkm_output_func
+nv50_pior_output_func = {
+};
 
-static int
-nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+int
+nv50_pior_output_new(struct nvkm_disp *disp, int index,
+                    struct dcb_output *dcbE, struct nvkm_output **poutp)
 {
-       return -ENODEV;
+       return nvkm_output_new_(&nv50_pior_output_func, disp,
+                               index, dcbE, poutp);
 }
 
+/******************************************************************************
+ * DisplayPort
+ *****************************************************************************/
 static int
-nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 {
        return 0;
 }
 
 static int
-nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
-       return nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef);
-}
-
-static int
-nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
+nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
 {
-       return -ENODEV;
+       return 0;
 }
 
 static int
-nv50_pior_dp_ctor(struct nvkm_object *parent,
-                 struct nvkm_object *engine,
-                 struct nvkm_oclass *oclass, void *info, u32 index,
-                 struct nvkm_object **pobject)
+nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp,
+                           int nr, int bw, bool ef)
 {
-       struct nvkm_i2c *i2c = nvkm_i2c(parent);
-       struct nvkm_output_dp *outp;
-       int ret;
-
-       ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
-       *pobject = nv_object(outp);
+       int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef);
        if (ret)
                return ret;
-
-       outp->aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(outp->base.info.extdev));
-       return 0;
+       return 1;
 }
 
-struct nvkm_output_dp_impl
-nv50_pior_dp_impl = {
-       .base.base.handle = DCB_OUTPUT_DP | 0x0010,
-       .base.base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv50_pior_dp_ctor,
-               .dtor = _nvkm_output_dp_dtor,
-               .init = _nvkm_output_dp_init,
-               .fini = _nvkm_output_dp_fini,
-       },
-       .pattern = nv50_pior_dp_pattern,
-       .lnk_pwr = nv50_pior_dp_lnk_pwr,
-       .lnk_ctl = nv50_pior_dp_lnk_ctl,
-       .drv_ctl = nv50_pior_dp_drv_ctl,
+static const struct nvkm_output_dp_func
+nv50_pior_output_dp_func = {
+       .pattern = nv50_pior_output_dp_pattern,
+       .lnk_pwr = nv50_pior_output_dp_lnk_pwr,
+       .lnk_ctl = nv50_pior_output_dp_lnk_ctl,
 };
 
-/******************************************************************************
- * General PIOR handling
- *****************************************************************************/
-
 int
-nv50_pior_power(NV50_DISP_MTHD_V1)
+nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
+                struct nvkm_output **poutp)
 {
-       struct nvkm_device *device = disp->base.engine.subdev.device;
-       const u32 soff = outp->or * 0x800;
-       union {
-               struct nv50_disp_pior_pwr_v0 v0;
-       } *args = data;
-       u32 ctrl, type;
-       int ret;
+       struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
+       struct nvkm_i2c_aux *aux =
+               nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev));
+       struct nvkm_output_dp *outp;
 
-       nvif_ioctl(object, "disp pior pwr size %d\n", size);
-       if (nvif_unpack(args->v0, 0, 0, false)) {
-               nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
-                          args->v0.version, args->v0.state, args->v0.type);
-               if (args->v0.type > 0x0f)
-                       return -EINVAL;
-               ctrl = !!args->v0.state;
-               type = args->v0.type;
-       } else
-               return ret;
+       if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL)))
+               return -ENOMEM;
+       *poutp = &outp->base;
 
-       nvkm_msec(device, 2000,
-               if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
-                       break;
-       );
-       nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
-       nvkm_msec(device, 2000,
-               if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
-                       break;
-       );
-       disp->pior.type[outp->or] = type;
-       return 0;
+       return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp,
+                                  index, dcbE, aux, outp);
 }
index 961ce8b..f1df297 100644 (file)
@@ -1,11 +1,28 @@
 #ifndef __NVKM_DISP_PRIV_H__
 #define __NVKM_DISP_PRIV_H__
 #include <engine/disp.h>
+#include "outp.h"
+#include "outpdp.h"
+
+struct nvkm_disp_func_outp {
+       int (* crt)(struct nvkm_disp *, int index, struct dcb_output *,
+                   struct nvkm_output **);
+       int (*  tv)(struct nvkm_disp *, int index, struct dcb_output *,
+                   struct nvkm_output **);
+       int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *,
+                   struct nvkm_output **);
+       int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *,
+                   struct nvkm_output **);
+       int (*  dp)(struct nvkm_disp *, int index, struct dcb_output *,
+                   struct nvkm_output **);
+};
 
 struct nvkm_disp_impl {
        struct nvkm_oclass base;
-       struct nvkm_oclass **outp;
-       struct nvkm_oclass **conn;
+       struct {
+               const struct nvkm_disp_func_outp internal;
+               const struct nvkm_disp_func_outp external;
+       } outp;
        const struct nvkm_event_func *vblank;
 };
 
index d921efe..1bb9d66 100644 (file)
@@ -38,15 +38,33 @@ g94_sor_loff(struct nvkm_output_dp *outp)
        return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
 }
 
+/*******************************************************************************
+ * TMDS/LVDS
+ ******************************************************************************/
+static const struct nvkm_output_func
+g94_sor_output_func = {
+};
+
+int
+g94_sor_output_new(struct nvkm_disp *disp, int index,
+                  struct dcb_output *dcbE, struct nvkm_output **poutp)
+{
+       return nvkm_output_new_(&g94_sor_output_func, disp,
+                               index, dcbE, poutp);
+}
+
+/*******************************************************************************
+ * DisplayPort
+ ******************************************************************************/
 u32
-g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane)
+g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane)
 {
        static const u8 gm100[] = { 0, 8, 16, 24 };
        static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
        static const u8   g94[] = { 16, 8, 0, 24 };
-       if (nv_device(disp)->chipset >= 0x110)
+       if (device->chipset >= 0x110)
                return gm100[lane];
-       if (nv_device(disp)->chipset == 0xaf)
+       if (device->chipset == 0xaf)
                return mcp89[lane];
        return g94[lane];
 }
@@ -54,8 +72,7 @@ g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane)
 static int
 g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 loff = g94_sor_loff(outp);
        nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24);
        return 0;
@@ -64,14 +81,13 @@ g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 int
 g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 soff = g94_sor_soff(outp);
        const u32 loff = g94_sor_loff(outp);
        u32 mask = 0, i;
 
        for (i = 0; i < nr; i++)
-               mask |= 1 << (g94_sor_dp_lane_map(disp, i) >> 3);
+               mask |= 1 << (g94_sor_dp_lane_map(device, i) >> 3);
 
        nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask);
        nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000);
@@ -85,8 +101,7 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
 static int
 g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 soff = g94_sor_soff(outp);
        const u32 loff = g94_sor_loff(outp);
        u32 dpctrl = 0x00000000;
@@ -106,10 +121,9 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
 static int
 g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        struct nvkm_bios *bios = device->bios;
-       const u32 shift = g94_sor_dp_lane_map(disp, ln);
+       const u32 shift = g94_sor_dp_lane_map(device, ln);
        const u32 loff = g94_sor_loff(outp);
        u32 addr, data[3];
        u8  ver, hdr, cnt, len;
@@ -118,12 +132,12 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
 
        addr = nvbios_dpout_match(bios, outp->base.info.hasht,
                                        outp->base.info.hashm,
-                                &ver, &hdr, &cnt, &len, &info);
+                                 &ver, &hdr, &cnt, &len, &info);
        if (!addr)
                return -ENODEV;
 
        addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
-                                &ver, &hdr, &cnt, &len, &ocfg);
+                                 &ver, &hdr, &cnt, &len, &ocfg);
        if (!addr)
                return -EINVAL;
 
@@ -138,17 +152,17 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
        return 0;
 }
 
-struct nvkm_output_dp_impl
-g94_sor_dp_impl = {
-       .base.base.handle = DCB_OUTPUT_DP,
-       .base.base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = _nvkm_output_dp_ctor,
-               .dtor = _nvkm_output_dp_dtor,
-               .init = _nvkm_output_dp_init,
-               .fini = _nvkm_output_dp_fini,
-       },
+static const struct nvkm_output_dp_func
+g94_sor_dp_func = {
        .pattern = g94_sor_dp_pattern,
        .lnk_pwr = g94_sor_dp_lnk_pwr,
        .lnk_ctl = g94_sor_dp_lnk_ctl,
        .drv_ctl = g94_sor_dp_drv_ctl,
 };
+
+int
+g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
+              struct nvkm_output **poutp)
+{
+       return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp);
+}
index 696bc64..7e5ef50 100644 (file)
@@ -39,8 +39,7 @@ gf110_sor_loff(struct nvkm_output_dp *outp)
 static int
 gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 loff = gf110_sor_loff(outp);
        nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
        return 0;
@@ -49,8 +48,7 @@ gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 int
 gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 soff = gf110_sor_soff(outp);
        const u32 loff = gf110_sor_loff(outp);
        u32 dpctrl = 0x00000000;
@@ -70,10 +68,9 @@ static int
 gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
                     int ln, int vs, int pe, int pc)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        struct nvkm_bios *bios = device->bios;
-       const u32 shift = g94_sor_dp_lane_map(disp, ln);
+       const u32 shift = g94_sor_dp_lane_map(device, ln);
        const u32 loff = gf110_sor_loff(outp);
        u32 addr, data[4];
        u8  ver, hdr, cnt, len;
@@ -104,17 +101,17 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
        return 0;
 }
 
-struct nvkm_output_dp_impl
-gf110_sor_dp_impl = {
-       .base.base.handle = DCB_OUTPUT_DP,
-       .base.base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = _nvkm_output_dp_ctor,
-               .dtor = _nvkm_output_dp_dtor,
-               .init = _nvkm_output_dp_init,
-               .fini = _nvkm_output_dp_fini,
-       },
+static const struct nvkm_output_dp_func
+gf110_sor_dp_func = {
        .pattern = gf110_sor_dp_pattern,
        .lnk_pwr = g94_sor_dp_lnk_pwr,
        .lnk_ctl = gf110_sor_dp_lnk_ctl,
        .drv_ctl = gf110_sor_dp_drv_ctl,
 };
+
+int
+gf110_sor_dp_new(struct nvkm_disp *disp, int index,
+                struct dcb_output *dcbE, struct nvkm_output **poutp)
+{
+       return nvkm_output_dp_new_(&gf110_sor_dp_func, disp, index, dcbE, poutp);
+}
index 8792dcf..5a35bf4 100644 (file)
@@ -41,8 +41,7 @@ gm204_sor_loff(struct nvkm_output_dp *outp)
 void
 gm204_sor_magic(struct nvkm_output *outp)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->disp->engine.subdev.device;
        const u32 soff = outp->or * 0x100;
        const u32 data = outp->or + 1;
        if (outp->info.sorconf.link & 1)
@@ -52,7 +51,7 @@ gm204_sor_magic(struct nvkm_output *outp)
 }
 
 static inline u32
-gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane)
+gm204_sor_dp_lane_map(struct nvkm_device *device, u8 lane)
 {
        return lane * 0x08;
 }
@@ -60,8 +59,7 @@ gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane)
 static int
 gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 soff = gm204_sor_soff(outp);
        const u32 data = 0x01010101 * pattern;
        if (outp->base.info.sorconf.link & 1)
@@ -74,14 +72,13 @@ gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 static int
 gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        const u32 soff = gm204_sor_soff(outp);
        const u32 loff = gm204_sor_loff(outp);
        u32 mask = 0, i;
 
        for (i = 0; i < nr; i++)
-               mask |= 1 << (gm204_sor_dp_lane_map(disp, i) >> 3);
+               mask |= 1 << (gm204_sor_dp_lane_map(device, i) >> 3);
 
        nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask);
        nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000);
@@ -96,10 +93,9 @@ static int
 gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
                     int ln, int vs, int pe, int pc)
 {
-       struct nv50_disp *disp = (void *)nvkm_disp(outp);
-       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_device *device = outp->base.disp->engine.subdev.device;
        struct nvkm_bios *bios = device->bios;
-       const u32 shift = gm204_sor_dp_lane_map(disp, ln);
+       const u32 shift = gm204_sor_dp_lane_map(device, ln);
        const u32 loff = gm204_sor_loff(outp);
        u32 addr, data[4];
        u8  ver, hdr, cnt, len;
@@ -131,17 +127,17 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
        return 0;
 }
 
-struct nvkm_output_dp_impl
-gm204_sor_dp_impl = {
-       .base.base.handle = DCB_OUTPUT_DP,
-       .base.base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = _nvkm_output_dp_ctor,
-               .dtor = _nvkm_output_dp_dtor,
-               .init = _nvkm_output_dp_init,
-               .fini = _nvkm_output_dp_fini,
-       },
+static const struct nvkm_output_dp_func
+gm204_sor_dp_func = {
        .pattern = gm204_sor_dp_pattern,
        .lnk_pwr = gm204_sor_dp_lnk_pwr,
        .lnk_ctl = gf110_sor_dp_lnk_ctl,
        .drv_ctl = gm204_sor_dp_drv_ctl,
 };
+
+int
+gm204_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
+                struct nvkm_output **poutp)
+{
+       return nvkm_output_dp_new_(&gm204_sor_dp_func, disp, index, dcbE, poutp);
+}
index 73ee036..29e0d2a 100644 (file)
@@ -65,3 +65,15 @@ nv50_sor_power(NV50_DISP_MTHD_V1)
        );
        return 0;
 }
+
+static const struct nvkm_output_func
+nv50_sor_output_func = {
+};
+
+int
+nv50_sor_output_new(struct nvkm_disp *disp, int index,
+                   struct dcb_output *dcbE, struct nvkm_output **poutp)
+{
+       return nvkm_output_new_(&nv50_sor_output_func, disp,
+                               index, dcbE, poutp);
+}