drm/nouveau/disp: add internal representaion of output paths and connectors
authorBen Skeggs <bskeggs@redhat.com>
Fri, 16 May 2014 04:36:15 +0000 (14:36 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 11 Jun 2014 06:10:36 +0000 (16:10 +1000)
This will, at some point, be used to replace various bits and pieces of
code doing direct bios parsing.  For now, it'll just be used for some
DP improvements.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/engine/disp/base.c
drivers/gpu/drm/nouveau/core/engine/disp/conn.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/conn.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/outp.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/outp.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
drivers/gpu/drm/nouveau/core/engine/disp/priv.h
drivers/gpu/drm/nouveau/core/include/engine/disp.h

index d647e74..de2eada 100644 (file)
@@ -222,6 +222,8 @@ nouveau-y += core/engine/device/nvc0.o
 nouveau-y += core/engine/device/nve0.o
 nouveau-y += core/engine/device/gm100.o
 nouveau-y += core/engine/disp/base.o
+nouveau-y += core/engine/disp/conn.o
+nouveau-y += core/engine/disp/outp.o
 nouveau-y += core/engine/disp/nv04.o
 nouveau-y += core/engine/disp/nv50.o
 nouveau-y += core/engine/disp/nv84.o
index 7c34cf3..c41f656 100644 (file)
  */
 
 #include "priv.h"
+#include "outp.h"
+#include "conn.h"
+
+static int
+nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
+{
+       struct nouveau_disp *disp = event->priv;
+       struct nvkm_output *outp;
+       list_for_each_entry(outp, &disp->outp, head) {
+               if (outp->conn->index == index) {
+                       if (outp->conn->hpd.event)
+                               return 0;
+                       break;
+               }
+       }
+       return -ENOSYS;
+}
 
 int
 _nouveau_disp_fini(struct nouveau_object *object, bool suspend)
 {
        struct nouveau_disp *disp = (void *)object;
+       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;
+       }
+
        return nouveau_engine_fini(&disp->base, suspend);
+
+fail_outp:
+       list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
+               nv_ofuncs(outp)->init(nv_object(outp));
+       }
+
+       return ret;
 }
 
 int
 _nouveau_disp_init(struct nouveau_object *object)
 {
-       return 0;
+       struct nouveau_disp *disp = (void *)object;
+       struct nvkm_output *outp;
+       int ret;
+
+       ret = nouveau_engine_init(&disp->base);
+       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;
+       }
+
+       return ret;
+
+fail_outp:
+       list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
+               nv_ofuncs(outp)->fini(nv_object(outp), false);
+       }
+
+       return ret;
 }
 
 void
 _nouveau_disp_dtor(struct nouveau_object *object)
 {
        struct nouveau_disp *disp = (void *)object;
+       struct nvkm_output *outp, *outt;
+
        nouveau_event_destroy(&disp->vblank);
+
+       list_for_each_entry_safe(outp, outt, &disp->outp, head) {
+               nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
+       }
+
        nouveau_engine_destroy(&disp->base);
 }
 
@@ -52,8 +113,15 @@ nouveau_disp_create_(struct nouveau_object *parent,
                     const char *intname, const char *extname,
                     int length, void **pobject)
 {
+       struct nouveau_disp_impl *impl = (void *)oclass;
+       struct nouveau_bios *bios = nouveau_bios(parent);
        struct nouveau_disp *disp;
-       int ret;
+       struct nouveau_oclass **sclass;
+       struct nouveau_object *object;
+       struct dcb_output dcbE;
+       u8  hpd = 0, ver, hdr;
+       u32 data;
+       int ret, i;
 
        ret = nouveau_engine_create_(parent, engine, oclass, true,
                                     intname, extname, length, pobject);
@@ -61,6 +129,39 @@ nouveau_disp_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       INIT_LIST_HEAD(&disp->outp);
+
+       /* create output objects for each display path in the vbios */
+       i = -1;
+       while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
+               if (dcbE.type == DCB_OUTPUT_UNUSED)
+                       continue;
+               if (dcbE.type == DCB_OUTPUT_EOL)
+                       break;
+               data = dcbE.location << 4 | dcbE.type;
+
+               oclass = nvkm_output_oclass;
+               sclass = impl->outp;
+               while (sclass && sclass[0]) {
+                       if (sclass[0]->handle == data) {
+                               oclass = sclass[0];
+                               break;
+                       }
+                       sclass++;
+               }
+
+               nouveau_object_ctor(*pobject, *pobject, oclass,
+                                   &dcbE, i, &object);
+               hpd = max(hpd, (u8)(dcbE.connector + 1));
+       }
+
+       ret = nouveau_event_create(3, hpd, &disp->hpd);
+       if (ret)
+               return ret;
+
+       disp->hpd->priv = disp;
+       disp->hpd->check = nouveau_disp_hpd_check;
+
        ret = nouveau_event_create(1, heads, &disp->vblank);
        if (ret)
                return ret;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
