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/unpack.h>
35 nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0
)
37 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
38 const u32 blanke
= nvkm_rd32(device
, 0x610aec + (head
* 0x540));
39 const u32 blanks
= nvkm_rd32(device
, 0x610af4 + (head
* 0x540));
40 const u32 total
= nvkm_rd32(device
, 0x610afc + (head
* 0x540));
42 struct nv04_disp_scanoutpos_v0 v0
;
46 nvif_ioctl(object
, "disp scanoutpos size %d\n", size
);
47 if (nvif_unpack(args
->v0
, 0, 0, false)) {
48 nvif_ioctl(object
, "disp scanoutpos vers %d\n",
50 args
->v0
.vblanke
= (blanke
& 0xffff0000) >> 16;
51 args
->v0
.hblanke
= (blanke
& 0x0000ffff);
52 args
->v0
.vblanks
= (blanks
& 0xffff0000) >> 16;
53 args
->v0
.hblanks
= (blanks
& 0x0000ffff);
54 args
->v0
.vtotal
= ( total
& 0xffff0000) >> 16;
55 args
->v0
.htotal
= ( total
& 0x0000ffff);
56 args
->v0
.time
[0] = ktime_to_ns(ktime_get());
57 args
->v0
.vline
= /* vline read locks hline */
58 nvkm_rd32(device
, 0x616340 + (head
* 0x800)) & 0xffff;
59 args
->v0
.time
[1] = ktime_to_ns(ktime_get());
61 nvkm_rd32(device
, 0x616344 + (head
* 0x800)) & 0xffff;
69 nv50_disp_root_mthd_(struct nvkm_object
*object
, u32 mthd
, void *data
, u32 size
)
72 struct nv50_disp_mthd_v0 v0
;
73 struct nv50_disp_mthd_v1 v1
;
75 struct nv50_disp_root
*root
= nv50_disp_root(object
);
76 struct nv50_disp
*disp
= root
->disp
;
77 const struct nv50_disp_func
*func
= disp
->func
;
78 struct nvkm_output
*outp
= NULL
;
79 struct nvkm_output
*temp
;
83 if (mthd
!= NV50_DISP_MTHD
)
86 nvif_ioctl(object
, "disp mthd size %d\n", size
);
87 if (nvif_unpack(args
->v0
, 0, 0, true)) {
88 nvif_ioctl(object
, "disp mthd vers %d mthd %02x head %d\n",
89 args
->v0
.version
, args
->v0
.method
, args
->v0
.head
);
90 mthd
= args
->v0
.method
;
93 if (nvif_unpack(args
->v1
, 1, 1, true)) {
94 nvif_ioctl(object
, "disp mthd vers %d mthd %02x "
95 "type %04x mask %04x\n",
96 args
->v1
.version
, args
->v1
.method
,
97 args
->v1
.hasht
, args
->v1
.hashm
);
98 mthd
= args
->v1
.method
;
99 type
= args
->v1
.hasht
;
100 mask
= args
->v1
.hashm
;
101 head
= ffs((mask
>> 8) & 0x0f) - 1;
105 if (head
< 0 || head
>= disp
->base
.head
.nr
)
109 list_for_each_entry(temp
, &disp
->base
.outp
, head
) {
110 if ((temp
->info
.hasht
== type
) &&
111 (temp
->info
.hashm
& mask
) == mask
) {
121 case NV50_DISP_SCANOUTPOS
:
122 return func
->head
.scanoutpos(object
, disp
, data
, size
, head
);
127 switch (mthd
* !!outp
) {
128 case NV50_DISP_MTHD_V1_DAC_PWR
:
129 return func
->dac
.power(object
, disp
, data
, size
, head
, outp
);
130 case NV50_DISP_MTHD_V1_DAC_LOAD
:
131 return func
->dac
.sense(object
, disp
, data
, size
, head
, outp
);
132 case NV50_DISP_MTHD_V1_SOR_PWR
:
133 return func
->sor
.power(object
, disp
, data
, size
, head
, outp
);
134 case NV50_DISP_MTHD_V1_SOR_HDA_ELD
:
135 if (!func
->sor
.hda_eld
)
137 return func
->sor
.hda_eld(object
, disp
, data
, size
, head
, outp
);
138 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR
:
141 return func
->sor
.hdmi(object
, disp
, data
, size
, head
, outp
);
142 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT
: {
144 struct nv50_disp_sor_lvds_script_v0 v0
;
146 nvif_ioctl(object
, "disp sor lvds script size %d\n", size
);
147 if (nvif_unpack(args
->v0
, 0, 0, false)) {
148 nvif_ioctl(object
, "disp sor lvds script "
149 "vers %d name %04x\n",
150 args
->v0
.version
, args
->v0
.script
);
151 disp
->sor
.lvdsconf
= args
->v0
.script
;
157 case NV50_DISP_MTHD_V1_SOR_DP_PWR
: {
158 struct nvkm_output_dp
*outpdp
= nvkm_output_dp(outp
);
160 struct nv50_disp_sor_dp_pwr_v0 v0
;
162 nvif_ioctl(object
, "disp sor dp pwr size %d\n", size
);
163 if (nvif_unpack(args
->v0
, 0, 0, false)) {
164 nvif_ioctl(object
, "disp sor dp pwr vers %d state %d\n",
165 args
->v0
.version
, args
->v0
.state
);
166 if (args
->v0
.state
== 0) {
167 nvkm_notify_put(&outpdp
->irq
);
168 outpdp
->func
->lnk_pwr(outpdp
, 0);
169 atomic_set(&outpdp
->lt
.done
, 0);
172 if (args
->v0
.state
!= 0) {
173 nvkm_output_dp_train(&outpdp
->base
, 0, true);
180 case NV50_DISP_MTHD_V1_PIOR_PWR
:
181 if (!func
->pior
.power
)
183 return func
->pior
.power(object
, disp
, data
, size
, head
, outp
);
192 nv50_disp_root_dmac_new_(const struct nvkm_oclass
*oclass
,
193 void *data
, u32 size
, struct nvkm_object
**pobject
)
195 const struct nv50_disp_dmac_oclass
*sclass
= oclass
->priv
;
196 struct nv50_disp_root
*root
= nv50_disp_root(oclass
->parent
);
197 return sclass
->ctor(sclass
->func
, sclass
->mthd
, root
, sclass
->chid
,
198 oclass
, data
, size
, pobject
);
202 nv50_disp_root_pioc_new_(const struct nvkm_oclass
*oclass
,
203 void *data
, u32 size
, struct nvkm_object
**pobject
)
205 const struct nv50_disp_pioc_oclass
*sclass
= oclass
->priv
;
206 struct nv50_disp_root
*root
= nv50_disp_root(oclass
->parent
);
207 return sclass
->ctor(sclass
->func
, sclass
->mthd
, root
, sclass
->chid
,
208 oclass
, data
, size
, pobject
);
212 nv50_disp_root_child_get_(struct nvkm_object
*object
, int index
,
213 struct nvkm_oclass
*sclass
)
215 struct nv50_disp_root
*root
= nv50_disp_root(object
);
217 if (index
< ARRAY_SIZE(root
->func
->dmac
)) {
218 sclass
->base
= root
->func
->dmac
[index
]->base
;
219 sclass
->priv
= root
->func
->dmac
[index
];
220 sclass
->ctor
= nv50_disp_root_dmac_new_
;
224 index
-= ARRAY_SIZE(root
->func
->dmac
);
226 if (index
< ARRAY_SIZE(root
->func
->pioc
)) {
227 sclass
->base
= root
->func
->pioc
[index
]->base
;
228 sclass
->priv
= root
->func
->pioc
[index
];
229 sclass
->ctor
= nv50_disp_root_pioc_new_
;
237 nv50_disp_root_fini_(struct nvkm_object
*object
, bool suspend
)
239 struct nv50_disp_root
*root
= nv50_disp_root(object
);
240 root
->func
->fini(root
);
245 nv50_disp_root_init_(struct nvkm_object
*object
)
247 struct nv50_disp_root
*root
= nv50_disp_root(object
);
248 return root
->func
->init(root
);
252 nv50_disp_root_dtor_(struct nvkm_object
*object
)
254 struct nv50_disp_root
*root
= nv50_disp_root(object
);
255 nvkm_ramht_del(&root
->ramht
);
256 nvkm_gpuobj_del(&root
->instmem
);
260 static const struct nvkm_object_func
262 .dtor
= nv50_disp_root_dtor_
,
263 .init
= nv50_disp_root_init_
,
264 .fini
= nv50_disp_root_fini_
,
265 .mthd
= nv50_disp_root_mthd_
,
266 .ntfy
= nvkm_disp_ntfy
,
267 .sclass
= nv50_disp_root_child_get_
,
271 nv50_disp_root_new_(const struct nv50_disp_root_func
*func
,
272 struct nvkm_disp
*base
, const struct nvkm_oclass
*oclass
,
273 void *data
, u32 size
, struct nvkm_object
**pobject
)
275 struct nv50_disp
*disp
= nv50_disp(base
);
276 struct nv50_disp_root
*root
;
277 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
280 if (!(root
= kzalloc(sizeof(*root
), GFP_KERNEL
)))
282 *pobject
= &root
->object
;
284 nvkm_object_ctor(&nv50_disp_root_
, oclass
, &root
->object
);
288 ret
= nvkm_gpuobj_new(disp
->base
.engine
.subdev
.device
, 0x10000, 0x10000,
289 false, NULL
, &root
->instmem
);
293 return nvkm_ramht_new(device
, 0x1000, 0, root
->instmem
, &root
->ramht
);
297 nv50_disp_root_fini(struct nv50_disp_root
*root
)
299 struct nvkm_device
*device
= root
->disp
->base
.engine
.subdev
.device
;
300 /* disable all interrupts */
301 nvkm_wr32(device
, 0x610024, 0x00000000);
302 nvkm_wr32(device
, 0x610020, 0x00000000);
306 nv50_disp_root_init(struct nv50_disp_root
*root
)
308 struct nv50_disp
*disp
= root
->disp
;
309 struct nvkm_device
*device
= disp
->base
.engine
.subdev
.device
;
313 /* The below segments of code copying values from one register to
314 * another appear to inform EVO of the display capabilities or
315 * something similar. NFI what the 0x614004 caps are for..
317 tmp
= nvkm_rd32(device
, 0x614004);
318 nvkm_wr32(device
, 0x610184, tmp
);
321 for (i
= 0; i
< disp
->base
.head
.nr
; i
++) {
322 tmp
= nvkm_rd32(device
, 0x616100 + (i
* 0x800));
323 nvkm_wr32(device
, 0x610190 + (i
* 0x10), tmp
);
324 tmp
= nvkm_rd32(device
, 0x616104 + (i
* 0x800));
325 nvkm_wr32(device
, 0x610194 + (i
* 0x10), tmp
);
326 tmp
= nvkm_rd32(device
, 0x616108 + (i
* 0x800));
327 nvkm_wr32(device
, 0x610198 + (i
* 0x10), tmp
);
328 tmp
= nvkm_rd32(device
, 0x61610c + (i
* 0x800));
329 nvkm_wr32(device
, 0x61019c + (i
* 0x10), tmp
);
333 for (i
= 0; i
< disp
->func
->dac
.nr
; i
++) {
334 tmp
= nvkm_rd32(device
, 0x61a000 + (i
* 0x800));
335 nvkm_wr32(device
, 0x6101d0 + (i
* 0x04), tmp
);
339 for (i
= 0; i
< disp
->func
->sor
.nr
; i
++) {
340 tmp
= nvkm_rd32(device
, 0x61c000 + (i
* 0x800));
341 nvkm_wr32(device
, 0x6101e0 + (i
* 0x04), tmp
);
345 for (i
= 0; i
< disp
->func
->pior
.nr
; i
++) {
346 tmp
= nvkm_rd32(device
, 0x61e000 + (i
* 0x800));
347 nvkm_wr32(device
, 0x6101f0 + (i
* 0x04), tmp
);
350 /* steal display away from vbios, or something like that */
351 if (nvkm_rd32(device
, 0x610024) & 0x00000100) {
352 nvkm_wr32(device
, 0x610024, 0x00000100);
353 nvkm_mask(device
, 0x6194e8, 0x00000001, 0x00000000);
354 if (nvkm_msec(device
, 2000,
355 if (!(nvkm_rd32(device
, 0x6194e8) & 0x00000002))
361 /* point at display engine memory area (hash table, objects) */
362 nvkm_wr32(device
, 0x610010, (root
->instmem
->addr
>> 8) | 9);
364 /* enable supervisor interrupts, disable everything else */
365 nvkm_wr32(device
, 0x61002c, 0x00000370);
366 nvkm_wr32(device
, 0x610028, 0x00000000);
370 static const struct nv50_disp_root_func
372 .init
= nv50_disp_root_init
,
373 .fini
= nv50_disp_root_fini
,
375 &nv50_disp_core_oclass
,
376 &nv50_disp_base_oclass
,
377 &nv50_disp_ovly_oclass
,
380 &nv50_disp_oimm_oclass
,
381 &nv50_disp_curs_oclass
,
386 nv50_disp_root_new(struct nvkm_disp
*disp
, const struct nvkm_oclass
*oclass
,
387 void *data
, u32 size
, struct nvkm_object
**pobject
)
389 return nv50_disp_root_new_(&nv50_disp_root
, disp
, oclass
,
390 data
, size
, pobject
);
393 const struct nvkm_disp_oclass
394 nv50_disp_root_oclass
= {
395 .base
.oclass
= NV50_DISP
,
398 .ctor
= nv50_disp_root_new
,