drm/nouveau/disp: split user classes out from engine implementations
[deliverable/linux.git] / drivers / gpu / drm / nouveau / nvkm / engine / disp / base.c
CommitLineData
1d7c71a3
BS
1/*
2 * Copyright 2013 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 */
878da15a
BS
24#include "priv.h"
25#include "conn.h"
26#include "outp.h"
27
28#include <core/notify.h>
29#include <subdev/bios.h>
30#include <subdev/bios/dcb.h>
1d7c71a3 31
80bc340b 32#include <nvif/class.h>
79ca2770 33#include <nvif/event.h>
878da15a 34#include <nvif/unpack.h>
7a014a87 35
79ca2770 36int
878da15a
BS
37nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size,
38 struct nvkm_notify *notify)
79ca2770 39{
878da15a 40 struct nvkm_disp *disp =
79ca2770
BS
41 container_of(notify->event, typeof(*disp), vblank);
42 union {
43 struct nvif_notify_head_req_v0 v0;
44 } *req = data;
45 int ret;
46
47 if (nvif_unpack(req->v0, 0, 0, false)) {
48 notify->size = sizeof(struct nvif_notify_head_rep_v0);
49 if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
50 notify->types = 1;
51 notify->index = req->v0.head;
52 return 0;
53 }
54 }
55
56 return ret;
57}
58
59void
878da15a 60nvkm_disp_vblank(struct nvkm_disp *disp, int head)
79ca2770
BS
61{
62 struct nvif_notify_head_rep_v0 rep = {};
63 nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
64}
65
7a014a87 66static int
878da15a
BS
67nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
68 struct nvkm_notify *notify)
7a014a87 69{
878da15a 70 struct nvkm_disp *disp =
79ca2770
BS
71 container_of(notify->event, typeof(*disp), hpd);
72 union {
73 struct nvif_notify_conn_req_v0 v0;
74 } *req = data;
7a014a87 75 struct nvkm_output *outp;
79ca2770
BS
76 int ret;
77
78 if (nvif_unpack(req->v0, 0, 0, false)) {
79 notify->size = sizeof(struct nvif_notify_conn_rep_v0);
80 list_for_each_entry(outp, &disp->outp, head) {
81 if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
82 if (ret = -ENODEV, outp->conn->hpd.event) {
83 notify->types = req->v0.mask;
84 notify->index = req->v0.conn;
85 ret = 0;
86 }
87 break;
88 }
7a014a87
BS
89 }
90 }
79ca2770
BS
91
92 return ret;
7a014a87 93}
377b1f16 94
79ca2770 95static const struct nvkm_event_func
878da15a
BS
96nvkm_disp_hpd_func = {
97 .ctor = nvkm_disp_hpd_ctor
79ca2770
BS
98};
99
80bc340b 100int
878da15a 101nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event)
80bc340b 102{
878da15a 103 struct nvkm_disp *disp = (void *)object->engine;
80bc340b
BS
104 switch (type) {
105 case NV04_DISP_NTFY_VBLANK:
106 *event = &disp->vblank;
107 return 0;
108 case NV04_DISP_NTFY_CONN:
109 *event = &disp->hpd;
110 return 0;
111 default:
112 break;
113 }
114 return -EINVAL;
115}
116
377b1f16 117int
878da15a 118_nvkm_disp_fini(struct nvkm_object *object, bool suspend)
377b1f16 119{
878da15a 120 struct nvkm_disp *disp = (void *)object;
f2c906fc 121 struct nvkm_connector *conn;
7a014a87 122 struct nvkm_output *outp;
7a014a87
BS
123
124 list_for_each_entry(outp, &disp->outp, head) {
f2c906fc 125 nvkm_output_fini(outp);
7a014a87
BS
126 }
127
f2c906fc
BS
128 list_for_each_entry(conn, &disp->conn, head) {
129 nvkm_connector_fini(conn);
7a014a87
BS
130 }
131
89c651e2 132 return nvkm_engine_fini_old(&disp->engine, suspend);
377b1f16
BS
133}
134
135int
878da15a 136_nvkm_disp_init(struct nvkm_object *object)
377b1f16 137{
878da15a 138 struct nvkm_disp *disp = (void *)object;
f2c906fc 139 struct nvkm_connector *conn;
7a014a87
BS
140 struct nvkm_output *outp;
141 int ret;
142
89c651e2 143 ret = nvkm_engine_init_old(&disp->engine);
7a014a87
BS
144 if (ret)
145 return ret;
146
f2c906fc
BS
147 list_for_each_entry(conn, &disp->conn, head) {
148 nvkm_connector_init(conn);
7a014a87
BS
149 }
150
f2c906fc
BS
151 list_for_each_entry(outp, &disp->outp, head) {
152 nvkm_output_init(outp);
7a014a87
BS
153 }
154
155 return ret;
377b1f16 156}
1d7c71a3
BS
157
158void
878da15a 159_nvkm_disp_dtor(struct nvkm_object *object)
1d7c71a3 160{
878da15a 161 struct nvkm_disp *disp = (void *)object;
f2c906fc
BS
162 struct nvkm_connector *conn;
163 struct nvkm_output *outp;
7a014a87 164
79ca2770
BS
165 nvkm_event_fini(&disp->vblank);
166 nvkm_event_fini(&disp->hpd);
7a014a87 167
f2c906fc
BS
168 while (!list_empty(&disp->outp)) {
169 outp = list_first_entry(&disp->outp, typeof(*outp), head);
170 list_del(&outp->head);
171 nvkm_output_del(&outp);
172 }
173
174 while (!list_empty(&disp->conn)) {
175 conn = list_first_entry(&disp->conn, typeof(*conn), head);
176 list_del(&conn->head);
177 nvkm_connector_del(&conn);
7a014a87
BS
178 }
179
fd166a18 180 nvkm_engine_destroy(&disp->engine);
1d7c71a3
BS
181}
182
183int
878da15a
BS
184nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
185 struct nvkm_oclass *oclass, int heads, const char *intname,
186 const char *extname, int length, void **pobject)
1d7c71a3 187{
878da15a 188 struct nvkm_disp_impl *impl = (void *)oclass;
f2c906fc
BS
189 struct nvkm_device *device = (void *)parent;
190 struct nvkm_bios *bios = device->bios;
878da15a 191 struct nvkm_disp *disp;
f2c906fc
BS
192 struct nvkm_connector *conn;
193 struct nvkm_output *outp, *outt, *pair;
194 struct nvbios_connE connE;
7a014a87
BS
195 struct dcb_output dcbE;
196 u8 hpd = 0, ver, hdr;
197 u32 data;
198 int ret, i;
1d7c71a3 199
878da15a
BS
200 ret = nvkm_engine_create_(parent, engine, oclass, true, intname,
201 extname, length, pobject);
1d7c71a3
BS
202 disp = *pobject;
203 if (ret)
204 return ret;
205
7a014a87 206 INIT_LIST_HEAD(&disp->outp);
f2c906fc 207 INIT_LIST_HEAD(&disp->conn);
7a014a87
BS
208
209 /* create output objects for each display path in the vbios */
210 i = -1;
211 while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
f2c906fc
BS
212 const struct nvkm_disp_func_outp *outps;
213 int (*ctor)(struct nvkm_disp *, int, struct dcb_output *,
214 struct nvkm_output **);
215
7a014a87
BS
216 if (dcbE.type == DCB_OUTPUT_UNUSED)
217 continue;
218 if (dcbE.type == DCB_OUTPUT_EOL)
219 break;
f2c906fc
BS
220 outp = NULL;
221
222 switch (dcbE.location) {
223 case 0: outps = &impl->outp.internal; break;
224 case 1: outps = &impl->outp.external; break;
225 default:
226 nvkm_warn(&disp->engine.subdev,
227 "dcb %d locn %d unknown\n", i, dcbE.location);
228 continue;
229 }
7a014a87 230
f2c906fc
BS
231 switch (dcbE.type) {
232 case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break;
233 case DCB_OUTPUT_TV : ctor = outps->tv ; break;
234 case DCB_OUTPUT_TMDS : ctor = outps->tmds; break;
235 case DCB_OUTPUT_LVDS : ctor = outps->lvds; break;
236 case DCB_OUTPUT_DP : ctor = outps->dp ; break;
237 default:
238 nvkm_warn(&disp->engine.subdev,
239 "dcb %d type %d unknown\n", i, dcbE.type);
240 continue;
241 }
242
243 if (ctor)
244 ret = ctor(disp, i, &dcbE, &outp);
245 else
246 ret = -ENODEV;
247
248 if (ret) {
249 if (ret == -ENODEV) {
250 nvkm_debug(&disp->engine.subdev,
251 "dcb %d %d/%d not supported\n",
252 i, dcbE.location, dcbE.type);
253 continue;
7a014a87 254 }
f2c906fc
BS
255 nvkm_error(&disp->engine.subdev,
256 "failed to create output %d\n", i);
257 nvkm_output_del(&outp);
258 continue;
7a014a87
BS
259 }
260
f2c906fc 261 list_add_tail(&outp->head, &disp->outp);
7a014a87
BS
262 hpd = max(hpd, (u8)(dcbE.connector + 1));
263 }
264
f2c906fc
BS
265 /* create connector objects based on the outputs we support */
266 list_for_each_entry_safe(outp, outt, &disp->outp, head) {
267 /* bios data *should* give us the most useful information */
268 data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
269 &connE);
270
271 /* no bios connector data... */
272 if (!data) {
273 /* heuristic: anything with the same ccb index is
274 * considered to be on the same connector, any
275 * output path without an associated ccb entry will
276 * be put on its own connector
277 */
278 int ccb_index = outp->info.i2c_index;
279 if (ccb_index != 0xf) {
280 list_for_each_entry(pair, &disp->outp, head) {
281 if (pair->info.i2c_index == ccb_index) {
282 outp->conn = pair->conn;
283 break;
284 }
285 }
286 }
287
288 /* connector shared with another output path */
289 if (outp->conn)
290 continue;
291
292 memset(&connE, 0x00, sizeof(connE));
293 connE.type = DCB_CONNECTOR_NONE;
294 i = -1;
295 } else {
296 i = outp->info.connector;
297 }
298
299 /* check that we haven't already created this connector */
300 list_for_each_entry(conn, &disp->conn, head) {
301 if (conn->index == outp->info.connector) {
302 outp->conn = conn;
303 break;
304 }
305 }
306
307 if (outp->conn)
308 continue;
309
310 /* apparently we need to create a new one! */
311 ret = nvkm_connector_new(disp, i, &connE, &outp->conn);
312 if (ret) {
313 nvkm_error(&disp->engine.subdev,
314 "failed to create output %d conn: %d\n",
315 outp->index, ret);
316 nvkm_connector_del(&outp->conn);
317 list_del(&outp->head);
318 nvkm_output_del(&outp);
319 continue;
320 }
321
322 list_add_tail(&outp->conn->head, &disp->conn);
323 }
324
878da15a 325 ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
7a014a87
BS
326 if (ret)
327 return ret;
328
79ca2770 329 ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
377b1f16
BS
330 if (ret)
331 return ret;
332
333 return 0;
1d7c71a3 334}
This page took 0.172282 seconds and 5 git commands to generate.