new file mode 100644 (file)
index 0000000..4ffbc70
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/gpio.h>
+
+#include "conn.h"
+#include "outp.h"
+
+static void
+nvkm_connector_hpd_work(struct work_struct *w)
+{
+       struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work);
+       struct nouveau_disp *disp = nouveau_disp(conn);
+       struct nouveau_gpio *gpio = nouveau_gpio(conn);
+       u32 send = NVKM_HPD_UNPLUG;
+       if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index))
+               send = NVKM_HPD_PLUG;
+       nouveau_event_trigger(disp->hpd, send, conn->index);
+       nouveau_event_get(conn->hpd.event);
+}
+
+static int
+nvkm_connector_hpd(void *data, u32 type, int index)
+{
+       struct nvkm_connector *conn = data;
+       DBG("HPD: %d\n", type);
+       schedule_work(&conn->hpd.work);
+       return NVKM_EVENT_DROP;
+}
+
+int
+_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nvkm_connector *conn = (void *)object;
+       if (conn->hpd.event)
+               nouveau_event_put(conn->hpd.event);
+       return nouveau_object_fini(&conn->base, suspend);
+}
+
+int
+_nvkm_connector_init(struct nouveau_object *object)
+{
+       struct nvkm_connector *conn = (void *)object;
+       int ret = nouveau_object_init(&conn->base);
+       if (ret == 0) {
+               if (conn->hpd.event)
+                       nouveau_event_get(conn->hpd.event);
+       }
+       return ret;
+}
+
+void
+_nvkm_connector_dtor(struct nouveau_object *object)
+{
+       struct nvkm_connector *conn = (void *)object;
+       nouveau_event_ref(NULL, &conn->hpd.event);
+       nouveau_object_destroy(&conn->base);
+}
+
+int
+nvkm_connector_create_(struct nouveau_object *parent,
+                      struct nouveau_object *engine,
+                      struct nouveau_oclass *oclass,
+                      struct nvbios_connE *info, int index,
+                      int length, void **pobject)
+{
+       static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
+       struct nouveau_gpio *gpio = nouveau_gpio(parent);
+       struct nouveau_disp *disp = (void *)engine;
+       struct nvkm_connector *conn;
+       struct nvkm_output *outp;
+       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 = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
+       conn = *pobject;
+       if (ret)
+               return ret;
+
+       conn->info = *info;
+       conn->index = index;
+
+       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);
+
+       if ((info->hpd = ffs(info->hpd))) {
+               if (--info->hpd >= ARRAY_SIZE(hpd)) {
+                       ERR("hpd %02x unknown\n", info->hpd);
+                       goto done;
+               }
+               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);
+                       goto done;
+               }
+
+               ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED,
+                                       func.line, nvkm_connector_hpd,
+                                       conn, &conn->hpd.event);
+               if (ret) {
+                       ERR("func %02x failed, %d\n", info->hpd, ret);
+               } else {
+                       DBG("func %02x (HPD)\n", info->hpd);
+               }
+       }
+
+done:
+       INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
+       return 0;
+}
+
+int
+_nvkm_connector_ctor(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, void *info, u32 index,
+                    struct nouveau_object **pobject)
+{
+       struct nvkm_connector *conn;
+       int ret;
+
+       ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
+       *pobject = nv_object(conn);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+struct nouveau_oclass *
+nvkm_connector_oclass = &(struct nvkm_connector_impl) {
+       .base = {
+               .handle = 0,
+               .ofuncs = &(struct nouveau_ofuncs) {
+                       .ctor = _nvkm_connector_ctor,
+                       .dtor = _nvkm_connector_dtor,
+                       .init = _nvkm_connector_init,
+                       .fini = _nvkm_connector_fini,
+               },
+       },
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
new file mode 100644 (file)
index 0000000..035ebea
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __NVKM_DISP_CONN_H__
+#define __NVKM_DISP_CONN_H__
+
+#include "priv.h"
+
+struct nvkm_connector {
+       struct nouveau_object base;
+       struct list_head head;
+
+       struct nvbios_connE info;
+       int index;
+
+       struct {
+               struct nouveau_eventh *event;
+               struct work_struct work;
+       } 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 nouveau_object *, struct nouveau_object *,
+                          struct nouveau_oclass *, struct nvbios_connE *,
+                          int, int, void **);
+
+int  _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *,
+                         struct nouveau_oclass *, void *, u32,
+                         struct nouveau_object **);
+void _nvkm_connector_dtor(struct nouveau_object *);
+int  _nvkm_connector_init(struct nouveau_object *);
+int  _nvkm_connector_fini(struct nouveau_object *, bool);
+
+struct nvkm_connector_impl {
+       struct nouveau_oclass base;
+};
+
+#ifndef MSG
+#define MSG(l,f,a...) do {                                                     \
+       struct nvkm_connector *_conn = (void *)conn;                           \
+       nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _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
+
+#endif
index 48d59db..24cb180 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "dport.h"
 #include "priv.h"
+#include "outp.h"
 
 struct nv50_disp_impl {
        struct nouveau_disp_impl base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
new file mode 100644 (file)
index 0000000..ad9ba7c
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/i2c.h>
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+
+#include "outp.h"
+
+int
+_nvkm_output_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nvkm_output *outp = (void *)object;
+       nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
+       return nouveau_object_fini(&outp->base, suspend);
+}
+
+int
+_nvkm_output_init(struct nouveau_object *object)
+{
+       struct nvkm_output *outp = (void *)object;
+       int ret = nouveau_object_init(&outp->base);
+       if (ret == 0)
+               nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
+       return 0;
+}
+
+void
+_nvkm_output_dtor(struct nouveau_object *object)
+{
+       struct nvkm_output *outp = (void *)object;
+       list_del(&outp->head);
+       nouveau_object_ref(NULL, (void *)&outp->conn);
+       nouveau_object_destroy(&outp->base);
+}
+
+int
+nvkm_output_create_(struct nouveau_object *parent,
+                   struct nouveau_object *engine,
+                   struct nouveau_oclass *oclass,
+                   struct dcb_output *dcbE, int index,
+                   int length, void **pobject)
+{
+       struct nouveau_bios *bios = nouveau_bios(engine);
+       struct nouveau_i2c *i2c = nouveau_i2c(parent);
+       struct nouveau_disp *disp = (void *)engine;
+       struct nvbios_connE connE;
+       struct nvkm_output *outp;
+       u8  ver, hdr;
+       u32 data;
+       int ret;
+
+       ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
+       outp = *pobject;
+       if (ret)
+               return ret;
+
+       outp->info = *dcbE;
+       outp->index = index;
+
+       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->port = i2c->find(i2c, outp->info.i2c_index);
+       outp->edid = outp->port;
+
+       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 = nouveau_object_ctor(parent, engine, nvkm_connector_oclass,
+                                &connE, outp->info.connector,
+                                (struct nouveau_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;
+}
+
+int
+_nvkm_output_ctor(struct nouveau_object *parent,
+                 struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *dcbE, u32 index,
+                 struct nouveau_object **pobject)
+{
+       struct nvkm_output *outp;
+       int ret;
+
+       ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
+       *pobject = nv_object(outp);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+struct nouveau_oclass *
+nvkm_output_oclass = &(struct nvkm_output_impl) {
+       .base = {
+               .handle = 0,
+               .ofuncs = &(struct nouveau_ofuncs) {
+                       .ctor = _nvkm_output_ctor,
+                       .dtor = _nvkm_output_dtor,
+                       .init = _nvkm_output_init,
+                       .fini = _nvkm_output_fini,
+               },
+       },
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
new file mode 100644 (file)
index 0000000..bc76fbf
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __NVKM_DISP_OUTP_H__
+#define __NVKM_DISP_OUTP_H__
+
+#include "priv.h"
+
+struct nvkm_output {
+       struct nouveau_object base;
+       struct list_head head;
+
+       struct dcb_output info;
+       int index;
+
+       struct nouveau_i2c_port *port;
+       struct nouveau_i2c_port *edid;
+
+       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 nouveau_object *, struct nouveau_object *,
+                       struct nouveau_oclass *, struct dcb_output *,
+                       int, int, void **);
+
+int  _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *,
+                      struct nouveau_oclass *, void *, u32,
+                      struct nouveau_object **);
+void _nvkm_output_dtor(struct nouveau_object *);
+int  _nvkm_output_init(struct nouveau_object *);
+int  _nvkm_output_fini(struct nouveau_object *, bool);
+
+struct nvkm_output_impl {
+       struct nouveau_oclass base;
+};
+
+#ifndef MSG
+#define MSG(l,f,a...) do {                                                     \
+       struct nvkm_output *_outp = (void *)outp;                              \
+       nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _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
+
+#endif
index 2c8ce35..c4d36ed 100644 (file)
 #include "nv50.h"
 
 /******************************************************************************
+ * TMDS
+ *****************************************************************************/
+
+static int
+nv50_pior_tmds_ctor(struct nouveau_object *parent,
+                   struct nouveau_object *engine,
+                   struct nouveau_oclass *oclass, void *info, u32 index,
+                   struct nouveau_object **pobject)
+{
+       struct nouveau_i2c *i2c = nouveau_i2c(parent);
+       struct nvkm_output *outp;
+       int ret;
+
+       ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
+       *pobject = nv_object(outp);
+       if (ret)
+               return ret;
+
+       outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
+       return 0;
+}
+
+struct nvkm_output_impl
+nv50_pior_tmds_impl = {
+       .base.handle = DCB_OUTPUT_TMDS | 0x0100,
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_pior_tmds_ctor,
+               .dtor = _nvkm_output_dtor,
+               .init = _nvkm_output_init,
+               .fini = _nvkm_output_fini,
+       },
+};
+
+/******************************************************************************
  * DisplayPort
  *****************************************************************************/
+
 static struct nouveau_i2c_port *
 nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp)
 {
@@ -99,9 +134,40 @@ nv50_pior_dp_func = {
        .drv_ctl = nv50_pior_dp_drv_ctl,
 };
 
+static int
+nv50_pior_dp_ctor(struct nouveau_object *parent,
+                 struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *info, u32 index,
+                 struct nouveau_object **pobject)
+{
+       struct nouveau_i2c *i2c = nouveau_i2c(parent);
+       struct nvkm_output *outp;
+       int ret;
+
+       ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
+       *pobject = nv_object(outp);
+       if (ret)
+               return ret;
+
+       outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->info.extdev));
+       return 0;
+}
+
+struct nvkm_output_impl
+nv50_pior_dp_impl = {
+       .base.handle = DCB_OUTPUT_DP | 0x0100,
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_pior_dp_ctor,
+               .dtor = _nvkm_output_dtor,
+               .init = _nvkm_output_init,
+               .fini = _nvkm_output_fini,
+       },
+};
+
 /******************************************************************************
  * General PIOR handling
  *****************************************************************************/
