aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-16 00:36:15 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 02:10:36 -0400
commit7a014a872914a6bb5af8b67eba603f8546794ab9 (patch)
tree8d8290902034fcc337b26d4882448c8d05637fa6
parent20014cbe8b2b9921476531a051735ed3f932fb13 (diff)
drm/nouveau/disp: add internal representaion of output paths and connectors
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>
-rw-r--r--drivers/gpu/drm/nouveau/Makefile2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/base.c105
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/conn.c172
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/conn.h59
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outp.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outp.h59
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c66
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/priv.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/disp.h11
10 files changed, 619 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index d647e7487a0d..de2eada522a0 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -222,6 +222,8 @@ nouveau-y += core/engine/device/nvc0.o
222nouveau-y += core/engine/device/nve0.o 222nouveau-y += core/engine/device/nve0.o
223nouveau-y += core/engine/device/gm100.o 223nouveau-y += core/engine/device/gm100.o
224nouveau-y += core/engine/disp/base.o 224nouveau-y += core/engine/disp/base.o
225nouveau-y += core/engine/disp/conn.o
226nouveau-y += core/engine/disp/outp.o
225nouveau-y += core/engine/disp/nv04.o 227nouveau-y += core/engine/disp/nv04.o
226nouveau-y += core/engine/disp/nv50.o 228nouveau-y += core/engine/disp/nv50.o
227nouveau-y += core/engine/disp/nv84.o 229nouveau-y += core/engine/disp/nv84.o
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
index 7c34cf33be85..c41f656abe64 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
@@ -23,25 +23,86 @@
23 */ 23 */
24 24
25#include "priv.h" 25#include "priv.h"
26#include "outp.h"
27#include "conn.h"
28
29static int
30nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
31{
32 struct nouveau_disp *disp = event->priv;
33 struct nvkm_output *outp;
34 list_for_each_entry(outp, &disp->outp, head) {
35 if (outp->conn->index == index) {
36 if (outp->conn->hpd.event)
37 return 0;
38 break;
39 }
40 }
41 return -ENOSYS;
42}
26 43
27int 44int
28_nouveau_disp_fini(struct nouveau_object *object, bool suspend) 45_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
29{ 46{
30 struct nouveau_disp *disp = (void *)object; 47 struct nouveau_disp *disp = (void *)object;
48 struct nvkm_output *outp;
49 int ret;
50
51 list_for_each_entry(outp, &disp->outp, head) {
52 ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
53 if (ret && suspend)
54 goto fail_outp;
55 }
56
31 return nouveau_engine_fini(&disp->base, suspend); 57 return nouveau_engine_fini(&disp->base, suspend);
58
59fail_outp:
60 list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
61 nv_ofuncs(outp)->init(nv_object(outp));
62 }
63
64 return ret;
32} 65}
33 66
34int 67int
35_nouveau_disp_init(struct nouveau_object *object) 68_nouveau_disp_init(struct nouveau_object *object)
36{ 69{
37 return 0; 70 struct nouveau_disp *disp = (void *)object;
71 struct nvkm_output *outp;
72 int ret;
73
74 ret = nouveau_engine_init(&disp->base);
75 if (ret)
76 return ret;
77
78 list_for_each_entry(outp, &disp->outp, head) {
79 ret = nv_ofuncs(outp)->init(nv_object(outp));
80 if (ret)
81 goto fail_outp;
82 }
83
84 return ret;
85
86fail_outp:
87 list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
88 nv_ofuncs(outp)->fini(nv_object(outp), false);
89 }
90
91 return ret;
38} 92}
39 93
40void 94void
41_nouveau_disp_dtor(struct nouveau_object *object) 95_nouveau_disp_dtor(struct nouveau_object *object)
42{ 96{
43 struct nouveau_disp *disp = (void *)object; 97 struct nouveau_disp *disp = (void *)object;
98 struct nvkm_output *outp, *outt;
99
44 nouveau_event_destroy(&disp->vblank); 100 nouveau_event_destroy(&disp->vblank);
101
102 list_for_each_entry_safe(outp, outt, &disp->outp, head) {
103 nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
104 }
105
45 nouveau_engine_destroy(&disp->base); 106 nouveau_engine_destroy(&disp->base);
46} 107}
47 108
@@ -52,8 +113,15 @@ nouveau_disp_create_(struct nouveau_object *parent,
52 const char *intname, const char *extname, 113 const char *intname, const char *extname,
53 int length, void **pobject) 114 int length, void **pobject)
54{ 115{
116 struct nouveau_disp_impl *impl = (void *)oclass;
117 struct nouveau_bios *bios = nouveau_bios(parent);
55 struct nouveau_disp *disp; 118 struct nouveau_disp *disp;
56 int ret; 119 struct nouveau_oclass **sclass;
120 struct nouveau_object *object;
121 struct dcb_output dcbE;
122 u8 hpd = 0, ver, hdr;
123 u32 data;
124 int ret, i;
57 125
58 ret = nouveau_engine_create_(parent, engine, oclass, true, 126 ret = nouveau_engine_create_(parent, engine, oclass, true,
59 intname, extname, length, pobject); 127 intname, extname, length, pobject);
@@ -61,6 +129,39 @@ nouveau_disp_create_(struct nouveau_object *parent,
61 if (ret) 129 if (ret)
62 return ret; 130 return ret;
63 131
132 INIT_LIST_HEAD(&disp->outp);
133
134 /* create output objects for each display path in the vbios */
135 i = -1;
136 while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
137 if (dcbE.type == DCB_OUTPUT_UNUSED)
138 continue;
139 if (dcbE.type == DCB_OUTPUT_EOL)
140 break;
141 data = dcbE.location << 4 | dcbE.type;
142
143 oclass = nvkm_output_oclass;
144 sclass = impl->outp;
145 while (sclass && sclass[0]) {
146 if (sclass[0]->handle == data) {
147 oclass = sclass[0];
148 break;
149 }
150 sclass++;
151 }
152
153 nouveau_object_ctor(*pobject, *pobject, oclass,
154 &dcbE, i, &object);
155 hpd = max(hpd, (u8)(dcbE.connector + 1));
156 }
157
158 ret = nouveau_event_create(3, hpd, &disp->hpd);
159 if (ret)
160 return ret;
161
162 disp->hpd->priv = disp;
163 disp->hpd->check = nouveau_disp_hpd_check;
164
64 ret = nouveau_event_create(1, heads, &disp->vblank); 165 ret = nouveau_event_create(1, heads, &disp->vblank);
65 if (ret) 166 if (ret)
66 return ret; 167 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
index 000000000000..4ffbc70ecf5a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright 2014 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include <subdev/gpio.h>
26
27#include "conn.h"
28#include "outp.h"
29
30static void
31nvkm_connector_hpd_work(struct work_struct *w)
32{
33 struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work);
34 struct nouveau_disp *disp = nouveau_disp(conn);
35 struct nouveau_gpio *gpio = nouveau_gpio(conn);
36 u32 send = NVKM_HPD_UNPLUG;
37 if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index))
38 send = NVKM_HPD_PLUG;
39 nouveau_event_trigger(disp->hpd, send, conn->index);
40 nouveau_event_get(conn->hpd.event);
41}
42
43static int
44nvkm_connector_hpd(void *data, u32 type, int index)
45{
46 struct nvkm_connector *conn = data;
47 DBG("HPD: %d\n", type);
48 schedule_work(&conn->hpd.work);
49 return NVKM_EVENT_DROP;
50}
51
52int
53_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
54{
55 struct nvkm_connector *conn = (void *)object;
56 if (conn->hpd.event)
57 nouveau_event_put(conn->hpd.event);
58 return nouveau_object_fini(&conn->base, suspend);
59}
60
61int
62_nvkm_connector_init(struct nouveau_object *object)
63{
64 struct nvkm_connector *conn = (void *)object;
65 int ret = nouveau_object_init(&conn->base);
66 if (ret == 0) {
67 if (conn->hpd.event)
68 nouveau_event_get(conn->hpd.event);
69 }
70 return ret;
71}
72
73void
74_nvkm_connector_dtor(struct nouveau_object *object)
75{
76 struct nvkm_connector *conn = (void *)object;
77 nouveau_event_ref(NULL, &conn->hpd.event);
78 nouveau_object_destroy(&conn->base);
79}
80
81int
82nvkm_connector_create_(struct nouveau_object *parent,
83 struct nouveau_object *engine,
84 struct nouveau_oclass *oclass,
85 struct nvbios_connE *info, int index,
86 int length, void **pobject)
87{
88 static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
89 struct nouveau_gpio *gpio = nouveau_gpio(parent);
90 struct nouveau_disp *disp = (void *)engine;
91 struct nvkm_connector *conn;
92 struct nvkm_output *outp;
93 struct dcb_gpio_func func;
94 int ret;
95
96 list_for_each_entry(outp, &disp->outp, head) {
97 if (outp->conn && outp->conn->index == index) {
98 atomic_inc(&nv_object(outp->conn)->refcount);
99 *pobject = outp->conn;
100 return 1;
101 }
102 }
103
104 ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
105 conn = *pobject;
106 if (ret)
107 return ret;
108
109 conn->info = *info;
110 conn->index = index;
111
112 DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
113 info->type, info->location, info->hpd, info->dp,
114 info->di, info->sr, info->lcdid);
115
116 if ((info->hpd = ffs(info->hpd))) {
117 if (--info->hpd >= ARRAY_SIZE(hpd)) {
118 ERR("hpd %02x unknown\n", info->hpd);
119 goto done;
120 }
121 info->hpd = hpd[info->hpd];
122
123 ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
124 if (ret) {
125 ERR("func %02x lookup failed, %d\n", info->hpd, ret);
126 goto done;
127 }
128
129 ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED,
130 func.line, nvkm_connector_hpd,
131 conn, &conn->hpd.event);
132 if (ret) {
133 ERR("func %02x failed, %d\n", info->hpd, ret);
134 } else {
135 DBG("func %02x (HPD)\n", info->hpd);
136 }
137 }
138
139done:
140 INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
141 return 0;
142}
143
144int
145_nvkm_connector_ctor(struct nouveau_object *parent,
146 struct nouveau_object *engine,
147 struct nouveau_oclass *oclass, void *info, u32 index,
148 struct nouveau_object **pobject)
149{
150 struct nvkm_connector *conn;
151 int ret;
152
153 ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
154 *pobject = nv_object(conn);
155 if (ret)
156 return ret;
157
158 return 0;
159}
160
161struct nouveau_oclass *
162nvkm_connector_oclass = &(struct nvkm_connector_impl) {
163 .base = {
164 .handle = 0,
165 .ofuncs = &(struct nouveau_ofuncs) {
166 .ctor = _nvkm_connector_ctor,
167 .dtor = _nvkm_connector_dtor,
168 .init = _nvkm_connector_init,
169 .fini = _nvkm_connector_fini,
170 },
171 },
172}.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
index 000000000000..035ebeacbb1c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
@@ -0,0 +1,59 @@
1#ifndef __NVKM_DISP_CONN_H__
2#define __NVKM_DISP_CONN_H__
3
4#include "priv.h"
5
6struct nvkm_connector {
7 struct nouveau_object base;
8 struct list_head head;
9
10 struct nvbios_connE info;
11 int index;
12
13 struct {
14 struct nouveau_eventh *event;
15 struct work_struct work;
16 } hpd;
17};
18
19#define nvkm_connector_create(p,e,c,b,i,d) \
20 nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
21#define nvkm_connector_destroy(d) ({ \
22 struct nvkm_connector *disp = (d); \
23 _nvkm_connector_dtor(nv_object(disp)); \
24})
25#define nvkm_connector_init(d) ({ \
26 struct nvkm_connector *disp = (d); \
27 _nvkm_connector_init(nv_object(disp)); \
28})
29#define nvkm_connector_fini(d,s) ({ \
30 struct nvkm_connector *disp = (d); \
31 _nvkm_connector_fini(nv_object(disp), (s)); \
32})
33
34int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *,
35 struct nouveau_oclass *, struct nvbios_connE *,
36 int, int, void **);
37
38int _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *,
39 struct nouveau_oclass *, void *, u32,
40 struct nouveau_object **);
41void _nvkm_connector_dtor(struct nouveau_object *);
42int _nvkm_connector_init(struct nouveau_object *);
43int _nvkm_connector_fini(struct nouveau_object *, bool);
44
45struct nvkm_connector_impl {
46 struct nouveau_oclass base;
47};
48
49#ifndef MSG
50#define MSG(l,f,a...) do { \
51 struct nvkm_connector *_conn = (void *)conn; \
52 nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _conn->index, \
53 _conn->info.location, _conn->info.type, ##a); \
54} while(0)
55#define DBG(f,a...) MSG(debug, f, ##a)
56#define ERR(f,a...) MSG(error, f, ##a)
57#endif
58
59#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
index 48d59db47f0d..24cb180f73f0 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
@@ -11,6 +11,7 @@
11 11
12#include "dport.h" 12#include "dport.h"
13#include "priv.h" 13#include "priv.h"
14#include "outp.h"
14 15
15struct nv50_disp_impl { 16struct nv50_disp_impl {
16 struct nouveau_disp_impl base; 17 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
index 000000000000..ad9ba7ccec7f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
@@ -0,0 +1,137 @@
1/*
2 * Copyright 2014 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include <subdev/i2c.h>
26#include <subdev/bios.h>
27#include <subdev/bios/conn.h>
28
29#include "outp.h"
30
31int
32_nvkm_output_fini(struct nouveau_object *object, bool suspend)
33{
34 struct nvkm_output *outp = (void *)object;
35 nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
36 return nouveau_object_fini(&outp->base, suspend);
37}
38
39int
40_nvkm_output_init(struct nouveau_object *object)
41{
42 struct nvkm_output *outp = (void *)object;
43 int ret = nouveau_object_init(&outp->base);
44 if (ret == 0)
45 nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
46 return 0;
47}
48
49void
50_nvkm_output_dtor(struct nouveau_object *object)
51{
52 struct nvkm_output *outp = (void *)object;
53 list_del(&outp->head);
54 nouveau_object_ref(NULL, (void *)&outp->conn);
55 nouveau_object_destroy(&outp->base);
56}
57
58int
59nvkm_output_create_(struct nouveau_object *parent,
60 struct nouveau_object *engine,
61 struct nouveau_oclass *oclass,
62 struct dcb_output *dcbE, int index,
63 int length, void **pobject)
64{
65 struct nouveau_bios *bios = nouveau_bios(engine);
66 struct nouveau_i2c *i2c = nouveau_i2c(parent);
67 struct nouveau_disp *disp = (void *)engine;
68 struct nvbios_connE connE;
69 struct nvkm_output *outp;
70 u8 ver, hdr;
71 u32 data;
72 int ret;
73
74 ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
75 outp = *pobject;
76 if (ret)
77 return ret;
78
79 outp->info = *dcbE;
80 outp->index = index;
81
82 DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
83 dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
84 dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
85 dcbE->bus, dcbE->heads);
86
87 outp->port = i2c->find(i2c, outp->info.i2c_index);
88 outp->edid = outp->port;
89
90 data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
91 if (!data) {
92 DBG("vbios connector data not found\n");
93 memset(&connE, 0x00, sizeof(connE));
94 connE.type = DCB_CONNECTOR_NONE;
95 }
96
97 ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass,
98 &connE, outp->info.connector,
99 (struct nouveau_object **)&outp->conn);
100 if (ret < 0) {
101 ERR("error %d creating connector, disabling\n", ret);
102 return ret;
103 }
104
105 list_add_tail(&outp->head, &disp->outp);
106 return 0;
107}
108
109int
110_nvkm_output_ctor(struct nouveau_object *parent,
111 struct nouveau_object *engine,
112 struct nouveau_oclass *oclass, void *dcbE, u32 index,
113 struct nouveau_object **pobject)
114{
115 struct nvkm_output *outp;
116 int ret;
117
118 ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
119 *pobject = nv_object(outp);
120 if (ret)
121 return ret;
122
123 return 0;
124}
125
126struct nouveau_oclass *
127nvkm_output_oclass = &(struct nvkm_output_impl) {
128 .base = {
129 .handle = 0,
130 .ofuncs = &(struct nouveau_ofuncs) {
131 .ctor = _nvkm_output_ctor,
132 .dtor = _nvkm_output_dtor,
133 .init = _nvkm_output_init,
134 .fini = _nvkm_output_fini,
135 },
136 },
137}.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
index 000000000000..bc76fbf85710
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
@@ -0,0 +1,59 @@
1#ifndef __NVKM_DISP_OUTP_H__
2#define __NVKM_DISP_OUTP_H__
3
4#include "priv.h"
5
6struct nvkm_output {
7 struct nouveau_object base;
8 struct list_head head;
9
10 struct dcb_output info;
11 int index;
12
13 struct nouveau_i2c_port *port;
14 struct nouveau_i2c_port *edid;
15
16 struct nvkm_connector *conn;
17};
18
19#define nvkm_output_create(p,e,c,b,i,d) \
20 nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
21#define nvkm_output_destroy(d) ({ \
22 struct nvkm_output *_outp = (d); \
23 _nvkm_output_dtor(nv_object(_outp)); \
24})
25#define nvkm_output_init(d) ({ \
26 struct nvkm_output *_outp = (d); \
27 _nvkm_output_init(nv_object(_outp)); \
28})
29#define nvkm_output_fini(d,s) ({ \
30 struct nvkm_output *_outp = (d); \
31 _nvkm_output_fini(nv_object(_outp), (s)); \
32})
33
34int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *,
35 struct nouveau_oclass *, struct dcb_output *,
36 int, int, void **);
37
38int _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *,
39 struct nouveau_oclass *, void *, u32,
40 struct nouveau_object **);
41void _nvkm_output_dtor(struct nouveau_object *);
42int _nvkm_output_init(struct nouveau_object *);
43int _nvkm_output_fini(struct nouveau_object *, bool);
44
45struct nvkm_output_impl {
46 struct nouveau_oclass base;
47};
48
49#ifndef MSG
50#define MSG(l,f,a...) do { \
51 struct nvkm_output *_outp = (void *)outp; \
52 nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _outp->index, \
53 _outp->info.hasht, _outp->info.hashm, ##a); \
54} while(0)
55#define DBG(f,a...) MSG(debug, f, ##a)
56#define ERR(f,a...) MSG(error, f, ##a)
57#endif
58
59#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
index 2c8ce351b52d..c4d36edc3dfb 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
@@ -33,8 +33,43 @@
33#include "nv50.h" 33#include "nv50.h"
34 34
35/****************************************************************************** 35/******************************************************************************
36 * TMDS
37 *****************************************************************************/
38
39static int
40nv50_pior_tmds_ctor(struct nouveau_object *parent,
41 struct nouveau_object *engine,
42 struct nouveau_oclass *oclass, void *info, u32 index,
43 struct nouveau_object **pobject)
44{
45 struct nouveau_i2c *i2c = nouveau_i2c(parent);
46 struct nvkm_output *outp;
47 int ret;
48
49 ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
50 *pobject = nv_object(outp);
51 if (ret)
52 return ret;
53
54 outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
55 return 0;
56}
57
58struct nvkm_output_impl
59nv50_pior_tmds_impl = {
60 .base.handle = DCB_OUTPUT_TMDS | 0x0100,
61 .base.ofuncs = &(struct nouveau_ofuncs) {
62 .ctor = nv50_pior_tmds_ctor,
63 .dtor = _nvkm_output_dtor,
64 .init = _nvkm_output_init,
65 .fini = _nvkm_output_fini,
66 },
67};
68
69/******************************************************************************
36 * DisplayPort 70 * DisplayPort
37 *****************************************************************************/ 71 *****************************************************************************/
72
38static struct nouveau_i2c_port * 73static struct nouveau_i2c_port *
39nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) 74nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp)
40{ 75{
@@ -99,9 +134,40 @@ nv50_pior_dp_func = {
99 .drv_ctl = nv50_pior_dp_drv_ctl, 134 .drv_ctl = nv50_pior_dp_drv_ctl,
100}; 135};
101 136
137static int
138nv50_pior_dp_ctor(struct nouveau_object *parent,
139 struct nouveau_object *engine,
140 struct nouveau_oclass *oclass, void *info, u32 index,
141 struct nouveau_object **pobject)
142{
143 struct nouveau_i2c *i2c = nouveau_i2c(parent);
144 struct nvkm_output *outp;
145 int ret;
146
147 ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
148 *pobject = nv_object(outp);
149 if (ret)
150 return ret;
151
152 outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->info.extdev));
153 return 0;
154}
155
156struct nvkm_output_impl
157nv50_pior_dp_impl = {
158 .base.handle = DCB_OUTPUT_DP | 0x0100,
159 .base.ofuncs = &(struct nouveau_ofuncs) {
160 .ctor = nv50_pior_dp_ctor,
161 .dtor = _nvkm_output_dtor,
162 .init = _nvkm_output_init,
163 .fini = _nvkm_output_fini,
164 },
165};
166
102/****************************************************************************** 167/******************************************************************************
103 * General PIOR handling 168 * General PIOR handling
104 *****************************************************************************/ 169 *****************************************************************************/
170
105int 171int
106nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) 172nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data)
107{ 173{
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
index 66901d28a966..26e9a42569c7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
@@ -1,10 +1,16 @@
1#ifndef __NVKM_DISP_PRIV_H__ 1#ifndef __NVKM_DISP_PRIV_H__
2#define __NVKM_DISP_PRIV_H__ 2#define __NVKM_DISP_PRIV_H__
3 3
4#include <subdev/bios.h>
5#include <subdev/bios/dcb.h>
6#include <subdev/bios/conn.h>
7
4#include <engine/disp.h> 8#include <engine/disp.h>
5 9
6struct nouveau_disp_impl { 10struct nouveau_disp_impl {
7 struct nouveau_oclass base; 11 struct nouveau_oclass base;
12 struct nouveau_oclass **outp;
13 struct nouveau_oclass **conn;
8}; 14};
9 15
10#define nouveau_disp_create(p,e,c,h,i,x,d) \ 16#define nouveau_disp_create(p,e,c,h,i,x,d) \
@@ -30,4 +36,7 @@ void _nouveau_disp_dtor(struct nouveau_object *);
30int _nouveau_disp_init(struct nouveau_object *); 36int _nouveau_disp_init(struct nouveau_object *);
31int _nouveau_disp_fini(struct nouveau_object *, bool); 37int _nouveau_disp_fini(struct nouveau_object *, bool);
32 38
39extern struct nouveau_oclass *nvkm_output_oclass;
40extern struct nouveau_oclass *nvkm_connector_oclass;
41
33#endif 42#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
index 1089faec373f..fde842896806 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
@@ -6,8 +6,19 @@
6#include <core/device.h> 6#include <core/device.h>
7#include <core/event.h> 7#include <core/event.h>
8 8
9enum nvkm_hpd_event {
10 NVKM_HPD_PLUG = 1,
11 NVKM_HPD_UNPLUG = 2,
12 NVKM_HPD_IRQ = 4,
13 NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ)
14};
15
9struct nouveau_disp { 16struct nouveau_disp {
10 struct nouveau_engine base; 17 struct nouveau_engine base;
18
19 struct list_head outp;
20 struct nouveau_event *hpd;
21
11 struct nouveau_event *vblank; 22 struct nouveau_event *vblank;
12}; 23};
13 24