2 * Copyright 2012 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.
30 #include <core/client.h>
31 #include <core/ramht.h>
32 #include <subdev/timer.h>
34 #include <nvif/class.h>
35 #include <nvif/cl5070.h>
36 #include <nvif/unpack.h>
39 nv50_disp_root_mthd_(struct nvkm_object
*object
, u32 mthd
, void *data
, u32 size
)
42 struct nv50_disp_mthd_v0 v0
;
43 struct nv50_disp_mthd_v1 v1
;
45 struct nv50_disp_root
*root
= nv50_disp_root(object
);
46 struct nv50_disp
*disp
= root
->disp
;
47 struct nvkm_outp
*temp
, *outp
= NULL
;
48 struct nvkm_head
*head
;
50 int hidx
, ret
= -ENOSYS
;
52 if (mthd
!= NV50_DISP_MTHD
)
55 nvif_ioctl(object
, "disp mthd size %d\n", size
);
56 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
57 nvif_ioctl(object
, "disp mthd vers %d mthd %02x head %d\n",
58 args
->v0
.version
, args
->v0
.method
, args
->v0
.head
);
59 mthd
= args
->v0
.method
;
62 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v1
, 1, 1, true))) {
63 nvif_ioctl(object
, "disp mthd vers %d mthd %02x "
64 "type %04x mask %04x\n",
65 args
->v1
.version
, args
->v1
.method
,
66 args
->v1
.hasht
, args
->v1
.hashm
);
67 mthd
= args
->v1
.method
;
68 type
= args
->v1
.hasht
;
69 mask
= args
->v1
.hashm
;
70 hidx
= ffs((mask
>> 8) & 0x0f) - 1;
74 if (!(head
= nvkm_head_find(&disp
->base
, hidx
)))
78 list_for_each_entry(temp
, &disp
->base
.outp
, head
) {
79 if ((temp
->info
.hasht
== type
) &&
80 (temp
->info
.hashm
& mask
) == mask
) {
90 case NV50_DISP_SCANOUTPOS
: {
91 return nvkm_head_mthd_scanoutpos(object
, head
, data
, size
);
97 switch (mthd
* !!outp
) {
98 case NV50_DISP_MTHD_V1_ACQUIRE
: {
100 struct nv50_disp_acquire_v0 v0
;
103 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
104 ret
= nvkm_outp_acquire(outp
, NVKM_OUTP_USER
);
106 args
->v0
.or = outp
->ior
->id
;
107 args
->v0
.link
= outp
->ior
->asy
.link
;
113 case NV50_DISP_MTHD_V1_RELEASE
:
114 nvkm_outp_release(outp
, NVKM_OUTP_USER
);
116 case NV50_DISP_MTHD_V1_DAC_LOAD
: {
118 struct nv50_disp_dac_load_v0 v0
;
121 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
122 if (args
->v0
.data
& 0xfff00000)
124 ret
= nvkm_outp_acquire(outp
, NVKM_OUTP_PRIV
);
127 ret
= outp
->ior
->func
->sense(outp
->ior
, args
->v0
.data
);
128 nvkm_outp_release(outp
, NVKM_OUTP_PRIV
);
137 case NV50_DISP_MTHD_V1_SOR_HDA_ELD
: {
139 struct nv50_disp_sor_hda_eld_v0 v0
;
141 struct nvkm_ior
*ior
= outp
->ior
;
144 nvif_ioctl(object
, "disp sor hda eld size %d\n", size
);
145 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
146 nvif_ioctl(object
, "disp sor hda eld vers %d\n",
153 if (!ior
->func
->hda
.hpd
)
156 if (size
&& args
->v0
.data
[0]) {
157 if (outp
->info
.type
== DCB_OUTPUT_DP
)
158 ior
->func
->dp
.audio(ior
, hidx
, true);
159 ior
->func
->hda
.hpd(ior
, hidx
, true);
160 ior
->func
->hda
.eld(ior
, data
, size
);
162 if (outp
->info
.type
== DCB_OUTPUT_DP
)
163 ior
->func
->dp
.audio(ior
, hidx
, false);
164 ior
->func
->hda
.hpd(ior
, hidx
, false);
170 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR
: {
172 struct nv50_disp_sor_hdmi_pwr_v0 v0
;
174 u8
*vendor
, vendor_size
;
178 nvif_ioctl(object
, "disp sor hdmi ctrl size %d\n", size
);
179 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
180 nvif_ioctl(object
, "disp sor hdmi ctrl vers %d state %d "
181 "max_ac_packet %d rekey %d\n",
182 args
->v0
.version
, args
->v0
.state
,
183 args
->v0
.max_ac_packet
, args
->v0
.rekey
);
184 if (args
->v0
.max_ac_packet
> 0x1f || args
->v0
.rekey
> 0x7f)
186 if ((args
->v0
.avi_infoframe_length
187 + args
->v0
.vendor_infoframe_length
) > size
)
190 if ((args
->v0
.avi_infoframe_length
191 + args
->v0
.vendor_infoframe_length
) < size
)
194 avi_size
= args
->v0
.avi_infoframe_length
;
195 vendor
= avi
+ avi_size
;
196 vendor_size
= args
->v0
.vendor_infoframe_length
;
200 if (!outp
->ior
->func
->hdmi
.ctrl
)
203 outp
->ior
->func
->hdmi
.ctrl(outp
->ior
, hidx
, args
->v0
.state
,
204 args
->v0
.max_ac_packet
,
205 args
->v0
.rekey
, avi
, avi_size
,
206 vendor
, vendor_size
);
210 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT
: {
212 struct nv50_disp_sor_lvds_script_v0 v0
;
215 nvif_ioctl(object
, "disp sor lvds script size %d\n", size
);
216 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
217 nvif_ioctl(object
, "disp sor lvds script "
218 "vers %d name %04x\n",
219 args
->v0
.version
, args
->v0
.script
);
220 disp
->sor
.lvdsconf
= args
->v0
.script
;
226 case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK
: {
227 struct nvkm_dp
*dp
= nvkm_dp(outp
);
229 struct nv50_disp_sor_dp_mst_link_v0 v0
;
232 nvif_ioctl(object
, "disp sor dp mst link size %d\n", size
);
233 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
234 nvif_ioctl(object
, "disp sor dp mst link vers %d state %d\n",
235 args
->v0
.version
, args
->v0
.state
);
236 dp
->lt
.mst
= !!args
->v0
.state
;
242 case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI
: {
244 struct nv50_disp_sor_dp_mst_vcpi_v0 v0
;
247 nvif_ioctl(object
, "disp sor dp mst vcpi size %d\n", size
);
248 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
249 nvif_ioctl(object
, "disp sor dp mst vcpi vers %d "
250 "slot %02x/%02x pbn %04x/%04x\n",
251 args
->v0
.version
, args
->v0
.start_slot
,
252 args
->v0
.num_slots
, args
->v0
.pbn
,
253 args
->v0
.aligned_pbn
);
254 if (!outp
->ior
->func
->dp
.vcpi
)
256 outp
->ior
->func
->dp
.vcpi(outp
->ior
, hidx
,
260 args
->v0
.aligned_pbn
);
274 nv50_disp_root_dmac_new_(const struct nvkm_oclass
*oclass
,
275 void *data
, u32 size
, struct nvkm_object
**pobject
)
277 const struct nv50_disp_dmac_oclass
*sclass
= oclass
->priv
;
278 struct nv50_disp_root
*root
= nv50_disp_root(oclass
->parent
);
279 return sclass
->ctor(sclass
->func
, sclass
->mthd
, root
, sclass
->chid
,
280 oclass
, data
, size
, pobject
);
284 nv50_disp_root_pioc_new_(const struct nvkm_oclass
*oclass
,
285 void *data
, u32 size
, struct nvkm_object
**pobject
)
287 const struct nv50_disp_pioc_oclass
*sclass
= oclass
->priv
;
288 struct nv50_disp_root
*root
= nv50_disp_root(oclass
->parent
);
289 return sclass
->ctor(sclass
->func
, sclass
->mthd
, root
, sclass
->chid
.ctrl
,
290 sclass
->chid
.user
, oclass
, data
, size
, pobject
);
294 nv50_disp_root_child_get_(struct nvkm_object
*object
, int index
,
295 struct nvkm_oclass
*sclass
)
297 struct nv50_disp_root
*root
= nv50_disp_root(object
);
299 if (index
< ARRAY_SIZE(root
->func
->dmac
)) {
300 sclass
->base
= root
->func
->dmac
[index
]->base
;
301 sclass
->priv
= root
->func
->dmac
[index
];
302 sclass
->ctor
= nv50_disp_root_dmac_new_
;
306 index
-= ARRAY_SIZE(root
->func
->dmac
);
308 if (index
< ARRAY_SIZE(root
->func
->pioc
)) {
309 sclass
->base
= root
->func
->pioc
[index
]->base
;
310 sclass
->priv
= root
->func
->pioc
[index
];
311 sclass
->ctor
= nv50_disp_root_pioc_new_
;
319 nv50_disp_root_fini_(struct nvkm_object
*object
, bool suspend
)
321 struct nv50_disp_root
*root
= nv50_disp_root(object
);
322 root
->func
->fini(root
);
327 nv50_disp_root_init_(struct nvkm_object
*object
)
329 struct nv50_disp_root
*root
= nv50_disp_root(object
);
330 struct nvkm_ior
*ior
;
333 ret
= root
->func
->init(root
);
337 /* Set 'normal' (ie. when it's attached to a head) state for
338 * each output resource to 'fully enabled'.
340 list_for_each_entry(ior
, &root
->disp
->base
.ior
, head
) {
341 ior
->func
->power(ior
, true, true, true, true, true);
348 nv50_disp_root_dtor_(struct nvkm_object
*object
)
350 struct nv50_disp_root
*root
= nv50_disp_root(object
);
351 nvkm_ramht_del(&root
->ramht
);
352 nvkm_gpuobj_del(&root
->instmem
);
356 static const struct nvkm_object_func
358 .dtor
= nv50_disp_root_dtor_
,
359 .init
= nv50_disp_root_init_
,
360 .fini
= nv50_disp_root_fini_
,
361 .mthd
= nv50_disp_root_mthd_
,
362 .ntfy
= nvkm_disp_ntfy
,
363 .sclass
= nv50_disp_root_child_get_
,
367 nv50_disp_root_new_(const struct nv50_disp_root_func
*func
,
368 struct nvkm_disp
*base
, const struct nvkm_oclass
*oclass
,
369 void *data
, u32 size
, struct nvkm_object
**pobject
)
371 struct nv50_disp
*disp
= nv50_disp(base
);
372 struct nv50_disp_root
*root
;
373 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
376 if (!(root
= kzalloc(sizeof(*root
), GFP_KERNEL
)))
378 *pobject
= &root
->object
;
380 nvkm_object_ctor(&nv50_disp_root_
, oclass
, &root
->object
);
384 ret
= nvkm_gpuobj_new(disp
->base
.engine
.subdev
.device
, 0x10000, 0x10000,
385 false, NULL
, &root
->instmem
);
389 return nvkm_ramht_new(device
, 0x1000, 0, root
->instmem
, &root
->ramht
);
393 nv50_disp_root_fini(struct nv50_disp_root
*root
)
395 struct nvkm_device
*device
= root
->disp
->base
.engine
.subdev
.device
;
396 /* disable all interrupts */
397 nvkm_wr32(device
, 0x610024, 0x00000000);
398 nvkm_wr32(device
, 0x610020, 0x00000000);
402 nv50_disp_root_init(struct nv50_disp_root
*root
)
404 struct nv50_disp
*disp
= root
->disp
;
405 struct nvkm_head
*head
;
406 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
410 /* The below segments of code copying values from one register to
411 * another appear to inform EVO of the display capabilities or
412 * something similar. NFI what the 0x614004 caps are for..
414 tmp
= nvkm_rd32(device
, 0x614004);
415 nvkm_wr32(device
, 0x610184, tmp
);
418 list_for_each_entry(head
, &disp
->base
.head
, head
) {
419 tmp
= nvkm_rd32(device
, 0x616100 + (head
->id
* 0x800));
420 nvkm_wr32(device
, 0x610190 + (head
->id
* 0x10), tmp
);
421 tmp
= nvkm_rd32(device
, 0x616104 + (head
->id
* 0x800));
422 nvkm_wr32(device
, 0x610194 + (head
->id
* 0x10), tmp
);
423 tmp
= nvkm_rd32(device
, 0x616108 + (head
->id
* 0x800));
424 nvkm_wr32(device
, 0x610198 + (head
->id
* 0x10), tmp
);
425 tmp
= nvkm_rd32(device
, 0x61610c + (head
->id
* 0x800));
426 nvkm_wr32(device
, 0x61019c + (head
->id
* 0x10), tmp
);
430 for (i
= 0; i
< disp
->func
->dac
.nr
; i
++) {
431 tmp
= nvkm_rd32(device
, 0x61a000 + (i
* 0x800));
432 nvkm_wr32(device
, 0x6101d0 + (i
* 0x04), tmp
);
436 for (i
= 0; i
< disp
->func
->sor
.nr
; i
++) {
437 tmp
= nvkm_rd32(device
, 0x61c000 + (i
* 0x800));
438 nvkm_wr32(device
, 0x6101e0 + (i
* 0x04), tmp
);
442 for (i
= 0; i
< disp
->func
->pior
.nr
; i
++) {
443 tmp
= nvkm_rd32(device
, 0x61e000 + (i
* 0x800));
444 nvkm_wr32(device
, 0x6101f0 + (i
* 0x04), tmp
);
447 /* steal display away from vbios, or something like that */
448 if (nvkm_rd32(device
, 0x610024) & 0x00000100) {
449 nvkm_wr32(device
, 0x610024, 0x00000100);
450 nvkm_mask(device
, 0x6194e8, 0x00000001, 0x00000000);
451 if (nvkm_msec(device
, 2000,
452 if (!(nvkm_rd32(device
, 0x6194e8) & 0x00000002))
458 /* point at display engine memory area (hash table, objects) */
459 nvkm_wr32(device
, 0x610010, (root
->instmem
->addr
>> 8) | 9);
461 /* enable supervisor interrupts, disable everything else */
462 nvkm_wr32(device
, 0x61002c, 0x00000370);
463 nvkm_wr32(device
, 0x610028, 0x00000000);
467 static const struct nv50_disp_root_func
469 .init
= nv50_disp_root_init
,
470 .fini
= nv50_disp_root_fini
,
472 &nv50_disp_core_oclass
,
473 &nv50_disp_base_oclass
,
474 &nv50_disp_ovly_oclass
,
477 &nv50_disp_oimm_oclass
,
478 &nv50_disp_curs_oclass
,
483 nv50_disp_root_new(struct nvkm_disp
*disp
, const struct nvkm_oclass
*oclass
,
484 void *data
, u32 size
, struct nvkm_object
**pobject
)
486 return nv50_disp_root_new_(&nv50_disp_root
, disp
, oclass
,
487 data
, size
, pobject
);
490 const struct nvkm_disp_oclass
491 nv50_disp_root_oclass
= {
492 .base
.oclass
= NV50_DISP
,
495 .ctor
= nv50_disp_root_new
,