+
 int
 nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data)
 {
index 66901d2..26e9a42 100644 (file)
@@ -1,10 +1,16 @@
 #ifndef __NVKM_DISP_PRIV_H__
 #define __NVKM_DISP_PRIV_H__
 
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/conn.h>
+
 #include <engine/disp.h>
 
 struct nouveau_disp_impl {
        struct nouveau_oclass base;
+       struct nouveau_oclass **outp;
+       struct nouveau_oclass **conn;
 };
 
 #define nouveau_disp_create(p,e,c,h,i,x,d)                                     \
@@ -30,4 +36,7 @@ void _nouveau_disp_dtor(struct nouveau_object *);
 int  _nouveau_disp_init(struct nouveau_object *);
 int  _nouveau_disp_fini(struct nouveau_object *, bool);
 
+extern struct nouveau_oclass *nvkm_output_oclass;
+extern struct nouveau_oclass *nvkm_connector_oclass;
+
 #endif
index 1089fae..fde8428 100644 (file)
@@ -6,8 +6,19 @@
 #include <core/device.h>
 #include <core/event.h>
 
+enum nvkm_hpd_event {
+       NVKM_HPD_PLUG = 1,
+       NVKM_HPD_UNPLUG = 2,
+       NVKM_HPD_IRQ = 4,
+       NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ)
+};
+
 struct nouveau_disp {
        struct nouveau_engine base;
+
+       struct list_head outp;
+       struct nouveau_event *hpd;
+
        struct nouveau_event *vblank;
 };