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.
26 #include <nvif/unpack.h>
27 #include <nvif/class.h>
28 #include <nvif/event.h>
35 nouveau_disp_vblank_ctor(void *data
, u32 size
, struct nvkm_notify
*notify
)
37 struct nouveau_disp
*disp
=
38 container_of(notify
->event
, typeof(*disp
), vblank
);
40 struct nvif_notify_head_req_v0 v0
;
44 if (nvif_unpack(req
->v0
, 0, 0, false)) {
45 notify
->size
= sizeof(struct nvif_notify_head_rep_v0
);
46 if (ret
= -ENXIO
, req
->v0
.head
<= disp
->vblank
.index_nr
) {
48 notify
->index
= req
->v0
.head
;
57 nouveau_disp_vblank(struct nouveau_disp
*disp
, int head
)
59 struct nvif_notify_head_rep_v0 rep
= {};
60 nvkm_event_send(&disp
->vblank
, 1, head
, &rep
, sizeof(rep
));
64 nouveau_disp_hpd_ctor(void *data
, u32 size
, struct nvkm_notify
*notify
)
66 struct nouveau_disp
*disp
=
67 container_of(notify
->event
, typeof(*disp
), hpd
);
69 struct nvif_notify_conn_req_v0 v0
;
71 struct nvkm_output
*outp
;
74 if (nvif_unpack(req
->v0
, 0, 0, false)) {
75 notify
->size
= sizeof(struct nvif_notify_conn_rep_v0
);
76 list_for_each_entry(outp
, &disp
->outp
, head
) {
77 if (ret
= -ENXIO
, outp
->conn
->index
== req
->v0
.conn
) {
78 if (ret
= -ENODEV
, outp
->conn
->hpd
.event
) {
79 notify
->types
= req
->v0
.mask
;
80 notify
->index
= req
->v0
.conn
;
91 static const struct nvkm_event_func
92 nouveau_disp_hpd_func
= {
93 .ctor
= nouveau_disp_hpd_ctor
97 nouveau_disp_ntfy(struct nouveau_object
*object
, u32 type
,
98 struct nvkm_event
**event
)
100 struct nouveau_disp
*disp
= (void *)object
->engine
;
102 case NV04_DISP_NTFY_VBLANK
:
103 *event
= &disp
->vblank
;
105 case NV04_DISP_NTFY_CONN
:
115 _nouveau_disp_fini(struct nouveau_object
*object
, bool suspend
)
117 struct nouveau_disp
*disp
= (void *)object
;
118 struct nvkm_output
*outp
;
121 list_for_each_entry(outp
, &disp
->outp
, head
) {
122 ret
= nv_ofuncs(outp
)->fini(nv_object(outp
), suspend
);
127 return nouveau_engine_fini(&disp
->base
, suspend
);
130 list_for_each_entry_continue_reverse(outp
, &disp
->outp
, head
) {
131 nv_ofuncs(outp
)->init(nv_object(outp
));
138 _nouveau_disp_init(struct nouveau_object
*object
)
140 struct nouveau_disp
*disp
= (void *)object
;
141 struct nvkm_output
*outp
;
144 ret
= nouveau_engine_init(&disp
->base
);
148 list_for_each_entry(outp
, &disp
->outp
, head
) {
149 ret
= nv_ofuncs(outp
)->init(nv_object(outp
));
157 list_for_each_entry_continue_reverse(outp
, &disp
->outp
, head
) {
158 nv_ofuncs(outp
)->fini(nv_object(outp
), false);
165 _nouveau_disp_dtor(struct nouveau_object
*object
)
167 struct nouveau_disp
*disp
= (void *)object
;
168 struct nvkm_output
*outp
, *outt
;
170 nvkm_event_fini(&disp
->vblank
);
171 nvkm_event_fini(&disp
->hpd
);
173 if (disp
->outp
.next
) {
174 list_for_each_entry_safe(outp
, outt
, &disp
->outp
, head
) {
175 nouveau_object_ref(NULL
, (struct nouveau_object
**)&outp
);
179 nouveau_engine_destroy(&disp
->base
);
183 nouveau_disp_create_(struct nouveau_object
*parent
,
184 struct nouveau_object
*engine
,
185 struct nouveau_oclass
*oclass
, int heads
,
186 const char *intname
, const char *extname
,
187 int length
, void **pobject
)
189 struct nouveau_disp_impl
*impl
= (void *)oclass
;
190 struct nouveau_bios
*bios
= nouveau_bios(parent
);
191 struct nouveau_disp
*disp
;
192 struct nouveau_oclass
**sclass
;
193 struct nouveau_object
*object
;
194 struct dcb_output dcbE
;
195 u8 hpd
= 0, ver
, hdr
;
199 ret
= nouveau_engine_create_(parent
, engine
, oclass
, true,
200 intname
, extname
, length
, pobject
);
205 INIT_LIST_HEAD(&disp
->outp
);
207 /* create output objects for each display path in the vbios */
209 while ((data
= dcb_outp_parse(bios
, ++i
, &ver
, &hdr
, &dcbE
))) {
210 if (dcbE
.type
== DCB_OUTPUT_UNUSED
)
212 if (dcbE
.type
== DCB_OUTPUT_EOL
)
214 data
= dcbE
.location
<< 4 | dcbE
.type
;
216 oclass
= nvkm_output_oclass
;
218 while (sclass
&& sclass
[0]) {
219 if (sclass
[0]->handle
== data
) {
226 nouveau_object_ctor(*pobject
, *pobject
, oclass
,
228 hpd
= max(hpd
, (u8
)(dcbE
.connector
+ 1));
231 ret
= nvkm_event_init(&nouveau_disp_hpd_func
, 3, hpd
, &disp
->hpd
);
235 ret
= nvkm_event_init(impl
->vblank
, 1, heads
, &disp
->vblank
);