2 * Copyright 2013 Red Hat Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
31 #include <core/client.h>
32 #include <core/notify.h>
33 #include <core/oproxy.h>
34 #include <subdev/bios.h>
35 #include <subdev/bios/dcb.h>
37 #include <nvif/class.h>
38 #include <nvif/cl0046.h>
39 #include <nvif/event.h>
40 #include <nvif/unpack.h>
43 nvkm_disp_vblank_fini(struct nvkm_event
*event
, int type
, int id
)
45 struct nvkm_disp
*disp
= container_of(event
, typeof(*disp
), vblank
);
46 struct nvkm_head
*head
= nvkm_head_find(disp
, id
);
48 head
->func
->vblank_put(head
);
52 nvkm_disp_vblank_init(struct nvkm_event
*event
, int type
, int id
)
54 struct nvkm_disp
*disp
= container_of(event
, typeof(*disp
), vblank
);
55 struct nvkm_head
*head
= nvkm_head_find(disp
, id
);
57 head
->func
->vblank_get(head
);
61 nvkm_disp_vblank_ctor(struct nvkm_object
*object
, void *data
, u32 size
,
62 struct nvkm_notify
*notify
)
64 struct nvkm_disp
*disp
=
65 container_of(notify
->event
, typeof(*disp
), vblank
);
67 struct nvif_notify_head_req_v0 v0
;
71 if (!(ret
= nvif_unpack(ret
, &data
, &size
, req
->v0
, 0, 0, false))) {
72 notify
->size
= sizeof(struct nvif_notify_head_rep_v0
);
73 if (ret
= -ENXIO
, req
->v0
.head
<= disp
->vblank
.index_nr
) {
75 notify
->index
= req
->v0
.head
;
83 static const struct nvkm_event_func
84 nvkm_disp_vblank_func
= {
85 .ctor
= nvkm_disp_vblank_ctor
,
86 .init
= nvkm_disp_vblank_init
,
87 .fini
= nvkm_disp_vblank_fini
,
91 nvkm_disp_vblank(struct nvkm_disp
*disp
, int head
)
93 struct nvif_notify_head_rep_v0 rep
= {};
94 nvkm_event_send(&disp
->vblank
, 1, head
, &rep
, sizeof(rep
));
98 nvkm_disp_hpd_ctor(struct nvkm_object
*object
, void *data
, u32 size
,
99 struct nvkm_notify
*notify
)
101 struct nvkm_disp
*disp
=
102 container_of(notify
->event
, typeof(*disp
), hpd
);
104 struct nvif_notify_conn_req_v0 v0
;
106 struct nvkm_outp
*outp
;
109 if (!(ret
= nvif_unpack(ret
, &data
, &size
, req
->v0
, 0, 0, false))) {
110 notify
->size
= sizeof(struct nvif_notify_conn_rep_v0
);
111 list_for_each_entry(outp
, &disp
->outp
, head
) {
112 if (ret
= -ENXIO
, outp
->conn
->index
== req
->v0
.conn
) {
113 if (ret
= -ENODEV
, outp
->conn
->hpd
.event
) {
114 notify
->types
= req
->v0
.mask
;
115 notify
->index
= req
->v0
.conn
;
126 static const struct nvkm_event_func
127 nvkm_disp_hpd_func
= {
128 .ctor
= nvkm_disp_hpd_ctor
132 nvkm_disp_ntfy(struct nvkm_object
*object
, u32 type
, struct nvkm_event
**event
)
134 struct nvkm_disp
*disp
= nvkm_disp(object
->engine
);
136 case NV04_DISP_NTFY_VBLANK
:
137 *event
= &disp
->vblank
;
139 case NV04_DISP_NTFY_CONN
:
149 nvkm_disp_class_del(struct nvkm_oproxy
*oproxy
)
151 struct nvkm_disp
*disp
= nvkm_disp(oproxy
->base
.engine
);
152 mutex_lock(&disp
->engine
.subdev
.mutex
);
153 if (disp
->client
== oproxy
)
155 mutex_unlock(&disp
->engine
.subdev
.mutex
);
158 static const struct nvkm_oproxy_func
160 .dtor
[1] = nvkm_disp_class_del
,
164 nvkm_disp_class_new(struct nvkm_device
*device
,
165 const struct nvkm_oclass
*oclass
, void *data
, u32 size
,
166 struct nvkm_object
**pobject
)
168 const struct nvkm_disp_oclass
*sclass
= oclass
->engn
;
169 struct nvkm_disp
*disp
= nvkm_disp(oclass
->engine
);
170 struct nvkm_oproxy
*oproxy
;
173 ret
= nvkm_oproxy_new_(&nvkm_disp_class
, oclass
, &oproxy
);
176 *pobject
= &oproxy
->base
;
178 mutex_lock(&disp
->engine
.subdev
.mutex
);
180 mutex_unlock(&disp
->engine
.subdev
.mutex
);
183 disp
->client
= oproxy
;
184 mutex_unlock(&disp
->engine
.subdev
.mutex
);
186 return sclass
->ctor(disp
, oclass
, data
, size
, &oproxy
->object
);
189 static const struct nvkm_device_oclass
191 .ctor
= nvkm_disp_class_new
,
195 nvkm_disp_class_get(struct nvkm_oclass
*oclass
, int index
,
196 const struct nvkm_device_oclass
**class)
198 struct nvkm_disp
*disp
= nvkm_disp(oclass
->engine
);
200 const struct nvkm_disp_oclass
*root
= disp
->func
->root(disp
);
201 oclass
->base
= root
->base
;
203 *class = &nvkm_disp_sclass
;
210 nvkm_disp_intr(struct nvkm_engine
*engine
)
212 struct nvkm_disp
*disp
= nvkm_disp(engine
);
213 disp
->func
->intr(disp
);
217 nvkm_disp_fini(struct nvkm_engine
*engine
, bool suspend
)
219 struct nvkm_disp
*disp
= nvkm_disp(engine
);
220 struct nvkm_conn
*conn
;
221 struct nvkm_outp
*outp
;
223 list_for_each_entry(outp
, &disp
->outp
, head
) {
224 nvkm_outp_fini(outp
);
227 list_for_each_entry(conn
, &disp
->conn
, head
) {
228 nvkm_conn_fini(conn
);
235 nvkm_disp_init(struct nvkm_engine
*engine
)
237 struct nvkm_disp
*disp
= nvkm_disp(engine
);
238 struct nvkm_conn
*conn
;
239 struct nvkm_outp
*outp
;
241 list_for_each_entry(conn
, &disp
->conn
, head
) {
242 nvkm_conn_init(conn
);
245 list_for_each_entry(outp
, &disp
->outp
, head
) {
246 nvkm_outp_init(outp
);
253 nvkm_disp_oneinit(struct nvkm_engine
*engine
)
255 struct nvkm_disp
*disp
= nvkm_disp(engine
);
256 struct nvkm_subdev
*subdev
= &disp
->engine
.subdev
;
257 struct nvkm_bios
*bios
= subdev
->device
->bios
;
258 struct nvkm_outp
*outp
, *outt
, *pair
;
259 struct nvkm_conn
*conn
;
260 struct nvkm_head
*head
;
261 struct nvbios_connE connE
;
262 struct dcb_output dcbE
;
263 u8 hpd
= 0, ver
, hdr
;
267 /* Create output path objects for each VBIOS display path. */
269 while ((data
= dcb_outp_parse(bios
, ++i
, &ver
, &hdr
, &dcbE
))) {
270 if (ver
< 0x40) /* No support for chipsets prior to NV50. */
272 if (dcbE
.type
== DCB_OUTPUT_UNUSED
)
274 if (dcbE
.type
== DCB_OUTPUT_EOL
)
279 case DCB_OUTPUT_ANALOG
:
281 case DCB_OUTPUT_TMDS
:
282 case DCB_OUTPUT_LVDS
:
283 ret
= nvkm_outp_new(disp
, i
, &dcbE
, &outp
);
286 ret
= nvkm_dp_new(disp
, i
, &dcbE
, &outp
);
289 /* No support for WFD yet. */
293 nvkm_warn(subdev
, "dcb %d type %d unknown\n",
301 OUTP_ERR(outp
, "ctor failed: %d", ret
);
303 OUTP_DBG(outp
, "not supported");
304 nvkm_outp_del(&outp
);
307 nvkm_error(subdev
, "failed to create outp %d\n", i
);
311 list_add_tail(&outp
->head
, &disp
->outp
);
312 hpd
= max(hpd
, (u8
)(dcbE
.connector
+ 1));
315 /* Create connector objects based on available output paths. */
316 list_for_each_entry_safe(outp
, outt
, &disp
->outp
, head
) {
317 /* VBIOS data *should* give us the most useful information. */
318 data
= nvbios_connEp(bios
, outp
->info
.connector
, &ver
, &hdr
,
321 /* No bios connector data... */
323 /* Heuristic: anything with the same ccb index is
324 * considered to be on the same connector, any
325 * output path without an associated ccb entry will
326 * be put on its own connector.
328 int ccb_index
= outp
->info
.i2c_index
;
329 if (ccb_index
!= 0xf) {
330 list_for_each_entry(pair
, &disp
->outp
, head
) {
331 if (pair
->info
.i2c_index
== ccb_index
) {
332 outp
->conn
= pair
->conn
;
338 /* Connector shared with another output path. */
342 memset(&connE
, 0x00, sizeof(connE
));
343 connE
.type
= DCB_CONNECTOR_NONE
;
346 i
= outp
->info
.connector
;
349 /* Check that we haven't already created this connector. */
350 list_for_each_entry(conn
, &disp
->conn
, head
) {
351 if (conn
->index
== outp
->info
.connector
) {
360 /* Apparently we need to create a new one! */
361 ret
= nvkm_conn_new(disp
, i
, &connE
, &outp
->conn
);
363 nvkm_error(&disp
->engine
.subdev
,
364 "failed to create outp %d conn: %d\n",
366 nvkm_conn_del(&outp
->conn
);
367 list_del(&outp
->head
);
368 nvkm_outp_del(&outp
);
372 list_add_tail(&outp
->conn
->head
, &disp
->conn
);
375 ret
= nvkm_event_init(&nvkm_disp_hpd_func
, 3, hpd
, &disp
->hpd
);
380 list_for_each_entry(head
, &disp
->head
, head
)
381 i
= max(i
, head
->id
+ 1);
383 return nvkm_event_init(&nvkm_disp_vblank_func
, 1, i
, &disp
->vblank
);
387 nvkm_disp_dtor(struct nvkm_engine
*engine
)
389 struct nvkm_disp
*disp
= nvkm_disp(engine
);
390 struct nvkm_conn
*conn
;
391 struct nvkm_outp
*outp
;
394 if (disp
->func
->dtor
)
395 data
= disp
->func
->dtor(disp
);
397 nvkm_event_fini(&disp
->vblank
);
398 nvkm_event_fini(&disp
->hpd
);
400 while (!list_empty(&disp
->conn
)) {
401 conn
= list_first_entry(&disp
->conn
, typeof(*conn
), head
);
402 list_del(&conn
->head
);
403 nvkm_conn_del(&conn
);
406 while (!list_empty(&disp
->outp
)) {
407 outp
= list_first_entry(&disp
->outp
, typeof(*outp
), head
);
408 list_del(&outp
->head
);
409 nvkm_outp_del(&outp
);
412 while (!list_empty(&disp
->ior
)) {
413 struct nvkm_ior
*ior
=
414 list_first_entry(&disp
->ior
, typeof(*ior
), head
);
418 while (!list_empty(&disp
->head
)) {
419 struct nvkm_head
*head
=
420 list_first_entry(&disp
->head
, typeof(*head
), head
);
421 nvkm_head_del(&head
);
427 static const struct nvkm_engine_func
429 .dtor
= nvkm_disp_dtor
,
430 .oneinit
= nvkm_disp_oneinit
,
431 .init
= nvkm_disp_init
,
432 .fini
= nvkm_disp_fini
,
433 .intr
= nvkm_disp_intr
,
434 .base
.sclass
= nvkm_disp_class_get
,
438 nvkm_disp_ctor(const struct nvkm_disp_func
*func
, struct nvkm_device
*device
,
439 int index
, struct nvkm_disp
*disp
)
442 INIT_LIST_HEAD(&disp
->head
);
443 INIT_LIST_HEAD(&disp
->ior
);
444 INIT_LIST_HEAD(&disp
->outp
);
445 INIT_LIST_HEAD(&disp
->conn
);
446 return nvkm_engine_ctor(&nvkm_disp
, device
, index
, true, &disp
->engine
);
450 nvkm_disp_new_(const struct nvkm_disp_func
*func
, struct nvkm_device
*device
,
451 int index
, struct nvkm_disp
**pdisp
)
453 if (!(*pdisp
= kzalloc(sizeof(**pdisp
), GFP_KERNEL
)))
455 return nvkm_disp_ctor(func
, device
, index
, *pdisp
);