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.
25 #include <core/object.h>
26 #include <core/parent.h>
27 #include <core/handle.h>
28 #include <core/class.h>
30 #include <engine/disp.h>
32 #include <subdev/timer.h>
33 #include <subdev/fb.h>
34 #include <subdev/clock.h>
36 #include <subdev/bios.h>
37 #include <subdev/bios/dcb.h>
38 #include <subdev/bios/disp.h>
39 #include <subdev/bios/init.h>
40 #include <subdev/bios/pll.h>
44 /*******************************************************************************
45 * EVO DMA channel base class
46 ******************************************************************************/
49 nvd0_disp_dmac_object_attach(struct nouveau_object
*parent
,
50 struct nouveau_object
*object
, u32 name
)
52 struct nv50_disp_base
*base
= (void *)parent
->parent
;
53 struct nv50_disp_chan
*chan
= (void *)parent
;
54 u32 addr
= nv_gpuobj(object
)->node
->offset
;
55 u32 data
= (chan
->chid
<< 27) | (addr
<< 9) | 0x00000001;
56 return nouveau_ramht_insert(base
->ramht
, chan
->chid
, name
, data
);
60 nvd0_disp_dmac_object_detach(struct nouveau_object
*parent
, int cookie
)
62 struct nv50_disp_base
*base
= (void *)parent
->parent
;
63 nouveau_ramht_remove(base
->ramht
, cookie
);
67 nvd0_disp_dmac_init(struct nouveau_object
*object
)
69 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
70 struct nv50_disp_dmac
*dmac
= (void *)object
;
71 int chid
= dmac
->base
.chid
;
74 ret
= nv50_disp_chan_init(&dmac
->base
);
78 /* enable error reporting */
79 nv_mask(priv
, 0x610090, 0x00000001 << chid
, 0x00000001 << chid
);
80 nv_mask(priv
, 0x6100a0, 0x00000001 << chid
, 0x00000001 << chid
);
82 /* initialise channel for dma command submission */
83 nv_wr32(priv
, 0x610494 + (chid
* 0x0010), dmac
->push
);
84 nv_wr32(priv
, 0x610498 + (chid
* 0x0010), 0x00010000);
85 nv_wr32(priv
, 0x61049c + (chid
* 0x0010), 0x00000001);
86 nv_mask(priv
, 0x610490 + (chid
* 0x0010), 0x00000010, 0x00000010);
87 nv_wr32(priv
, 0x640000 + (chid
* 0x1000), 0x00000000);
88 nv_wr32(priv
, 0x610490 + (chid
* 0x0010), 0x00000013);
90 /* wait for it to go inactive */
91 if (!nv_wait(priv
, 0x610490 + (chid
* 0x10), 0x80000000, 0x00000000)) {
92 nv_error(dmac
, "init: 0x%08x\n",
93 nv_rd32(priv
, 0x610490 + (chid
* 0x10)));
101 nvd0_disp_dmac_fini(struct nouveau_object
*object
, bool suspend
)
103 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
104 struct nv50_disp_dmac
*dmac
= (void *)object
;
105 int chid
= dmac
->base
.chid
;
107 /* deactivate channel */
108 nv_mask(priv
, 0x610490 + (chid
* 0x0010), 0x00001010, 0x00001000);
109 nv_mask(priv
, 0x610490 + (chid
* 0x0010), 0x00000003, 0x00000000);
110 if (!nv_wait(priv
, 0x610490 + (chid
* 0x10), 0x001e0000, 0x00000000)) {
111 nv_error(dmac
, "fini: 0x%08x\n",
112 nv_rd32(priv
, 0x610490 + (chid
* 0x10)));
117 /* disable error reporting */
118 nv_mask(priv
, 0x610090, 0x00000001 << chid
, 0x00000000);
119 nv_mask(priv
, 0x6100a0, 0x00000001 << chid
, 0x00000000);
121 return nv50_disp_chan_fini(&dmac
->base
, suspend
);
124 /*******************************************************************************
125 * EVO master channel object
126 ******************************************************************************/
129 nvd0_disp_mast_ctor(struct nouveau_object
*parent
,
130 struct nouveau_object
*engine
,
131 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
132 struct nouveau_object
**pobject
)
134 struct nv50_display_mast_class
*args
= data
;
135 struct nv50_disp_dmac
*mast
;
138 if (size
< sizeof(*args
))
141 ret
= nv50_disp_dmac_create_(parent
, engine
, oclass
, args
->pushbuf
,
142 0, sizeof(*mast
), (void **)&mast
);
143 *pobject
= nv_object(mast
);
147 nv_parent(mast
)->object_attach
= nvd0_disp_dmac_object_attach
;
148 nv_parent(mast
)->object_detach
= nvd0_disp_dmac_object_detach
;
153 nvd0_disp_mast_init(struct nouveau_object
*object
)
155 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
156 struct nv50_disp_dmac
*mast
= (void *)object
;
159 ret
= nv50_disp_chan_init(&mast
->base
);
163 /* enable error reporting */
164 nv_mask(priv
, 0x610090, 0x00000001, 0x00000001);
165 nv_mask(priv
, 0x6100a0, 0x00000001, 0x00000001);
167 /* initialise channel for dma command submission */
168 nv_wr32(priv
, 0x610494, mast
->push
);
169 nv_wr32(priv
, 0x610498, 0x00010000);
170 nv_wr32(priv
, 0x61049c, 0x00000001);
171 nv_mask(priv
, 0x610490, 0x00000010, 0x00000010);
172 nv_wr32(priv
, 0x640000, 0x00000000);
173 nv_wr32(priv
, 0x610490, 0x01000013);
175 /* wait for it to go inactive */
176 if (!nv_wait(priv
, 0x610490, 0x80000000, 0x00000000)) {
177 nv_error(mast
, "init: 0x%08x\n", nv_rd32(priv
, 0x610490));
185 nvd0_disp_mast_fini(struct nouveau_object
*object
, bool suspend
)
187 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
188 struct nv50_disp_dmac
*mast
= (void *)object
;
190 /* deactivate channel */
191 nv_mask(priv
, 0x610490, 0x00000010, 0x00000000);
192 nv_mask(priv
, 0x610490, 0x00000003, 0x00000000);
193 if (!nv_wait(priv
, 0x610490, 0x001e0000, 0x00000000)) {
194 nv_error(mast
, "fini: 0x%08x\n", nv_rd32(priv
, 0x610490));
199 /* disable error reporting */
200 nv_mask(priv
, 0x610090, 0x00000001, 0x00000000);
201 nv_mask(priv
, 0x6100a0, 0x00000001, 0x00000000);
203 return nv50_disp_chan_fini(&mast
->base
, suspend
);
206 struct nouveau_ofuncs
207 nvd0_disp_mast_ofuncs
= {
208 .ctor
= nvd0_disp_mast_ctor
,
209 .dtor
= nv50_disp_dmac_dtor
,
210 .init
= nvd0_disp_mast_init
,
211 .fini
= nvd0_disp_mast_fini
,
212 .rd32
= nv50_disp_chan_rd32
,
213 .wr32
= nv50_disp_chan_wr32
,
216 /*******************************************************************************
217 * EVO sync channel objects
218 ******************************************************************************/
221 nvd0_disp_sync_ctor(struct nouveau_object
*parent
,
222 struct nouveau_object
*engine
,
223 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
224 struct nouveau_object
**pobject
)
226 struct nv50_display_sync_class
*args
= data
;
227 struct nv50_disp_priv
*priv
= (void *)engine
;
228 struct nv50_disp_dmac
*dmac
;
231 if (size
< sizeof(*args
) || args
->head
>= priv
->head
.nr
)
234 ret
= nv50_disp_dmac_create_(parent
, engine
, oclass
, args
->pushbuf
,
235 1 + args
->head
, sizeof(*dmac
),
237 *pobject
= nv_object(dmac
);
241 nv_parent(dmac
)->object_attach
= nvd0_disp_dmac_object_attach
;
242 nv_parent(dmac
)->object_detach
= nvd0_disp_dmac_object_detach
;
246 struct nouveau_ofuncs
247 nvd0_disp_sync_ofuncs
= {
248 .ctor
= nvd0_disp_sync_ctor
,
249 .dtor
= nv50_disp_dmac_dtor
,
250 .init
= nvd0_disp_dmac_init
,
251 .fini
= nvd0_disp_dmac_fini
,
252 .rd32
= nv50_disp_chan_rd32
,
253 .wr32
= nv50_disp_chan_wr32
,
256 /*******************************************************************************
257 * EVO overlay channel objects
258 ******************************************************************************/
261 nvd0_disp_ovly_ctor(struct nouveau_object
*parent
,
262 struct nouveau_object
*engine
,
263 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
264 struct nouveau_object
**pobject
)
266 struct nv50_display_ovly_class
*args
= data
;
267 struct nv50_disp_priv
*priv
= (void *)engine
;
268 struct nv50_disp_dmac
*dmac
;
271 if (size
< sizeof(*args
) || args
->head
>= priv
->head
.nr
)
274 ret
= nv50_disp_dmac_create_(parent
, engine
, oclass
, args
->pushbuf
,
275 5 + args
->head
, sizeof(*dmac
),
277 *pobject
= nv_object(dmac
);
281 nv_parent(dmac
)->object_attach
= nvd0_disp_dmac_object_attach
;
282 nv_parent(dmac
)->object_detach
= nvd0_disp_dmac_object_detach
;
286 struct nouveau_ofuncs
287 nvd0_disp_ovly_ofuncs
= {
288 .ctor
= nvd0_disp_ovly_ctor
,
289 .dtor
= nv50_disp_dmac_dtor
,
290 .init
= nvd0_disp_dmac_init
,
291 .fini
= nvd0_disp_dmac_fini
,
292 .rd32
= nv50_disp_chan_rd32
,
293 .wr32
= nv50_disp_chan_wr32
,
296 /*******************************************************************************
297 * EVO PIO channel base class
298 ******************************************************************************/
301 nvd0_disp_pioc_create_(struct nouveau_object
*parent
,
302 struct nouveau_object
*engine
,
303 struct nouveau_oclass
*oclass
, int chid
,
304 int length
, void **pobject
)
306 return nv50_disp_chan_create_(parent
, engine
, oclass
, chid
,
311 nvd0_disp_pioc_dtor(struct nouveau_object
*object
)
313 struct nv50_disp_pioc
*pioc
= (void *)object
;
314 nv50_disp_chan_destroy(&pioc
->base
);
318 nvd0_disp_pioc_init(struct nouveau_object
*object
)
320 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
321 struct nv50_disp_pioc
*pioc
= (void *)object
;
322 int chid
= pioc
->base
.chid
;
325 ret
= nv50_disp_chan_init(&pioc
->base
);
329 /* enable error reporting */
330 nv_mask(priv
, 0x610090, 0x00000001 << chid
, 0x00000001 << chid
);
331 nv_mask(priv
, 0x6100a0, 0x00000001 << chid
, 0x00000001 << chid
);
333 /* activate channel */
334 nv_wr32(priv
, 0x610490 + (chid
* 0x10), 0x00000001);
335 if (!nv_wait(priv
, 0x610490 + (chid
* 0x10), 0x00030000, 0x00010000)) {
336 nv_error(pioc
, "init: 0x%08x\n",
337 nv_rd32(priv
, 0x610490 + (chid
* 0x10)));
345 nvd0_disp_pioc_fini(struct nouveau_object
*object
, bool suspend
)
347 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
348 struct nv50_disp_pioc
*pioc
= (void *)object
;
349 int chid
= pioc
->base
.chid
;
351 nv_mask(priv
, 0x610490 + (chid
* 0x10), 0x00000001, 0x00000000);
352 if (!nv_wait(priv
, 0x610490 + (chid
* 0x10), 0x00030000, 0x00000000)) {
353 nv_error(pioc
, "timeout: 0x%08x\n",
354 nv_rd32(priv
, 0x610490 + (chid
* 0x10)));
359 /* disable error reporting */
360 nv_mask(priv
, 0x610090, 0x00000001 << chid
, 0x00000000);
361 nv_mask(priv
, 0x6100a0, 0x00000001 << chid
, 0x00000000);
363 return nv50_disp_chan_fini(&pioc
->base
, suspend
);
366 /*******************************************************************************
367 * EVO immediate overlay channel objects
368 ******************************************************************************/
371 nvd0_disp_oimm_ctor(struct nouveau_object
*parent
,
372 struct nouveau_object
*engine
,
373 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
374 struct nouveau_object
**pobject
)
376 struct nv50_display_oimm_class
*args
= data
;
377 struct nv50_disp_priv
*priv
= (void *)engine
;
378 struct nv50_disp_pioc
*pioc
;
381 if (size
< sizeof(*args
) || args
->head
>= priv
->head
.nr
)
384 ret
= nvd0_disp_pioc_create_(parent
, engine
, oclass
, 9 + args
->head
,
385 sizeof(*pioc
), (void **)&pioc
);
386 *pobject
= nv_object(pioc
);
393 struct nouveau_ofuncs
394 nvd0_disp_oimm_ofuncs
= {
395 .ctor
= nvd0_disp_oimm_ctor
,
396 .dtor
= nvd0_disp_pioc_dtor
,
397 .init
= nvd0_disp_pioc_init
,
398 .fini
= nvd0_disp_pioc_fini
,
399 .rd32
= nv50_disp_chan_rd32
,
400 .wr32
= nv50_disp_chan_wr32
,
403 /*******************************************************************************
404 * EVO cursor channel objects
405 ******************************************************************************/
408 nvd0_disp_curs_ctor(struct nouveau_object
*parent
,
409 struct nouveau_object
*engine
,
410 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
411 struct nouveau_object
**pobject
)
413 struct nv50_display_curs_class
*args
= data
;
414 struct nv50_disp_priv
*priv
= (void *)engine
;
415 struct nv50_disp_pioc
*pioc
;
418 if (size
< sizeof(*args
) || args
->head
>= priv
->head
.nr
)
421 ret
= nvd0_disp_pioc_create_(parent
, engine
, oclass
, 13 + args
->head
,
422 sizeof(*pioc
), (void **)&pioc
);
423 *pobject
= nv_object(pioc
);
430 struct nouveau_ofuncs
431 nvd0_disp_curs_ofuncs
= {
432 .ctor
= nvd0_disp_curs_ctor
,
433 .dtor
= nvd0_disp_pioc_dtor
,
434 .init
= nvd0_disp_pioc_init
,
435 .fini
= nvd0_disp_pioc_fini
,
436 .rd32
= nv50_disp_chan_rd32
,
437 .wr32
= nv50_disp_chan_wr32
,
440 /*******************************************************************************
441 * Base display object
442 ******************************************************************************/
445 nvd0_disp_base_vblank_enable(struct nouveau_event
*event
, int head
)
447 nv_mask(event
->priv
, 0x6100c0 + (head
* 0x800), 0x00000001, 0x00000001);
451 nvd0_disp_base_vblank_disable(struct nouveau_event
*event
, int head
)
453 nv_mask(event
->priv
, 0x6100c0 + (head
* 0x800), 0x00000001, 0x00000000);
457 nvd0_disp_base_ctor(struct nouveau_object
*parent
,
458 struct nouveau_object
*engine
,
459 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
460 struct nouveau_object
**pobject
)
462 struct nv50_disp_priv
*priv
= (void *)engine
;
463 struct nv50_disp_base
*base
;
466 ret
= nouveau_parent_create(parent
, engine
, oclass
, 0,
467 priv
->sclass
, 0, &base
);
468 *pobject
= nv_object(base
);
472 priv
->base
.vblank
->priv
= priv
;
473 priv
->base
.vblank
->enable
= nvd0_disp_base_vblank_enable
;
474 priv
->base
.vblank
->disable
= nvd0_disp_base_vblank_disable
;
476 return nouveau_ramht_new(parent
, parent
, 0x1000, 0, &base
->ramht
);
480 nvd0_disp_base_dtor(struct nouveau_object
*object
)
482 struct nv50_disp_base
*base
= (void *)object
;
483 nouveau_ramht_ref(NULL
, &base
->ramht
);
484 nouveau_parent_destroy(&base
->base
);
488 nvd0_disp_base_init(struct nouveau_object
*object
)
490 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
491 struct nv50_disp_base
*base
= (void *)object
;
495 ret
= nouveau_parent_init(&base
->base
);
499 /* The below segments of code copying values from one register to
500 * another appear to inform EVO of the display capabilities or
505 for (i
= 0; i
< priv
->head
.nr
; i
++) {
506 tmp
= nv_rd32(priv
, 0x616104 + (i
* 0x800));
507 nv_wr32(priv
, 0x6101b4 + (i
* 0x800), tmp
);
508 tmp
= nv_rd32(priv
, 0x616108 + (i
* 0x800));
509 nv_wr32(priv
, 0x6101b8 + (i
* 0x800), tmp
);
510 tmp
= nv_rd32(priv
, 0x61610c + (i
* 0x800));
511 nv_wr32(priv
, 0x6101bc + (i
* 0x800), tmp
);
515 for (i
= 0; i
< priv
->dac
.nr
; i
++) {
516 tmp
= nv_rd32(priv
, 0x61a000 + (i
* 0x800));
517 nv_wr32(priv
, 0x6101c0 + (i
* 0x800), tmp
);
521 for (i
= 0; i
< priv
->sor
.nr
; i
++) {
522 tmp
= nv_rd32(priv
, 0x61c000 + (i
* 0x800));
523 nv_wr32(priv
, 0x6301c4 + (i
* 0x800), tmp
);
526 /* steal display away from vbios, or something like that */
527 if (nv_rd32(priv
, 0x6100ac) & 0x00000100) {
528 nv_wr32(priv
, 0x6100ac, 0x00000100);
529 nv_mask(priv
, 0x6194e8, 0x00000001, 0x00000000);
530 if (!nv_wait(priv
, 0x6194e8, 0x00000002, 0x00000000)) {
531 nv_error(priv
, "timeout acquiring display\n");
536 /* point at display engine memory area (hash table, objects) */
537 nv_wr32(priv
, 0x610010, (nv_gpuobj(object
->parent
)->addr
>> 8) | 9);
539 /* enable supervisor interrupts, disable everything else */
540 nv_wr32(priv
, 0x610090, 0x00000000);
541 nv_wr32(priv
, 0x6100a0, 0x00000000);
542 nv_wr32(priv
, 0x6100b0, 0x00000307);
548 nvd0_disp_base_fini(struct nouveau_object
*object
, bool suspend
)
550 struct nv50_disp_priv
*priv
= (void *)object
->engine
;
551 struct nv50_disp_base
*base
= (void *)object
;
553 /* disable all interrupts */
554 nv_wr32(priv
, 0x6100b0, 0x00000000);
556 return nouveau_parent_fini(&base
->base
, suspend
);
559 struct nouveau_ofuncs
560 nvd0_disp_base_ofuncs
= {
561 .ctor
= nvd0_disp_base_ctor
,
562 .dtor
= nvd0_disp_base_dtor
,
563 .init
= nvd0_disp_base_init
,
564 .fini
= nvd0_disp_base_fini
,
567 static struct nouveau_oclass
568 nvd0_disp_base_oclass
[] = {
569 { NVD0_DISP_CLASS
, &nvd0_disp_base_ofuncs
, nva3_disp_base_omthds
},
573 static struct nouveau_oclass
574 nvd0_disp_sclass
[] = {
575 { NVD0_DISP_MAST_CLASS
, &nvd0_disp_mast_ofuncs
},
576 { NVD0_DISP_SYNC_CLASS
, &nvd0_disp_sync_ofuncs
},
577 { NVD0_DISP_OVLY_CLASS
, &nvd0_disp_ovly_ofuncs
},
578 { NVD0_DISP_OIMM_CLASS
, &nvd0_disp_oimm_ofuncs
},
579 { NVD0_DISP_CURS_CLASS
, &nvd0_disp_curs_ofuncs
},
583 /*******************************************************************************
584 * Display engine implementation
585 ******************************************************************************/
588 exec_lookup(struct nv50_disp_priv
*priv
, int head
, int outp
, u32 ctrl
,
589 struct dcb_output
*dcb
, u8
*ver
, u8
*hdr
, u8
*cnt
, u8
*len
,
590 struct nvbios_outp
*info
)
592 struct nouveau_bios
*bios
= nouveau_bios(priv
);
593 u16 mask
, type
, data
;
596 type
= DCB_OUTPUT_ANALOG
;
600 switch (ctrl
& 0x00000f00) {
601 case 0x00000000: type
= DCB_OUTPUT_LVDS
; mask
= 1; break;
602 case 0x00000100: type
= DCB_OUTPUT_TMDS
; mask
= 1; break;
603 case 0x00000200: type
= DCB_OUTPUT_TMDS
; mask
= 2; break;
604 case 0x00000500: type
= DCB_OUTPUT_TMDS
; mask
= 3; break;
605 case 0x00000800: type
= DCB_OUTPUT_DP
; mask
= 1; break;
606 case 0x00000900: type
= DCB_OUTPUT_DP
; mask
= 2; break;
608 nv_error(priv
, "unknown SOR mc 0x%08x\n", ctrl
);
611 dcb
->sorconf
.link
= mask
;
614 mask
= 0x00c0 & (mask
<< 6);
615 mask
|= 0x0001 << outp
;
616 mask
|= 0x0100 << head
;
618 data
= dcb_outp_match(bios
, type
, mask
, ver
, hdr
, dcb
);
622 return nvbios_outp_match(bios
, type
, mask
, ver
, hdr
, cnt
, len
, info
);
626 exec_script(struct nv50_disp_priv
*priv
, int head
, int outp
, u32 ctrl
, int id
)
628 struct nouveau_bios
*bios
= nouveau_bios(priv
);
629 struct nvbios_outp info
;
630 struct dcb_output dcb
;
631 u8 ver
, hdr
, cnt
, len
;
634 data
= exec_lookup(priv
, head
, outp
, ctrl
, &dcb
, &ver
, &hdr
, &cnt
, &len
, &info
);
636 struct nvbios_init init
= {
637 .subdev
= nv_subdev(priv
),
639 .offset
= info
.script
[id
],
645 return nvbios_exec(&init
) == 0;
652 exec_clkcmp(struct nv50_disp_priv
*priv
, int head
, int outp
,
653 u32 ctrl
, int id
, u32 pclk
)
655 struct nouveau_bios
*bios
= nouveau_bios(priv
);
656 struct nvbios_outp info1
;
657 struct nvbios_ocfg info2
;
658 struct dcb_output dcb
;
659 u8 ver
, hdr
, cnt
, len
;
662 data
= exec_lookup(priv
, head
, outp
, ctrl
, &dcb
, &ver
, &hdr
, &cnt
, &len
, &info1
);
667 case DCB_OUTPUT_TMDS
:
668 conf
= (ctrl
& 0x00000f00) >> 8;
672 case DCB_OUTPUT_LVDS
:
673 conf
= priv
->sor
.lvdsconf
;
676 conf
= (ctrl
& 0x00000f00) >> 8;
678 case DCB_OUTPUT_ANALOG
:
684 data
= nvbios_ocfg_match(bios
, data
, conf
, &ver
, &hdr
, &cnt
, &len
, &info2
);
686 data
= nvbios_oclk_match(bios
, info2
.clkcmp
[id
], pclk
);
688 struct nvbios_init init
= {
689 .subdev
= nv_subdev(priv
),
697 if (nvbios_exec(&init
))
707 nvd0_display_unk1_handler(struct nv50_disp_priv
*priv
, u32 head
, u32 mask
)
711 for (i
= 0; mask
&& i
< 8; i
++) {
712 u32 mcc
= nv_rd32(priv
, 0x640180 + (i
* 0x20));
713 if (mcc
& (1 << head
))
714 exec_script(priv
, head
, i
, mcc
, 1);
717 nv_wr32(priv
, 0x6101d4, 0x00000000);
718 nv_wr32(priv
, 0x6109d4, 0x00000000);
719 nv_wr32(priv
, 0x6101d0, 0x80000000);
723 nvd0_display_unk2_calc_tu(struct nv50_disp_priv
*priv
, int head
, int or)
725 const u32 ctrl
= nv_rd32(priv
, 0x660200 + (or * 0x020));
726 const u32 conf
= nv_rd32(priv
, 0x660404 + (head
* 0x300));
727 const u32 pclk
= nv_rd32(priv
, 0x660450 + (head
* 0x300)) / 1000;
728 const u32 link
= ((ctrl
& 0xf00) == 0x800) ? 0 : 1;
729 const u32 hoff
= (head
* 0x800);
730 const u32 soff
= ( or * 0x800);
731 const u32 loff
= (link
* 0x080) + soff
;
732 const u32 symbol
= 100000;
734 u32 dpctrl
= nv_rd32(priv
, 0x61c10c + loff
) & 0x000f0000;
735 u32 clksor
= nv_rd32(priv
, 0x612300 + soff
);
736 u32 datarate
, link_nr
, link_bw
, bits
;
739 if ((conf
& 0x3c0) == 0x180) bits
= 30;
740 else if ((conf
& 0x3c0) == 0x140) bits
= 24;
742 datarate
= (pclk
* bits
) / 8;
744 if (dpctrl
> 0x00030000) link_nr
= 4;
745 else if (dpctrl
> 0x00010000) link_nr
= 2;
748 link_bw
= (clksor
& 0x007c0000) >> 18;
753 do_div(ratio
, link_nr
* link_bw
);
755 value
= (symbol
- ratio
) * TU
;
757 do_div(value
, symbol
);
758 do_div(value
, symbol
);
763 nv_wr32(priv
, 0x616610 + hoff
, value
);
767 nvd0_display_unk2_handler(struct nv50_disp_priv
*priv
, u32 head
, u32 mask
)
772 for (i
= 0; mask
&& i
< 8; i
++) {
773 u32 mcc
= nv_rd32(priv
, 0x640180 + (i
* 0x20));
774 if (mcc
& (1 << head
))
775 exec_script(priv
, head
, i
, mcc
, 2);
778 pclk
= nv_rd32(priv
, 0x660450 + (head
* 0x300)) / 1000;
779 nv_debug(priv
, "head %d pclk %d mask 0x%08x\n", head
, pclk
, mask
);
780 if (pclk
&& (mask
& 0x00010000)) {
781 struct nouveau_clock
*clk
= nouveau_clock(priv
);
782 clk
->pll_set(clk
, PLL_VPLL0
+ head
, pclk
);
785 nv_wr32(priv
, 0x612200 + (head
* 0x800), 0x00000000);
787 for (i
= 0; mask
&& i
< 8; i
++) {
788 u32 mcp
= nv_rd32(priv
, 0x660180 + (i
* 0x20)), cfg
;
789 if (mcp
& (1 << head
)) {
790 if ((cfg
= exec_clkcmp(priv
, head
, i
, mcp
, 0, pclk
))) {
791 u32 addr
, mask
, data
= 0x00000000;
793 addr
= 0x612280 + ((i
- 0) * 0x800);
796 switch (mcp
& 0x00000f00) {
799 nvd0_display_unk2_calc_tu(priv
, head
, i
- 4);
805 addr
= 0x612300 + ((i
- 4) * 0x800);
807 if (cfg
& 0x00000100)
810 nv_mask(priv
, addr
, mask
, data
);
816 nv_wr32(priv
, 0x6101d4, 0x00000000);
817 nv_wr32(priv
, 0x6109d4, 0x00000000);
818 nv_wr32(priv
, 0x6101d0, 0x80000000);
822 nvd0_display_unk4_handler(struct nv50_disp_priv
*priv
, u32 head
, u32 mask
)
826 pclk
= nv_rd32(priv
, 0x660450 + (head
* 0x300)) / 1000;
828 for (i
= 0; mask
&& i
< 8; i
++) {
829 u32 mcp
= nv_rd32(priv
, 0x660180 + (i
* 0x20));
830 if (mcp
& (1 << head
))
831 exec_clkcmp(priv
, head
, i
, mcp
, 1, pclk
);
834 nv_wr32(priv
, 0x6101d4, 0x00000000);
835 nv_wr32(priv
, 0x6109d4, 0x00000000);
836 nv_wr32(priv
, 0x6101d0, 0x80000000);
840 nvd0_disp_intr(struct nouveau_subdev
*subdev
)
842 struct nv50_disp_priv
*priv
= (void *)subdev
;
843 u32 intr
= nv_rd32(priv
, 0x610088);
846 if (intr
& 0x00000001) {
847 u32 stat
= nv_rd32(priv
, 0x61008c);
848 nv_wr32(priv
, 0x61008c, stat
);
852 if (intr
& 0x00000002) {
853 u32 stat
= nv_rd32(priv
, 0x61009c);
854 int chid
= ffs(stat
) - 1;
856 u32 mthd
= nv_rd32(priv
, 0x6101f0 + (chid
* 12));
857 u32 data
= nv_rd32(priv
, 0x6101f4 + (chid
* 12));
858 u32 unkn
= nv_rd32(priv
, 0x6101f8 + (chid
* 12));
860 nv_error(priv
, "chid %d mthd 0x%04x data 0x%08x "
862 chid
, (mthd
& 0x0000ffc), data
, mthd
, unkn
);
863 nv_wr32(priv
, 0x61009c, (1 << chid
));
864 nv_wr32(priv
, 0x6101f0 + (chid
* 12), 0x90000000);
870 if (intr
& 0x00100000) {
871 u32 stat
= nv_rd32(priv
, 0x6100ac);
872 u32 mask
= 0, crtc
= ~0;
874 while (!mask
&& ++crtc
< priv
->head
.nr
)
875 mask
= nv_rd32(priv
, 0x6101d4 + (crtc
* 0x800));
877 if (stat
& 0x00000001) {
878 nv_wr32(priv
, 0x6100ac, 0x00000001);
879 nvd0_display_unk1_handler(priv
, crtc
, mask
);
883 if (stat
& 0x00000002) {
884 nv_wr32(priv
, 0x6100ac, 0x00000002);
885 nvd0_display_unk2_handler(priv
, crtc
, mask
);
889 if (stat
& 0x00000004) {
890 nv_wr32(priv
, 0x6100ac, 0x00000004);
891 nvd0_display_unk4_handler(priv
, crtc
, mask
);
896 nv_info(priv
, "unknown intr24 0x%08x\n", stat
);
897 nv_wr32(priv
, 0x6100ac, stat
);
903 for (i
= 0; i
< priv
->head
.nr
; i
++) {
904 u32 mask
= 0x01000000 << i
;
906 u32 stat
= nv_rd32(priv
, 0x6100bc + (i
* 0x800));
907 if (stat
& 0x00000001)
908 nouveau_event_trigger(priv
->base
.vblank
, i
);
909 nv_mask(priv
, 0x6100bc + (i
* 0x800), 0, 0);
910 nv_rd32(priv
, 0x6100c0 + (i
* 0x800));
916 nvd0_disp_ctor(struct nouveau_object
*parent
, struct nouveau_object
*engine
,
917 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
918 struct nouveau_object
**pobject
)
920 struct nv50_disp_priv
*priv
;
921 int heads
= nv_rd32(parent
, 0x022448);
924 ret
= nouveau_disp_create(parent
, engine
, oclass
, heads
,
925 "PDISP", "display", &priv
);
926 *pobject
= nv_object(priv
);
930 nv_engine(priv
)->sclass
= nvd0_disp_base_oclass
;
931 nv_engine(priv
)->cclass
= &nv50_disp_cclass
;
932 nv_subdev(priv
)->intr
= nvd0_disp_intr
;
933 priv
->sclass
= nvd0_disp_sclass
;
934 priv
->head
.nr
= heads
;
937 priv
->dac
.power
= nv50_dac_power
;
938 priv
->dac
.sense
= nv50_dac_sense
;
939 priv
->sor
.power
= nv50_sor_power
;
940 priv
->sor
.hda_eld
= nvd0_hda_eld
;
941 priv
->sor
.hdmi
= nvd0_hdmi_ctrl
;
942 priv
->sor
.dp_train
= nvd0_sor_dp_train
;
943 priv
->sor
.dp_train_init
= nv94_sor_dp_train_init
;
944 priv
->sor
.dp_train_fini
= nv94_sor_dp_train_fini
;
945 priv
->sor
.dp_lnkctl
= nvd0_sor_dp_lnkctl
;
946 priv
->sor
.dp_drvctl
= nvd0_sor_dp_drvctl
;
950 struct nouveau_oclass
952 .handle
= NV_ENGINE(DISP
, 0x90),
953 .ofuncs
= &(struct nouveau_ofuncs
) {
954 .ctor
= nvd0_disp_ctor
,
955 .dtor
= _nouveau_disp_dtor
,
956 .init
= _nouveau_disp_init
,
957 .fini
= _nouveau_disp_fini
,