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.
27 #include <core/client.h>
28 #include <core/ramht.h>
29 #include <subdev/timer.h>
31 #include <nvif/class.h>
32 #include <nvif/cl5070.h>
33 #include <nvif/unpack.h>
36 nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0
)
38 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
39 const u32 blanke
= nvkm_rd32(device
, 0x610aec + (head
* 0x540));
40 const u32 blanks
= nvkm_rd32(device
, 0x610af4 + (head
* 0x540));
41 const u32 total
= nvkm_rd32(device
, 0x610afc + (head
* 0x540));
43 struct nv50_disp_scanoutpos_v0 v0
;
47 nvif_ioctl(object
, "disp scanoutpos size %d\n", size
);
48 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
49 nvif_ioctl(object
, "disp scanoutpos vers %d\n",
51 args
->v0
.vblanke
= (blanke
& 0xffff0000) >> 16;
52 args
->v0
.hblanke
= (blanke
& 0x0000ffff);
53 args
->v0
.vblanks
= (blanks
& 0xffff0000) >> 16;
54 args
->v0
.hblanks
= (blanks
& 0x0000ffff);
55 args
->v0
.vtotal
= ( total
& 0xffff0000) >> 16;
56 args
->v0
.htotal
= ( total
& 0x0000ffff);
57 args
->v0
.time
[0] = ktime_to_ns(ktime_get());
58 args
->v0
.vline
= /* vline read locks hline */
59 nvkm_rd32(device
, 0x616340 + (head
* 0x800)) & 0xffff;
60 args
->v0
.time
[1] = ktime_to_ns(ktime_get());
62 nvkm_rd32(device
, 0x616344 + (head
* 0x800)) & 0xffff;
70 nv50_disp_root_mthd_(struct nvkm_object
*object
, u32 mthd
, void *data
, u32 size
)
73 struct nv50_disp_mthd_v0 v0
;
74 struct nv50_disp_mthd_v1 v1
;
76 struct nv50_disp_root
*root
= nv50_disp_root(object
);
77 struct nv50_disp
*disp
= root
->disp
;
78 const struct nv50_disp_func
*func
= disp
->func
;
79 struct nvkm_output
*outp
= NULL
;
80 struct nvkm_output
*temp
;
82 int head
, ret
= -ENOSYS
;
84 if (mthd
!= NV50_DISP_MTHD
)
87 nvif_ioctl(object
, "disp mthd size %d\n", size
);
88 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
89 nvif_ioctl(object
, "disp mthd vers %d mthd %02x head %d\n",
90 args
->v0
.version
, args
->v0
.method
, args
->v0
.head
);
91 mthd
= args
->v0
.method
;
94 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v1
, 1, 1, true))) {
95 nvif_ioctl(object
, "disp mthd vers %d mthd %02x "
96 "type %04x mask %04x\n",
97 args
->v1
.version
, args
->v1
.method
,
98 args
->v1
.hasht
, args
->v1
.hashm
);
99 mthd
= args
->v1
.method
;
100 type
= args
->v1
.hasht
;
101 mask
= args
->v1
.hashm
;
102 head
= ffs((mask
>> 8) & 0x0f) - 1;
106 if (head
< 0 || head
>= disp
->base
.head
.nr
)
110 list_for_each_entry(temp
, &disp
->base
.outp
, head
) {
111 if ((temp
->info
.hasht
== type
) &&
112 (temp
->info
.hashm
& mask
) == mask
) {
122 case NV50_DISP_SCANOUTPOS
:
123 return func
->head
.scanoutpos(object
, disp
, data
, size
, head
);
128 switch (mthd
* !!outp
) {
129 case NV50_DISP_MTHD_V1_DAC_PWR
:
130 return func
->dac
.power(object
, disp
, data
, size
, head
, outp
);
131 case NV50_DISP_MTHD_V1_DAC_LOAD
:
132 return func
->dac
.sense(object
, disp
, data
, size
, head
, outp
);
133 case NV50_DISP_MTHD_V1_SOR_PWR
:
134 return func
->sor
.power(object
, disp
, data
, size
, head
, outp
);
135 case NV50_DISP_MTHD_V1_SOR_HDA_ELD
:
136 if (!func
->sor
.hda_eld
)
138 return func
->sor
.hda_eld(object
, disp
, data
, size
, head
, outp
);
139 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR
:
142 return func
->sor
.hdmi(object
, disp
, data
, size
, head
, outp
);
143 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT
: {
145 struct nv50_disp_sor_lvds_script_v0 v0
;
148 nvif_ioctl(object
, "disp sor lvds script size %d\n", size
);
149 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
150 nvif_ioctl(object
, "disp sor lvds script "
151 "vers %d name %04x\n",
152 args
->v0
.version
, args
->v0
.script
);
153 disp
->sor
.lvdsconf
= args
->v0
.script
;
159 case NV50_DISP_MTHD_V1_SOR_DP_PWR
: {
160 struct nvkm_output_dp
*outpdp
= nvkm_output_dp(outp
);
162 struct nv50_disp_sor_dp_pwr_v0 v0
;
165 nvif_ioctl(object
, "disp sor dp pwr size %d\n", size
);
166 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
167 nvif_ioctl(object
, "disp sor dp pwr vers %d state %d\n",
168 args
->v0
.version
, args
->v0
.state
);
169 if (args
->v0
.state
== 0) {
170 nvkm_notify_put(&outpdp
->irq
);
171 outpdp
->func
->lnk_pwr(outpdp
, 0);
172 atomic_set(&outpdp
->lt
.done
, 0);
175 if (args
->v0
.state
!= 0) {
176 nvkm_output_dp_train(&outpdp
->base
, 0);
183 case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK
: {
184 struct nvkm_output_dp
*outpdp
= nvkm_output_dp(outp
);
186 struct nv50_disp_sor_dp_mst_link_v0 v0
;
189 nvif_ioctl(object
, "disp sor dp mst link size %d\n", size
);
190 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
191 nvif_ioctl(object
, "disp sor dp mst link vers %d state %d\n",
192 args
->v0
.version
, args
->v0
.state
);
193 if (outpdp
->lt
.mst
!= !!args
->v0
.state
) {
194 outpdp
->lt
.mst
= !!args
->v0
.state
;
195 atomic_set(&outpdp
->lt
.done
, 0);
196 nvkm_output_dp_train(&outpdp
->base
, 0);
203 case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI
: {
204 struct nvkm_output_dp
*outpdp
= nvkm_output_dp(outp
);
206 struct nv50_disp_sor_dp_mst_vcpi_v0 v0
;
209 nvif_ioctl(object
, "disp sor dp mst vcpi size %d\n", size
);
210 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
211 nvif_ioctl(object
, "disp sor dp mst vcpi vers %d "
212 "slot %02x/%02x pbn %04x/%04x\n",
213 args
->v0
.version
, args
->v0
.start_slot
,
214 args
->v0
.num_slots
, args
->v0
.pbn
,
215 args
->v0
.aligned_pbn
);
216 if (!outpdp
->func
->vcpi
)
218 outpdp
->func
->vcpi(outpdp
, head
, args
->v0
.start_slot
,
219 args
->v0
.num_slots
, args
->v0
.pbn
,
220 args
->v0
.aligned_pbn
);
226 case NV50_DISP_MTHD_V1_PIOR_PWR
:
227 if (!func
->pior
.power
)
229 return func
->pior
.power(object
, disp
, data
, size
, head
, outp
);
238 nv50_disp_root_dmac_new_(const struct nvkm_oclass
*oclass
,
239 void *data
, u32 size
, struct nvkm_object
**pobject
)
241 const struct nv50_disp_dmac_oclass
*sclass
= oclass
->priv
;
242 struct nv50_disp_root
*root
= nv50_disp_root(oclass
->parent
);
243 return sclass
->ctor(sclass
->func
, sclass
->mthd
, root
, sclass
->chid
,
244 oclass
, data
, size
, pobject
);
248 nv50_disp_root_pioc_new_(const struct nvkm_oclass
*oclass
,
249 void *data
, u32 size
, struct nvkm_object
**pobject
)
251 const struct nv50_disp_pioc_oclass
*sclass
= oclass
->priv
;
252 struct nv50_disp_root
*root
= nv50_disp_root(oclass
->parent
);
253 return sclass
->ctor(sclass
->func
, sclass
->mthd
, root
, sclass
->chid
,
254 oclass
, data
, size
, pobject
);
258 nv50_disp_root_child_get_(struct nvkm_object
*object
, int index
,
259 struct nvkm_oclass
*sclass
)
261 struct nv50_disp_root
*root
= nv50_disp_root(object
);
263 if (index
< ARRAY_SIZE(root
->func
->dmac
)) {
264 sclass
->base
= root
->func
->dmac
[index
]->base
;
265 sclass
->priv
= root
->func
->dmac
[index
];
266 sclass
->ctor
= nv50_disp_root_dmac_new_
;
270 index
-= ARRAY_SIZE(root
->func
->dmac
);
272 if (index
< ARRAY_SIZE(root
->func
->pioc
)) {
273 sclass
->base
= root
->func
->pioc
[index
]->base
;
274 sclass
->priv
= root
->func
->pioc
[index
];
275 sclass
->ctor
= nv50_disp_root_pioc_new_
;
283 nv50_disp_root_fini_(struct nvkm_object
*object
, bool suspend
)
285 struct nv50_disp_root
*root
= nv50_disp_root(object
);
286 root
->func
->fini(root
);
291 nv50_disp_root_init_(struct nvkm_object
*object
)
293 struct nv50_disp_root
*root
= nv50_disp_root(object
);
294 return root
->func
->init(root
);
298 nv50_disp_root_dtor_(struct nvkm_object
*object
)
300 struct nv50_disp_root
*root
= nv50_disp_root(object
);
301 nvkm_ramht_del(&root
->ramht
);
302 nvkm_gpuobj_del(&root
->instmem
);
306 static const struct nvkm_object_func
308 .dtor
= nv50_disp_root_dtor_
,
309 .init
= nv50_disp_root_init_
,
310 .fini
= nv50_disp_root_fini_
,
311 .mthd
= nv50_disp_root_mthd_
,
312 .ntfy
= nvkm_disp_ntfy
,
313 .sclass
= nv50_disp_root_child_get_
,
317 nv50_disp_root_new_(const struct nv50_disp_root_func
*func
,
318 struct nvkm_disp
*base
, const struct nvkm_oclass
*oclass
,
319 void *data
, u32 size
, struct nvkm_object
**pobject
)
321 struct nv50_disp
*disp
= nv50_disp(base
);
322 struct nv50_disp_root
*root
;
323 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
326 if (!(root
= kzalloc(sizeof(*root
), GFP_KERNEL
)))
328 *pobject
= &root
->object
;
330 nvkm_object_ctor(&nv50_disp_root_
, oclass
, &root
->object
);
334 ret
= nvkm_gpuobj_new(disp
->base
.engine
.subdev
.device
, 0x10000, 0x10000,
335 false, NULL
, &root
->instmem
);
339 return nvkm_ramht_new(device
, 0x1000, 0, root
->instmem
, &root
->ramht
);
343 nv50_disp_root_fini(struct nv50_disp_root
*root
)
345 struct nvkm_device
*device
= root
->disp
->base
.engine
.subdev
.device
;
346 /* disable all interrupts */
347 nvkm_wr32(device
, 0x610024, 0x00000000);
348 nvkm_wr32(device
, 0x610020, 0x00000000);
352 nv50_disp_root_init(struct nv50_disp_root
*root
)
354 struct nv50_disp
*disp
= root
->disp
;
355 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
359 /* The below segments of code copying values from one register to
360 * another appear to inform EVO of the display capabilities or
361 * something similar. NFI what the 0x614004 caps are for..
363 tmp
= nvkm_rd32(device
, 0x614004);
364 nvkm_wr32(device
, 0x610184, tmp
);
367 for (i
= 0; i
< disp
->base
.head
.nr
; i
++) {
368 tmp
= nvkm_rd32(device
, 0x616100 + (i
* 0x800));
369 nvkm_wr32(device
, 0x610190 + (i
* 0x10), tmp
);
370 tmp
= nvkm_rd32(device
, 0x616104 + (i
* 0x800));
371 nvkm_wr32(device
, 0x610194 + (i
* 0x10), tmp
);
372 tmp
= nvkm_rd32(device
, 0x616108 + (i
* 0x800));
373 nvkm_wr32(device
, 0x610198 + (i
* 0x10), tmp
);
374 tmp
= nvkm_rd32(device
, 0x61610c + (i
* 0x800));
375 nvkm_wr32(device
, 0x61019c + (i
* 0x10), tmp
);
379 for (i
= 0; i
< disp
->func
->dac
.nr
; i
++) {
380 tmp
= nvkm_rd32(device
, 0x61a000 + (i
* 0x800));
381 nvkm_wr32(device
, 0x6101d0 + (i
* 0x04), tmp
);
385 for (i
= 0; i
< disp
->func
->sor
.nr
; i
++) {
386 tmp
= nvkm_rd32(device
, 0x61c000 + (i
* 0x800));
387 nvkm_wr32(device
, 0x6101e0 + (i
* 0x04), tmp
);
391 for (i
= 0; i
< disp
->func
->pior
.nr
; i
++) {
392 tmp
= nvkm_rd32(device
, 0x61e000 + (i
* 0x800));
393 nvkm_wr32(device
, 0x6101f0 + (i
* 0x04), tmp
);
396 /* steal display away from vbios, or something like that */
397 if (nvkm_rd32(device
, 0x610024) & 0x00000100) {
398 nvkm_wr32(device
, 0x610024, 0x00000100);
399 nvkm_mask(device
, 0x6194e8, 0x00000001, 0x00000000);
400 if (nvkm_msec(device
, 2000,
401 if (!(nvkm_rd32(device
, 0x6194e8) & 0x00000002))
407 /* point at display engine memory area (hash table, objects) */
408 nvkm_wr32(device
, 0x610010, (root
->instmem
->addr
>> 8) | 9);
410 /* enable supervisor interrupts, disable everything else */
411 nvkm_wr32(device
, 0x61002c, 0x00000370);
412 nvkm_wr32(device
, 0x610028, 0x00000000);
416 static const struct nv50_disp_root_func
418 .init
= nv50_disp_root_init
,
419 .fini
= nv50_disp_root_fini
,
421 &nv50_disp_core_oclass
,
422 &nv50_disp_base_oclass
,
423 &nv50_disp_ovly_oclass
,
426 &nv50_disp_oimm_oclass
,
427 &nv50_disp_curs_oclass
,
432 nv50_disp_root_new(struct nvkm_disp
*disp
, const struct nvkm_oclass
*oclass
,
433 void *data
, u32 size
, struct nvkm_object
**pobject
)
435 return nv50_disp_root_new_(&nv50_disp_root
, disp
, oclass
,
436 data
, size
, pobject
);
439 const struct nvkm_disp_oclass
440 nv50_disp_root_oclass
= {
441 .base
.oclass
= NV50_DISP
,
444 .ctor
= nv50_disp_root_new
,