drm/nv50/devinit: reverse the logic for running encoder init scripts
[deliverable/linux.git] / drivers / gpu / drm / nouveau / core / engine / disp / nvd0.c
CommitLineData
ebb945a9
BS
1/*
2 * Copyright 2012 Red Hat Inc.
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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.
21 *
22 * Authors: Ben Skeggs
23 */
24
46654061
BS
25#include <core/object.h>
26#include <core/parent.h>
27#include <core/handle.h>
28#include <core/class.h>
ebb945a9 29
ebb945a9
BS
30#include <engine/disp.h>
31
46654061
BS
32#include <subdev/timer.h>
33#include <subdev/fb.h>
14464b8c
BS
34#include <subdev/clock.h>
35
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>
46654061
BS
41
42#include "nv50.h"
43
44/*******************************************************************************
45 * EVO DMA channel base class
46 ******************************************************************************/
47
48static int
49nvd0_disp_dmac_object_attach(struct nouveau_object *parent,
50 struct nouveau_object *object, u32 name)
51{
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);
57}
58
59static void
60nvd0_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
61{
62 struct nv50_disp_base *base = (void *)parent->parent;
63 nouveau_ramht_remove(base->ramht, cookie);
64}
65
66static int
67nvd0_disp_dmac_init(struct nouveau_object *object)
68{
69 struct nv50_disp_priv *priv = (void *)object->engine;
70 struct nv50_disp_dmac *dmac = (void *)object;
71 int chid = dmac->base.chid;
72 int ret;
73
74 ret = nv50_disp_chan_init(&dmac->base);
75 if (ret)
76 return ret;
77
78 /* enable error reporting */
79 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
80 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
81
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);
89
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)));
94 return -EBUSY;
95 }
96
97 return 0;
98}
99
100static int
101nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
102{
103 struct nv50_disp_priv *priv = (void *)object->engine;
104 struct nv50_disp_dmac *dmac = (void *)object;
105 int chid = dmac->base.chid;
106
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)));
113 if (suspend)
114 return -EBUSY;
115 }
116
117 /* disable error reporting */
118 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
119 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
120
121 return nv50_disp_chan_fini(&dmac->base, suspend);
122}
123
124/*******************************************************************************
125 * EVO master channel object
126 ******************************************************************************/
127
128static int
129nvd0_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)
133{
134 struct nv50_display_mast_class *args = data;
135 struct nv50_disp_dmac *mast;
136 int ret;
137
138 if (size < sizeof(*args))
139 return -EINVAL;
140
141 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
142 0, sizeof(*mast), (void **)&mast);
143 *pobject = nv_object(mast);
144 if (ret)
145 return ret;
146
147 nv_parent(mast)->object_attach = nvd0_disp_dmac_object_attach;
148 nv_parent(mast)->object_detach = nvd0_disp_dmac_object_detach;
149 return 0;
150}
151
152static int
153nvd0_disp_mast_init(struct nouveau_object *object)
154{
155 struct nv50_disp_priv *priv = (void *)object->engine;
156 struct nv50_disp_dmac *mast = (void *)object;
157 int ret;
158
159 ret = nv50_disp_chan_init(&mast->base);
160 if (ret)
161 return ret;
162
163 /* enable error reporting */
164 nv_mask(priv, 0x610090, 0x00000001, 0x00000001);
165 nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
166
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);
174
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));
178 return -EBUSY;
179 }
180
181 return 0;
182}
183
184static int
185nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
186{
187 struct nv50_disp_priv *priv = (void *)object->engine;
188 struct nv50_disp_dmac *mast = (void *)object;
189
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));
195 if (suspend)
196 return -EBUSY;
197 }
198
199 /* disable error reporting */
200 nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
201 nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
202
203 return nv50_disp_chan_fini(&mast->base, suspend);
204}
205
206struct nouveau_ofuncs
207nvd0_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,
214};
215
216/*******************************************************************************
217 * EVO sync channel objects
218 ******************************************************************************/
219
220static int
221nvd0_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)
225{
226 struct nv50_display_sync_class *args = data;
227 struct nv50_disp_priv *priv = (void *)engine;
228 struct nv50_disp_dmac *dmac;
229 int ret;
230
af1ac18a 231 if (size < sizeof(*args) || args->head >= priv->head.nr)
46654061
BS
232 return -EINVAL;
233
234 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
235 1 + args->head, sizeof(*dmac),
236 (void **)&dmac);
237 *pobject = nv_object(dmac);
238 if (ret)
239 return ret;
240
241 nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach;
242 nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach;
243 return 0;
244}
245
246struct nouveau_ofuncs
247nvd0_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,
254};
255
256/*******************************************************************************
257 * EVO overlay channel objects
258 ******************************************************************************/
259
260static int
261nvd0_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)
265{
266 struct nv50_display_ovly_class *args = data;
267 struct nv50_disp_priv *priv = (void *)engine;
268 struct nv50_disp_dmac *dmac;
269 int ret;
270
af1ac18a 271 if (size < sizeof(*args) || args->head >= priv->head.nr)
46654061
BS
272 return -EINVAL;
273
274 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
275 5 + args->head, sizeof(*dmac),
276 (void **)&dmac);
277 *pobject = nv_object(dmac);
278 if (ret)
279 return ret;
280
281 nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach;
282 nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach;
283 return 0;
284}
285
286struct nouveau_ofuncs
287nvd0_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,
294};
295
296/*******************************************************************************
297 * EVO PIO channel base class
298 ******************************************************************************/
299
300static int
301nvd0_disp_pioc_create_(struct nouveau_object *parent,
302 struct nouveau_object *engine,
303 struct nouveau_oclass *oclass, int chid,
304 int length, void **pobject)
305{
306 return nv50_disp_chan_create_(parent, engine, oclass, chid,
307 length, pobject);
308}
309
310static void
311nvd0_disp_pioc_dtor(struct nouveau_object *object)
312{
313 struct nv50_disp_pioc *pioc = (void *)object;
314 nv50_disp_chan_destroy(&pioc->base);
315}
316
317static int
318nvd0_disp_pioc_init(struct nouveau_object *object)
319{
320 struct nv50_disp_priv *priv = (void *)object->engine;
321 struct nv50_disp_pioc *pioc = (void *)object;
322 int chid = pioc->base.chid;
323 int ret;
324
325 ret = nv50_disp_chan_init(&pioc->base);
326 if (ret)
327 return ret;
328
329 /* enable error reporting */
330 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
331 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
332
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)));
338 return -EBUSY;
339 }
340
341 return 0;
342}
343
344static int
345nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
346{
347 struct nv50_disp_priv *priv = (void *)object->engine;
348 struct nv50_disp_pioc *pioc = (void *)object;
349 int chid = pioc->base.chid;
350
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)));
355 if (suspend)
356 return -EBUSY;
357 }
358
359 /* disable error reporting */
360 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
361 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
362
363 return nv50_disp_chan_fini(&pioc->base, suspend);
364}
365
366/*******************************************************************************
367 * EVO immediate overlay channel objects
368 ******************************************************************************/
369
370static int
371nvd0_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)
375{
376 struct nv50_display_oimm_class *args = data;
377 struct nv50_disp_priv *priv = (void *)engine;
378 struct nv50_disp_pioc *pioc;
379 int ret;
380
381 if (size < sizeof(*args) || args->head >= priv->head.nr)
382 return -EINVAL;
383
384 ret = nvd0_disp_pioc_create_(parent, engine, oclass, 9 + args->head,
385 sizeof(*pioc), (void **)&pioc);
386 *pobject = nv_object(pioc);
387 if (ret)
388 return ret;
389
390 return 0;
391}
392
393struct nouveau_ofuncs
394nvd0_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,
401};
402
403/*******************************************************************************
404 * EVO cursor channel objects
405 ******************************************************************************/
406
407static int
408nvd0_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)
412{
413 struct nv50_display_curs_class *args = data;
414 struct nv50_disp_priv *priv = (void *)engine;
415 struct nv50_disp_pioc *pioc;
416 int ret;
417
418 if (size < sizeof(*args) || args->head >= priv->head.nr)
419 return -EINVAL;
420
421 ret = nvd0_disp_pioc_create_(parent, engine, oclass, 13 + args->head,
422 sizeof(*pioc), (void **)&pioc);
423 *pobject = nv_object(pioc);
424 if (ret)
425 return ret;
426
427 return 0;
428}
429
430struct nouveau_ofuncs
431nvd0_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,
438};
439
440/*******************************************************************************
441 * Base display object
442 ******************************************************************************/
443
1d7c71a3
BS
444static void
445nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
446{
447 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
448}
449
450static void
451nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head)
452{
453 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
454}
455
46654061
BS
456static int
457nvd0_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)
461{
462 struct nv50_disp_priv *priv = (void *)engine;
463 struct nv50_disp_base *base;
464 int ret;
465
466 ret = nouveau_parent_create(parent, engine, oclass, 0,
467 priv->sclass, 0, &base);
468 *pobject = nv_object(base);
469 if (ret)
470 return ret;
471
1d7c71a3
BS
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;
475
46654061
BS
476 return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
477}
478
479static void
480nvd0_disp_base_dtor(struct nouveau_object *object)
481{
482 struct nv50_disp_base *base = (void *)object;
483 nouveau_ramht_ref(NULL, &base->ramht);
484 nouveau_parent_destroy(&base->base);
485}
486
487static int
488nvd0_disp_base_init(struct nouveau_object *object)
489{
490 struct nv50_disp_priv *priv = (void *)object->engine;
491 struct nv50_disp_base *base = (void *)object;
492 int ret, i;
493 u32 tmp;
494
495 ret = nouveau_parent_init(&base->base);
496 if (ret)
497 return ret;
498
499 /* The below segments of code copying values from one register to
500 * another appear to inform EVO of the display capabilities or
501 * something similar.
502 */
503
504 /* ... CRTC caps */
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);
512 }
513
514 /* ... DAC caps */
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);
518 }
519
520 /* ... SOR caps */
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);
524 }
525
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");
532 return -EBUSY;
533 }
534 }
535
536 /* point at display engine memory area (hash table, objects) */
537 nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
538
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);
543
544 return 0;
545}
546
547static int
548nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
549{
550 struct nv50_disp_priv *priv = (void *)object->engine;
551 struct nv50_disp_base *base = (void *)object;
552
553 /* disable all interrupts */
554 nv_wr32(priv, 0x6100b0, 0x00000000);
555
556 return nouveau_parent_fini(&base->base, suspend);
557}
558
559struct nouveau_ofuncs
560nvd0_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,
565};
566
567static struct nouveau_oclass
568nvd0_disp_base_oclass[] = {
6c5a0424 569 { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
46654061 570 {}
ebb945a9
BS
571};
572
573static struct nouveau_oclass
574nvd0_disp_sclass[] = {
46654061
BS
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 },
580 {}
ebb945a9
BS
581};
582
46654061
BS
583/*******************************************************************************
584 * Display engine implementation
585 ******************************************************************************/
586
14464b8c
BS
587static u16
588exec_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)
591{
592 struct nouveau_bios *bios = nouveau_bios(priv);
75f8693f 593 u16 mask, type, data;
14464b8c
BS
594
595 if (outp < 4) {
596 type = DCB_OUTPUT_ANALOG;
597 mask = 0;
598 } else {
599 outp -= 4;
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;
607 default:
608 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
609 return 0x0000;
610 }
611 dcb->sorconf.link = mask;
612 }
613
614 mask = 0x00c0 & (mask << 6);
615 mask |= 0x0001 << outp;
616 mask |= 0x0100 << head;
617
75f8693f
BS
618 data = dcb_outp_match(bios, type, mask, ver, hdr, dcb);
619 if (!data)
620 return 0x0000;
14464b8c 621
75f8693f 622 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
14464b8c
BS
623}
624
625static bool
626exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id)
627{
628 struct nouveau_bios *bios = nouveau_bios(priv);
629 struct nvbios_outp info;
630 struct dcb_output dcb;
631 u8 ver, hdr, cnt, len;
632 u16 data;
633
634 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
635 if (data) {
636 struct nvbios_init init = {
637 .subdev = nv_subdev(priv),
638 .bios = bios,
639 .offset = info.script[id],
640 .outp = &dcb,
641 .crtc = head,
642 .execute = 1,
643 };
644
645 return nvbios_exec(&init) == 0;
646 }
647
648 return false;
649}
650
4a230fa6 651static u32
14464b8c 652exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
4a230fa6 653 u32 ctrl, int id, u32 pclk)
14464b8c
BS
654{
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;
4a230fa6 660 u16 data, conf;
14464b8c
BS
661
662 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info1);
4a230fa6
BS
663 if (data == 0x0000)
664 return false;
665
666 switch (dcb.type) {
667 case DCB_OUTPUT_TMDS:
668 conf = (ctrl & 0x00000f00) >> 8;
669 if (pclk >= 165000)
670 conf |= 0x0100;
671 break;
672 case DCB_OUTPUT_LVDS:
673 conf = priv->sor.lvdsconf;
674 break;
675 case DCB_OUTPUT_DP:
676 conf = (ctrl & 0x00000f00) >> 8;
677 break;
678 case DCB_OUTPUT_ANALOG:
679 default:
680 conf = 0x00ff;
681 break;
682 }
683
684 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
14464b8c 685 if (data) {
4a230fa6 686 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
14464b8c 687 if (data) {
4a230fa6
BS
688 struct nvbios_init init = {
689 .subdev = nv_subdev(priv),
690 .bios = bios,
691 .offset = data,
692 .outp = &dcb,
693 .crtc = head,
694 .execute = 1,
695 };
696
697 if (nvbios_exec(&init))
698 return 0x0000;
699 return conf;
14464b8c
BS
700 }
701 }
702
4a230fa6 703 return 0x0000;
14464b8c
BS
704}
705
706static void
707nvd0_display_unk1_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
708{
709 int i;
710
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);
715 }
716
717 nv_wr32(priv, 0x6101d4, 0x00000000);
718 nv_wr32(priv, 0x6109d4, 0x00000000);
719 nv_wr32(priv, 0x6101d0, 0x80000000);
720}
721
ed58aee9
BS
722static void
723nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or)
724{
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;
ed58aee9
BS
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;
733 const u32 TU = 64;
734 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000;
735 u32 clksor = nv_rd32(priv, 0x612300 + soff);
bf2c886a 736 u32 datarate, link_nr, link_bw, bits;
ed58aee9
BS
737 u64 ratio, value;
738
bf2c886a
BS
739 if ((conf & 0x3c0) == 0x180) bits = 30;
740 else if ((conf & 0x3c0) == 0x140) bits = 24;
741 else bits = 18;
742 datarate = (pclk * bits) / 8;
743
ed58aee9
BS
744 if (dpctrl > 0x00030000) link_nr = 4;
745 else if (dpctrl > 0x00010000) link_nr = 2;
746 else link_nr = 1;
747
748 link_bw = (clksor & 0x007c0000) >> 18;
749 link_bw *= 27000;
750
751 ratio = datarate;
752 ratio *= symbol;
753 do_div(ratio, link_nr * link_bw);
754
755 value = (symbol - ratio) * TU;
756 value *= ratio;
757 do_div(value, symbol);
758 do_div(value, symbol);
759
760 value += 5;
761 value |= 0x08000000;
762
763 nv_wr32(priv, 0x616610 + hoff, value);
764}
765
14464b8c
BS
766static void
767nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
768{
769 u32 pclk;
770 int i;
771
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);
776 }
777
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);
783 }
784
785 nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
786
787 for (i = 0; mask && i < 8; i++) {
4a230fa6 788 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)), cfg;
14464b8c 789 if (mcp & (1 << head)) {
4a230fa6 790 if ((cfg = exec_clkcmp(priv, head, i, mcp, 0, pclk))) {
14464b8c
BS
791 u32 addr, mask, data = 0x00000000;
792 if (i < 4) {
793 addr = 0x612280 + ((i - 0) * 0x800);
794 mask = 0xffffffff;
795 } else {
ed58aee9
BS
796 switch (mcp & 0x00000f00) {
797 case 0x00000800:
798 case 0x00000900:
799 nvd0_display_unk2_calc_tu(priv, head, i - 4);
800 break;
801 default:
802 break;
803 }
804
14464b8c
BS
805 addr = 0x612300 + ((i - 4) * 0x800);
806 mask = 0x00000707;
807 if (cfg & 0x00000100)
808 data = 0x00000101;
809 }
810 nv_mask(priv, addr, mask, data);
811 }
812 break;
813 }
814 }
815
816 nv_wr32(priv, 0x6101d4, 0x00000000);
817 nv_wr32(priv, 0x6109d4, 0x00000000);
818 nv_wr32(priv, 0x6101d0, 0x80000000);
819}
820
821static void
822nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
823{
824 int pclk, i;
825
826 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
827
828 for (i = 0; mask && i < 8; i++) {
829 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
14464b8c 830 if (mcp & (1 << head))
4a230fa6 831 exec_clkcmp(priv, head, i, mcp, 1, pclk);
14464b8c
BS
832 }
833
834 nv_wr32(priv, 0x6101d4, 0x00000000);
835 nv_wr32(priv, 0x6109d4, 0x00000000);
836 nv_wr32(priv, 0x6101d0, 0x80000000);
837}
838
46654061 839void
ebb945a9
BS
840nvd0_disp_intr(struct nouveau_subdev *subdev)
841{
46654061 842 struct nv50_disp_priv *priv = (void *)subdev;
ebb945a9
BS
843 u32 intr = nv_rd32(priv, 0x610088);
844 int i;
845
14464b8c
BS
846 if (intr & 0x00000001) {
847 u32 stat = nv_rd32(priv, 0x61008c);
848 nv_wr32(priv, 0x61008c, stat);
849 intr &= ~0x00000001;
850 }
851
852 if (intr & 0x00000002) {
853 u32 stat = nv_rd32(priv, 0x61009c);
854 int chid = ffs(stat) - 1;
855 if (chid >= 0) {
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));
859
860 nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
861 "0x%08x 0x%08x\n",
862 chid, (mthd & 0x0000ffc), data, mthd, unkn);
863 nv_wr32(priv, 0x61009c, (1 << chid));
864 nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
865 }
866
867 intr &= ~0x00000002;
868 }
869
870 if (intr & 0x00100000) {
871 u32 stat = nv_rd32(priv, 0x6100ac);
872 u32 mask = 0, crtc = ~0;
873
874 while (!mask && ++crtc < priv->head.nr)
875 mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800));
876
877 if (stat & 0x00000001) {
878 nv_wr32(priv, 0x6100ac, 0x00000001);
879 nvd0_display_unk1_handler(priv, crtc, mask);
880 stat &= ~0x00000001;
881 }
882
883 if (stat & 0x00000002) {
884 nv_wr32(priv, 0x6100ac, 0x00000002);
885 nvd0_display_unk2_handler(priv, crtc, mask);
886 stat &= ~0x00000002;
887 }
888
889 if (stat & 0x00000004) {
890 nv_wr32(priv, 0x6100ac, 0x00000004);
891 nvd0_display_unk4_handler(priv, crtc, mask);
892 stat &= ~0x00000004;
893 }
894
895 if (stat) {
896 nv_info(priv, "unknown intr24 0x%08x\n", stat);
897 nv_wr32(priv, 0x6100ac, stat);
898 }
899
900 intr &= ~0x00100000;
901 }
902
903 for (i = 0; i < priv->head.nr; i++) {
ebb945a9
BS
904 u32 mask = 0x01000000 << i;
905 if (mask & intr) {
906 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
907 if (stat & 0x00000001)
1d7c71a3 908 nouveau_event_trigger(priv->base.vblank, i);
ebb945a9
BS
909 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
910 nv_rd32(priv, 0x6100c0 + (i * 0x800));
911 }
912 }
913}
914
915static int
916nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
46654061
BS
917 struct nouveau_oclass *oclass, void *data, u32 size,
918 struct nouveau_object **pobject)
ebb945a9 919{
46654061 920 struct nv50_disp_priv *priv;
1d7c71a3 921 int heads = nv_rd32(parent, 0x022448);
ebb945a9
BS
922 int ret;
923
1d7c71a3
BS
924 ret = nouveau_disp_create(parent, engine, oclass, heads,
925 "PDISP", "display", &priv);
ebb945a9
BS
926 *pobject = nv_object(priv);
927 if (ret)
928 return ret;
929
46654061
BS
930 nv_engine(priv)->sclass = nvd0_disp_base_oclass;
931 nv_engine(priv)->cclass = &nv50_disp_cclass;
ebb945a9 932 nv_subdev(priv)->intr = nvd0_disp_intr;
46654061 933 priv->sclass = nvd0_disp_sclass;
1d7c71a3 934 priv->head.nr = heads;
46654061
BS
935 priv->dac.nr = 3;
936 priv->sor.nr = 4;
35b21d39
BS
937 priv->dac.power = nv50_dac_power;
938 priv->dac.sense = nv50_dac_sense;
74b66850 939 priv->sor.power = nv50_sor_power;
0a9e2b95 940 priv->sor.hda_eld = nvd0_hda_eld;
1c30cd09 941 priv->sor.hdmi = nvd0_hdmi_ctrl;
6c5a0424 942 priv->sor.dp_train = nvd0_sor_dp_train;
8f2abc25
BS
943 priv->sor.dp_train_init = nv94_sor_dp_train_init;
944 priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
6c5a0424
BS
945 priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
946 priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
ebb945a9
BS
947 return 0;
948}
949
950struct nouveau_oclass
951nvd0_disp_oclass = {
46654061 952 .handle = NV_ENGINE(DISP, 0x90),
ebb945a9
BS
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,
958 },
959};
This page took 0.166866 seconds and 5 git commands to generate.