drm/nv50-/disp: move DP link training to core and train from supervisor
[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,
0a0afd28 653 u32 ctrl, int id, u32 pclk, struct dcb_output *dcb)
14464b8c
BS
654{
655 struct nouveau_bios *bios = nouveau_bios(priv);
656 struct nvbios_outp info1;
657 struct nvbios_ocfg info2;
14464b8c 658 u8 ver, hdr, cnt, len;
46c13c13 659 u32 data, conf = ~0;
14464b8c 660
0a0afd28 661 data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1);
4a230fa6 662 if (data == 0x0000)
46c13c13 663 return conf;
4a230fa6 664
0a0afd28 665 switch (dcb->type) {
4a230fa6
BS
666 case DCB_OUTPUT_TMDS:
667 conf = (ctrl & 0x00000f00) >> 8;
668 if (pclk >= 165000)
669 conf |= 0x0100;
670 break;
671 case DCB_OUTPUT_LVDS:
672 conf = priv->sor.lvdsconf;
673 break;
674 case DCB_OUTPUT_DP:
675 conf = (ctrl & 0x00000f00) >> 8;
676 break;
677 case DCB_OUTPUT_ANALOG:
678 default:
679 conf = 0x00ff;
680 break;
681 }
682
683 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
0a0afd28 684 if (data && id < 0xff) {
4a230fa6 685 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
14464b8c 686 if (data) {
4a230fa6
BS
687 struct nvbios_init init = {
688 .subdev = nv_subdev(priv),
689 .bios = bios,
690 .offset = data,
0a0afd28 691 .outp = dcb,
4a230fa6
BS
692 .crtc = head,
693 .execute = 1,
694 };
695
46c13c13 696 nvbios_exec(&init);
14464b8c
BS
697 }
698 }
699
46c13c13 700 return conf;
14464b8c
BS
701}
702
703static void
704nvd0_display_unk1_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
705{
706 int i;
707
708 for (i = 0; mask && i < 8; i++) {
709 u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20));
710 if (mcc & (1 << head))
711 exec_script(priv, head, i, mcc, 1);
712 }
713
714 nv_wr32(priv, 0x6101d4, 0x00000000);
715 nv_wr32(priv, 0x6109d4, 0x00000000);
716 nv_wr32(priv, 0x6101d0, 0x80000000);
717}
718
ed58aee9
BS
719static void
720nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or)
721{
722 const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
723 const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
724 const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
ed58aee9
BS
725 const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
726 const u32 hoff = (head * 0x800);
727 const u32 soff = ( or * 0x800);
728 const u32 loff = (link * 0x080) + soff;
729 const u32 symbol = 100000;
730 const u32 TU = 64;
731 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000;
732 u32 clksor = nv_rd32(priv, 0x612300 + soff);
bf2c886a 733 u32 datarate, link_nr, link_bw, bits;
ed58aee9
BS
734 u64 ratio, value;
735
bf2c886a
BS
736 if ((conf & 0x3c0) == 0x180) bits = 30;
737 else if ((conf & 0x3c0) == 0x140) bits = 24;
738 else bits = 18;
739 datarate = (pclk * bits) / 8;
740
ed58aee9
BS
741 if (dpctrl > 0x00030000) link_nr = 4;
742 else if (dpctrl > 0x00010000) link_nr = 2;
743 else link_nr = 1;
744
745 link_bw = (clksor & 0x007c0000) >> 18;
746 link_bw *= 27000;
747
748 ratio = datarate;
749 ratio *= symbol;
750 do_div(ratio, link_nr * link_bw);
751
752 value = (symbol - ratio) * TU;
753 value *= ratio;
754 do_div(value, symbol);
755 do_div(value, symbol);
756
757 value += 5;
758 value |= 0x08000000;
759
760 nv_wr32(priv, 0x616610 + hoff, value);
761}
762
14464b8c
BS
763static void
764nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
765{
0a0afd28 766 struct dcb_output outp;
14464b8c
BS
767 u32 pclk;
768 int i;
769
770 for (i = 0; mask && i < 8; i++) {
771 u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20));
772 if (mcc & (1 << head))
773 exec_script(priv, head, i, mcc, 2);
774 }
775
776 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
777 nv_debug(priv, "head %d pclk %d mask 0x%08x\n", head, pclk, mask);
778 if (pclk && (mask & 0x00010000)) {
779 struct nouveau_clock *clk = nouveau_clock(priv);
780 clk->pll_set(clk, PLL_VPLL0 + head, pclk);
781 }
782
783 nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
784
785 for (i = 0; mask && i < 8; i++) {
46c13c13 786 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
14464b8c 787 if (mcp & (1 << head)) {
0a0afd28 788 u32 cfg = exec_clkcmp(priv, head, i, mcp, 0xff, pclk, &outp);
46c13c13 789 if (cfg != ~0) {
14464b8c 790 u32 addr, mask, data = 0x00000000;
0a0afd28
BS
791
792 if (outp.type == DCB_OUTPUT_DP) {
793 switch ((mcp & 0x000f0000) >> 16) {
794 case 6: pclk = pclk * 30 / 8; break;
795 case 5: pclk = pclk * 24 / 8; break;
796 case 2:
797 default:
798 pclk = pclk * 18 / 8;
799 break;
800 }
801
802 nouveau_dp_train(&priv->base,
803 priv->sor.dp,
804 &outp, head, pclk);
805 }
806
807 exec_clkcmp(priv, head, i, mcp, 0, pclk, &outp);
808
14464b8c
BS
809 if (i < 4) {
810 addr = 0x612280 + ((i - 0) * 0x800);
811 mask = 0xffffffff;
812 } else {
ed58aee9
BS
813 switch (mcp & 0x00000f00) {
814 case 0x00000800:
815 case 0x00000900:
816 nvd0_display_unk2_calc_tu(priv, head, i - 4);
817 break;
818 default:
819 break;
820 }
821
14464b8c
BS
822 addr = 0x612300 + ((i - 4) * 0x800);
823 mask = 0x00000707;
824 if (cfg & 0x00000100)
825 data = 0x00000101;
826 }
827 nv_mask(priv, addr, mask, data);
828 }
829 break;
830 }
831 }
832
833 nv_wr32(priv, 0x6101d4, 0x00000000);
834 nv_wr32(priv, 0x6109d4, 0x00000000);
835 nv_wr32(priv, 0x6101d0, 0x80000000);
836}
837
838static void
839nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
840{
0a0afd28 841 struct dcb_output outp;
14464b8c
BS
842 int pclk, i;
843
844 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
845
846 for (i = 0; mask && i < 8; i++) {
847 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
14464b8c 848 if (mcp & (1 << head))
0a0afd28 849 exec_clkcmp(priv, head, i, mcp, 1, pclk, &outp);
14464b8c
BS
850 }
851
852 nv_wr32(priv, 0x6101d4, 0x00000000);
853 nv_wr32(priv, 0x6109d4, 0x00000000);
854 nv_wr32(priv, 0x6101d0, 0x80000000);
855}
856
5cc027f6
BS
857void
858nvd0_disp_intr_supervisor(struct work_struct *work)
859{
860 struct nv50_disp_priv *priv =
861 container_of(work, struct nv50_disp_priv, supervisor);
862 u32 mask = 0, head = ~0;
863
864 while (!mask && ++head < priv->head.nr)
865 mask = nv_rd32(priv, 0x6101d4 + (head * 0x800));
866
867 nv_debug(priv, "supervisor %08x %08x %d\n", priv->super, mask, head);
868
869 if (priv->super & 0x00000001)
870 nvd0_display_unk1_handler(priv, head, mask);
871 if (priv->super & 0x00000002)
872 nvd0_display_unk2_handler(priv, head, mask);
873 if (priv->super & 0x00000004)
874 nvd0_display_unk4_handler(priv, head, mask);
875}
876
46654061 877void
ebb945a9
BS
878nvd0_disp_intr(struct nouveau_subdev *subdev)
879{
46654061 880 struct nv50_disp_priv *priv = (void *)subdev;
ebb945a9
BS
881 u32 intr = nv_rd32(priv, 0x610088);
882 int i;
883
14464b8c
BS
884 if (intr & 0x00000001) {
885 u32 stat = nv_rd32(priv, 0x61008c);
886 nv_wr32(priv, 0x61008c, stat);
887 intr &= ~0x00000001;
888 }
889
890 if (intr & 0x00000002) {
891 u32 stat = nv_rd32(priv, 0x61009c);
892 int chid = ffs(stat) - 1;
893 if (chid >= 0) {
894 u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
895 u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
896 u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
897
898 nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
899 "0x%08x 0x%08x\n",
900 chid, (mthd & 0x0000ffc), data, mthd, unkn);
901 nv_wr32(priv, 0x61009c, (1 << chid));
902 nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
903 }
904
905 intr &= ~0x00000002;
906 }
907
908 if (intr & 0x00100000) {
909 u32 stat = nv_rd32(priv, 0x6100ac);
5cc027f6
BS
910 if (stat & 0x00000007) {
911 priv->super = (stat & 0x00000007);
912 schedule_work(&priv->supervisor);
913 nv_wr32(priv, 0x6100ac, priv->super);
914 stat &= ~0x00000007;
14464b8c
BS
915 }
916
917 if (stat) {
918 nv_info(priv, "unknown intr24 0x%08x\n", stat);
919 nv_wr32(priv, 0x6100ac, stat);
920 }
921
922 intr &= ~0x00100000;
923 }
924
925 for (i = 0; i < priv->head.nr; i++) {
ebb945a9
BS
926 u32 mask = 0x01000000 << i;
927 if (mask & intr) {
928 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
929 if (stat & 0x00000001)
1d7c71a3 930 nouveau_event_trigger(priv->base.vblank, i);
ebb945a9
BS
931 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
932 nv_rd32(priv, 0x6100c0 + (i * 0x800));
933 }
934 }
935}
936
937static int
938nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
46654061
BS
939 struct nouveau_oclass *oclass, void *data, u32 size,
940 struct nouveau_object **pobject)
ebb945a9 941{
46654061 942 struct nv50_disp_priv *priv;
1d7c71a3 943 int heads = nv_rd32(parent, 0x022448);
ebb945a9
BS
944 int ret;
945
1d7c71a3
BS
946 ret = nouveau_disp_create(parent, engine, oclass, heads,
947 "PDISP", "display", &priv);
ebb945a9
BS
948 *pobject = nv_object(priv);
949 if (ret)
950 return ret;
951
46654061
BS
952 nv_engine(priv)->sclass = nvd0_disp_base_oclass;
953 nv_engine(priv)->cclass = &nv50_disp_cclass;
ebb945a9 954 nv_subdev(priv)->intr = nvd0_disp_intr;
5cc027f6 955 INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
46654061 956 priv->sclass = nvd0_disp_sclass;
1d7c71a3 957 priv->head.nr = heads;
46654061
BS
958 priv->dac.nr = 3;
959 priv->sor.nr = 4;
35b21d39
BS
960 priv->dac.power = nv50_dac_power;
961 priv->dac.sense = nv50_dac_sense;
74b66850 962 priv->sor.power = nv50_sor_power;
0a9e2b95 963 priv->sor.hda_eld = nvd0_hda_eld;
1c30cd09 964 priv->sor.hdmi = nvd0_hdmi_ctrl;
0a0afd28 965 priv->sor.dp = &nvd0_sor_dp_func;
ebb945a9
BS
966 return 0;
967}
968
969struct nouveau_oclass
970nvd0_disp_oclass = {
46654061 971 .handle = NV_ENGINE(DISP, 0x90),
ebb945a9
BS
972 .ofuncs = &(struct nouveau_ofuncs) {
973 .ctor = nvd0_disp_ctor,
974 .dtor = _nouveau_disp_dtor,
975 .init = _nouveau_disp_init,
976 .fini = _nouveau_disp_fini,
977 },
978};
This page took 0.093294 seconds and 5 git commands to generate.