drm/nvd0/disp: move HDMI control to core
[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
BS
29
30#include <engine/software.h>
31#include <engine/disp.h>
32
46654061
BS
33#include <subdev/timer.h>
34#include <subdev/fb.h>
35#include <subdev/bar.h>
14464b8c
BS
36#include <subdev/clock.h>
37
38#include <subdev/bios.h>
39#include <subdev/bios/dcb.h>
40#include <subdev/bios/disp.h>
41#include <subdev/bios/init.h>
42#include <subdev/bios/pll.h>
46654061
BS
43
44#include "nv50.h"
45
46/*******************************************************************************
47 * EVO DMA channel base class
48 ******************************************************************************/
49
50static int
51nvd0_disp_dmac_object_attach(struct nouveau_object *parent,
52 struct nouveau_object *object, u32 name)
53{
54 struct nv50_disp_base *base = (void *)parent->parent;
55 struct nv50_disp_chan *chan = (void *)parent;
56 u32 addr = nv_gpuobj(object)->node->offset;
57 u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
58 return nouveau_ramht_insert(base->ramht, chan->chid, name, data);
59}
60
61static void
62nvd0_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
63{
64 struct nv50_disp_base *base = (void *)parent->parent;
65 nouveau_ramht_remove(base->ramht, cookie);
66}
67
68static int
69nvd0_disp_dmac_init(struct nouveau_object *object)
70{
71 struct nv50_disp_priv *priv = (void *)object->engine;
72 struct nv50_disp_dmac *dmac = (void *)object;
73 int chid = dmac->base.chid;
74 int ret;
75
76 ret = nv50_disp_chan_init(&dmac->base);
77 if (ret)
78 return ret;
79
80 /* enable error reporting */
81 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
82 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
83
84 /* initialise channel for dma command submission */
85 nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push);
86 nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000);
87 nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001);
88 nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
89 nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
90 nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013);
91
92 /* wait for it to go inactive */
93 if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) {
94 nv_error(dmac, "init: 0x%08x\n",
95 nv_rd32(priv, 0x610490 + (chid * 0x10)));
96 return -EBUSY;
97 }
98
99 return 0;
100}
101
102static int
103nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
104{
105 struct nv50_disp_priv *priv = (void *)object->engine;
106 struct nv50_disp_dmac *dmac = (void *)object;
107 int chid = dmac->base.chid;
108
109 /* deactivate channel */
110 nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
111 nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
112 if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) {
113 nv_error(dmac, "fini: 0x%08x\n",
114 nv_rd32(priv, 0x610490 + (chid * 0x10)));
115 if (suspend)
116 return -EBUSY;
117 }
118
119 /* disable error reporting */
120 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
121 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
122
123 return nv50_disp_chan_fini(&dmac->base, suspend);
124}
125
126/*******************************************************************************
127 * EVO master channel object
128 ******************************************************************************/
129
130static int
131nvd0_disp_mast_ctor(struct nouveau_object *parent,
132 struct nouveau_object *engine,
133 struct nouveau_oclass *oclass, void *data, u32 size,
134 struct nouveau_object **pobject)
135{
136 struct nv50_display_mast_class *args = data;
137 struct nv50_disp_dmac *mast;
138 int ret;
139
140 if (size < sizeof(*args))
141 return -EINVAL;
142
143 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
144 0, sizeof(*mast), (void **)&mast);
145 *pobject = nv_object(mast);
146 if (ret)
147 return ret;
148
149 nv_parent(mast)->object_attach = nvd0_disp_dmac_object_attach;
150 nv_parent(mast)->object_detach = nvd0_disp_dmac_object_detach;
151 return 0;
152}
153
154static int
155nvd0_disp_mast_init(struct nouveau_object *object)
156{
157 struct nv50_disp_priv *priv = (void *)object->engine;
158 struct nv50_disp_dmac *mast = (void *)object;
159 int ret;
160
161 ret = nv50_disp_chan_init(&mast->base);
162 if (ret)
163 return ret;
164
165 /* enable error reporting */
166 nv_mask(priv, 0x610090, 0x00000001, 0x00000001);
167 nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
168
169 /* initialise channel for dma command submission */
170 nv_wr32(priv, 0x610494, mast->push);
171 nv_wr32(priv, 0x610498, 0x00010000);
172 nv_wr32(priv, 0x61049c, 0x00000001);
173 nv_mask(priv, 0x610490, 0x00000010, 0x00000010);
174 nv_wr32(priv, 0x640000, 0x00000000);
175 nv_wr32(priv, 0x610490, 0x01000013);
176
177 /* wait for it to go inactive */
178 if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) {
179 nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490));
180 return -EBUSY;
181 }
182
183 return 0;
184}
185
186static int
187nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
188{
189 struct nv50_disp_priv *priv = (void *)object->engine;
190 struct nv50_disp_dmac *mast = (void *)object;
191
192 /* deactivate channel */
193 nv_mask(priv, 0x610490, 0x00000010, 0x00000000);
194 nv_mask(priv, 0x610490, 0x00000003, 0x00000000);
195 if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) {
196 nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490));
197 if (suspend)
198 return -EBUSY;
199 }
200
201 /* disable error reporting */
202 nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
203 nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
204
205 return nv50_disp_chan_fini(&mast->base, suspend);
206}
207
208struct nouveau_ofuncs
209nvd0_disp_mast_ofuncs = {
210 .ctor = nvd0_disp_mast_ctor,
211 .dtor = nv50_disp_dmac_dtor,
212 .init = nvd0_disp_mast_init,
213 .fini = nvd0_disp_mast_fini,
214 .rd32 = nv50_disp_chan_rd32,
215 .wr32 = nv50_disp_chan_wr32,
216};
217
218/*******************************************************************************
219 * EVO sync channel objects
220 ******************************************************************************/
221
222static int
223nvd0_disp_sync_ctor(struct nouveau_object *parent,
224 struct nouveau_object *engine,
225 struct nouveau_oclass *oclass, void *data, u32 size,
226 struct nouveau_object **pobject)
227{
228 struct nv50_display_sync_class *args = data;
229 struct nv50_disp_priv *priv = (void *)engine;
230 struct nv50_disp_dmac *dmac;
231 int ret;
232
233 if (size < sizeof(*data) || args->head >= priv->head.nr)
234 return -EINVAL;
235
236 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
237 1 + args->head, sizeof(*dmac),
238 (void **)&dmac);
239 *pobject = nv_object(dmac);
240 if (ret)
241 return ret;
242
243 nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach;
244 nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach;
245 return 0;
246}
247
248struct nouveau_ofuncs
249nvd0_disp_sync_ofuncs = {
250 .ctor = nvd0_disp_sync_ctor,
251 .dtor = nv50_disp_dmac_dtor,
252 .init = nvd0_disp_dmac_init,
253 .fini = nvd0_disp_dmac_fini,
254 .rd32 = nv50_disp_chan_rd32,
255 .wr32 = nv50_disp_chan_wr32,
256};
257
258/*******************************************************************************
259 * EVO overlay channel objects
260 ******************************************************************************/
261
262static int
263nvd0_disp_ovly_ctor(struct nouveau_object *parent,
264 struct nouveau_object *engine,
265 struct nouveau_oclass *oclass, void *data, u32 size,
266 struct nouveau_object **pobject)
267{
268 struct nv50_display_ovly_class *args = data;
269 struct nv50_disp_priv *priv = (void *)engine;
270 struct nv50_disp_dmac *dmac;
271 int ret;
272
273 if (size < sizeof(*data) || args->head >= priv->head.nr)
274 return -EINVAL;
275
276 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
277 5 + args->head, sizeof(*dmac),
278 (void **)&dmac);
279 *pobject = nv_object(dmac);
280 if (ret)
281 return ret;
282
283 nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach;
284 nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach;
285 return 0;
286}
287
288struct nouveau_ofuncs
289nvd0_disp_ovly_ofuncs = {
290 .ctor = nvd0_disp_ovly_ctor,
291 .dtor = nv50_disp_dmac_dtor,
292 .init = nvd0_disp_dmac_init,
293 .fini = nvd0_disp_dmac_fini,
294 .rd32 = nv50_disp_chan_rd32,
295 .wr32 = nv50_disp_chan_wr32,
296};
297
298/*******************************************************************************
299 * EVO PIO channel base class
300 ******************************************************************************/
301
302static int
303nvd0_disp_pioc_create_(struct nouveau_object *parent,
304 struct nouveau_object *engine,
305 struct nouveau_oclass *oclass, int chid,
306 int length, void **pobject)
307{
308 return nv50_disp_chan_create_(parent, engine, oclass, chid,
309 length, pobject);
310}
311
312static void
313nvd0_disp_pioc_dtor(struct nouveau_object *object)
314{
315 struct nv50_disp_pioc *pioc = (void *)object;
316 nv50_disp_chan_destroy(&pioc->base);
317}
318
319static int
320nvd0_disp_pioc_init(struct nouveau_object *object)
321{
322 struct nv50_disp_priv *priv = (void *)object->engine;
323 struct nv50_disp_pioc *pioc = (void *)object;
324 int chid = pioc->base.chid;
325 int ret;
326
327 ret = nv50_disp_chan_init(&pioc->base);
328 if (ret)
329 return ret;
330
331 /* enable error reporting */
332 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
333 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
334
335 /* activate channel */
336 nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001);
337 if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) {
338 nv_error(pioc, "init: 0x%08x\n",
339 nv_rd32(priv, 0x610490 + (chid * 0x10)));
340 return -EBUSY;
341 }
342
343 return 0;
344}
345
346static int
347nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
348{
349 struct nv50_disp_priv *priv = (void *)object->engine;
350 struct nv50_disp_pioc *pioc = (void *)object;
351 int chid = pioc->base.chid;
352
353 nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
354 if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) {
355 nv_error(pioc, "timeout: 0x%08x\n",
356 nv_rd32(priv, 0x610490 + (chid * 0x10)));
357 if (suspend)
358 return -EBUSY;
359 }
360
361 /* disable error reporting */
362 nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
363 nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
364
365 return nv50_disp_chan_fini(&pioc->base, suspend);
366}
367
368/*******************************************************************************
369 * EVO immediate overlay channel objects
370 ******************************************************************************/
371
372static int
373nvd0_disp_oimm_ctor(struct nouveau_object *parent,
374 struct nouveau_object *engine,
375 struct nouveau_oclass *oclass, void *data, u32 size,
376 struct nouveau_object **pobject)
377{
378 struct nv50_display_oimm_class *args = data;
379 struct nv50_disp_priv *priv = (void *)engine;
380 struct nv50_disp_pioc *pioc;
381 int ret;
382
383 if (size < sizeof(*args) || args->head >= priv->head.nr)
384 return -EINVAL;
385
386 ret = nvd0_disp_pioc_create_(parent, engine, oclass, 9 + args->head,
387 sizeof(*pioc), (void **)&pioc);
388 *pobject = nv_object(pioc);
389 if (ret)
390 return ret;
391
392 return 0;
393}
394
395struct nouveau_ofuncs
396nvd0_disp_oimm_ofuncs = {
397 .ctor = nvd0_disp_oimm_ctor,
398 .dtor = nvd0_disp_pioc_dtor,
399 .init = nvd0_disp_pioc_init,
400 .fini = nvd0_disp_pioc_fini,
401 .rd32 = nv50_disp_chan_rd32,
402 .wr32 = nv50_disp_chan_wr32,
403};
404
405/*******************************************************************************
406 * EVO cursor channel objects
407 ******************************************************************************/
408
409static int
410nvd0_disp_curs_ctor(struct nouveau_object *parent,
411 struct nouveau_object *engine,
412 struct nouveau_oclass *oclass, void *data, u32 size,
413 struct nouveau_object **pobject)
414{
415 struct nv50_display_curs_class *args = data;
416 struct nv50_disp_priv *priv = (void *)engine;
417 struct nv50_disp_pioc *pioc;
418 int ret;
419
420 if (size < sizeof(*args) || args->head >= priv->head.nr)
421 return -EINVAL;
422
423 ret = nvd0_disp_pioc_create_(parent, engine, oclass, 13 + args->head,
424 sizeof(*pioc), (void **)&pioc);
425 *pobject = nv_object(pioc);
426 if (ret)
427 return ret;
428
429 return 0;
430}
431
432struct nouveau_ofuncs
433nvd0_disp_curs_ofuncs = {
434 .ctor = nvd0_disp_curs_ctor,
435 .dtor = nvd0_disp_pioc_dtor,
436 .init = nvd0_disp_pioc_init,
437 .fini = nvd0_disp_pioc_fini,
438 .rd32 = nv50_disp_chan_rd32,
439 .wr32 = nv50_disp_chan_wr32,
440};
441
442/*******************************************************************************
443 * Base display object
444 ******************************************************************************/
445
446static int
447nvd0_disp_base_ctor(struct nouveau_object *parent,
448 struct nouveau_object *engine,
449 struct nouveau_oclass *oclass, void *data, u32 size,
450 struct nouveau_object **pobject)
451{
452 struct nv50_disp_priv *priv = (void *)engine;
453 struct nv50_disp_base *base;
454 int ret;
455
456 ret = nouveau_parent_create(parent, engine, oclass, 0,
457 priv->sclass, 0, &base);
458 *pobject = nv_object(base);
459 if (ret)
460 return ret;
461
462 return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
463}
464
465static void
466nvd0_disp_base_dtor(struct nouveau_object *object)
467{
468 struct nv50_disp_base *base = (void *)object;
469 nouveau_ramht_ref(NULL, &base->ramht);
470 nouveau_parent_destroy(&base->base);
471}
472
473static int
474nvd0_disp_base_init(struct nouveau_object *object)
475{
476 struct nv50_disp_priv *priv = (void *)object->engine;
477 struct nv50_disp_base *base = (void *)object;
478 int ret, i;
479 u32 tmp;
480
481 ret = nouveau_parent_init(&base->base);
482 if (ret)
483 return ret;
484
485 /* The below segments of code copying values from one register to
486 * another appear to inform EVO of the display capabilities or
487 * something similar.
488 */
489
490 /* ... CRTC caps */
491 for (i = 0; i < priv->head.nr; i++) {
492 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
493 nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp);
494 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
495 nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp);
496 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
497 nv_wr32(priv, 0x6101bc + (i * 0x800), tmp);
498 }
499
500 /* ... DAC caps */
501 for (i = 0; i < priv->dac.nr; i++) {
502 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
503 nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp);
504 }
505
506 /* ... SOR caps */
507 for (i = 0; i < priv->sor.nr; i++) {
508 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
509 nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp);
510 }
511
512 /* steal display away from vbios, or something like that */
513 if (nv_rd32(priv, 0x6100ac) & 0x00000100) {
514 nv_wr32(priv, 0x6100ac, 0x00000100);
515 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
516 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
517 nv_error(priv, "timeout acquiring display\n");
518 return -EBUSY;
519 }
520 }
521
522 /* point at display engine memory area (hash table, objects) */
523 nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
524
525 /* enable supervisor interrupts, disable everything else */
526 nv_wr32(priv, 0x610090, 0x00000000);
527 nv_wr32(priv, 0x6100a0, 0x00000000);
528 nv_wr32(priv, 0x6100b0, 0x00000307);
529
530 return 0;
531}
532
533static int
534nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
535{
536 struct nv50_disp_priv *priv = (void *)object->engine;
537 struct nv50_disp_base *base = (void *)object;
538
539 /* disable all interrupts */
540 nv_wr32(priv, 0x6100b0, 0x00000000);
541
542 return nouveau_parent_fini(&base->base, suspend);
543}
544
545struct nouveau_ofuncs
546nvd0_disp_base_ofuncs = {
547 .ctor = nvd0_disp_base_ctor,
548 .dtor = nvd0_disp_base_dtor,
549 .init = nvd0_disp_base_init,
550 .fini = nvd0_disp_base_fini,
551};
552
553static struct nouveau_oclass
554nvd0_disp_base_oclass[] = {
6c5a0424 555 { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
46654061 556 {}
ebb945a9
BS
557};
558
559static struct nouveau_oclass
560nvd0_disp_sclass[] = {
46654061
BS
561 { NVD0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs },
562 { NVD0_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs },
563 { NVD0_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs },
564 { NVD0_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs },
565 { NVD0_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs },
566 {}
ebb945a9
BS
567};
568
46654061
BS
569/*******************************************************************************
570 * Display engine implementation
571 ******************************************************************************/
572
14464b8c
BS
573static u16
574exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
575 struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
576 struct nvbios_outp *info)
577{
578 struct nouveau_bios *bios = nouveau_bios(priv);
579 u16 data, idx = 0;
580 u16 mask, type;
581
582 if (outp < 4) {
583 type = DCB_OUTPUT_ANALOG;
584 mask = 0;
585 } else {
586 outp -= 4;
587 switch (ctrl & 0x00000f00) {
588 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
589 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
590 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
591 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
592 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
593 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
594 default:
595 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
596 return 0x0000;
597 }
598 dcb->sorconf.link = mask;
599 }
600
601 mask = 0x00c0 & (mask << 6);
602 mask |= 0x0001 << outp;
603 mask |= 0x0100 << head;
604
605 /* this is a tad special, but for the moment its needed to get
606 * all the dcb data required by the vbios scripts.. will be cleaned
607 * up later as more bits are moved to the core..
608 */
609 while ((data = dcb_outp(bios, idx++, ver, hdr))) {
610 u32 conn = nv_ro32(bios, data + 0);
611 u32 conf = nv_ro32(bios, data + 4);
612 if ((conn & 0x00300000) ||
613 (conn & 0x0000000f) != type ||
614 (conn & 0x0f000000) != (0x01000000 << outp))
615 continue;
616
617 if ( (mask & 0x00c0) && (mask & 0x00c0) !=
618 ((mask & 0x00c0) & ((conf & 0x00000030) << 2)))
619 continue;
620
621 dcb->type = type;
622 dcb->or = 1 << outp;
623 dcb->connector = (conn & 0x0000f000) >> 12;
624
625 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
626 }
627
628 return 0x0000;
629}
630
631static bool
632exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id)
633{
634 struct nouveau_bios *bios = nouveau_bios(priv);
635 struct nvbios_outp info;
636 struct dcb_output dcb;
637 u8 ver, hdr, cnt, len;
638 u16 data;
639
640 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
641 if (data) {
642 struct nvbios_init init = {
643 .subdev = nv_subdev(priv),
644 .bios = bios,
645 .offset = info.script[id],
646 .outp = &dcb,
647 .crtc = head,
648 .execute = 1,
649 };
650
651 return nvbios_exec(&init) == 0;
652 }
653
654 return false;
655}
656
657static bool
658exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
659 u32 ctrl, u32 conf, int id, u32 pclk)
660{
661 struct nouveau_bios *bios = nouveau_bios(priv);
662 struct nvbios_outp info1;
663 struct nvbios_ocfg info2;
664 struct dcb_output dcb;
665 u8 ver, hdr, cnt, len;
666 u16 data;
667
668 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info1);
669 if (data) {
670 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
671 if (data) {
672 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
673 if (data) {
674 struct nvbios_init init = {
675 .subdev = nv_subdev(priv),
676 .bios = bios,
677 .offset = data,
678 .outp = &dcb,
679 .crtc = head,
680 .execute = 1,
681 };
682
683 return nvbios_exec(&init) == 0;
684 }
685 }
686 }
687
688 return false;
689}
690
691static void
692nvd0_display_unk1_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
693{
694 int i;
695
696 for (i = 0; mask && i < 8; i++) {
697 u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20));
698 if (mcc & (1 << head))
699 exec_script(priv, head, i, mcc, 1);
700 }
701
702 nv_wr32(priv, 0x6101d4, 0x00000000);
703 nv_wr32(priv, 0x6109d4, 0x00000000);
704 nv_wr32(priv, 0x6101d0, 0x80000000);
705}
706
707static void
708nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
709{
710 u32 pclk;
711 int i;
712
713 for (i = 0; mask && i < 8; i++) {
714 u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20));
715 if (mcc & (1 << head))
716 exec_script(priv, head, i, mcc, 2);
717 }
718
719 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
720 nv_debug(priv, "head %d pclk %d mask 0x%08x\n", head, pclk, mask);
721 if (pclk && (mask & 0x00010000)) {
722 struct nouveau_clock *clk = nouveau_clock(priv);
723 clk->pll_set(clk, PLL_VPLL0 + head, pclk);
724 }
725
726 nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
727
728 for (i = 0; mask && i < 8; i++) {
729 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
730 u32 cfg = nv_rd32(priv, 0x660184 + (i * 0x20));
731 if (mcp & (1 << head)) {
732 if (exec_clkcmp(priv, head, i, mcp, cfg, 0, pclk)) {
733 u32 addr, mask, data = 0x00000000;
734 if (i < 4) {
735 addr = 0x612280 + ((i - 0) * 0x800);
736 mask = 0xffffffff;
737 } else {
738 addr = 0x612300 + ((i - 4) * 0x800);
739 mask = 0x00000707;
740 if (cfg & 0x00000100)
741 data = 0x00000101;
742 }
743 nv_mask(priv, addr, mask, data);
744 }
745 break;
746 }
747 }
748
749 nv_wr32(priv, 0x6101d4, 0x00000000);
750 nv_wr32(priv, 0x6109d4, 0x00000000);
751 nv_wr32(priv, 0x6101d0, 0x80000000);
752}
753
754static void
755nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
756{
757 int pclk, i;
758
759 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
760
761 for (i = 0; mask && i < 8; i++) {
762 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
763 u32 cfg = nv_rd32(priv, 0x660184 + (i * 0x20));
764 if (mcp & (1 << head))
765 exec_clkcmp(priv, head, i, mcp, cfg, 1, pclk);
766 }
767
768 nv_wr32(priv, 0x6101d4, 0x00000000);
769 nv_wr32(priv, 0x6109d4, 0x00000000);
770 nv_wr32(priv, 0x6101d0, 0x80000000);
771}
772
ebb945a9 773static void
46654061 774nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
ebb945a9
BS
775{
776 struct nouveau_bar *bar = nouveau_bar(priv);
777 struct nouveau_disp *disp = &priv->base;
778 struct nouveau_software_chan *chan, *temp;
779 unsigned long flags;
780
781 spin_lock_irqsave(&disp->vblank.lock, flags);
782 list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
783 if (chan->vblank.crtc != crtc)
784 continue;
785
786 nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
787 bar->flush(bar);
788 nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
789 nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
790 nv_wr32(priv, 0x060014, chan->vblank.value);
791
792 list_del(&chan->vblank.head);
793 if (disp->vblank.put)
794 disp->vblank.put(disp->vblank.data, crtc);
795 }
796 spin_unlock_irqrestore(&disp->vblank.lock, flags);
797
798 if (disp->vblank.notify)
799 disp->vblank.notify(disp->vblank.data, crtc);
800}
801
46654061 802void
ebb945a9
BS
803nvd0_disp_intr(struct nouveau_subdev *subdev)
804{
46654061 805 struct nv50_disp_priv *priv = (void *)subdev;
ebb945a9
BS
806 u32 intr = nv_rd32(priv, 0x610088);
807 int i;
808
14464b8c
BS
809 if (intr & 0x00000001) {
810 u32 stat = nv_rd32(priv, 0x61008c);
811 nv_wr32(priv, 0x61008c, stat);
812 intr &= ~0x00000001;
813 }
814
815 if (intr & 0x00000002) {
816 u32 stat = nv_rd32(priv, 0x61009c);
817 int chid = ffs(stat) - 1;
818 if (chid >= 0) {
819 u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
820 u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
821 u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
822
823 nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
824 "0x%08x 0x%08x\n",
825 chid, (mthd & 0x0000ffc), data, mthd, unkn);
826 nv_wr32(priv, 0x61009c, (1 << chid));
827 nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
828 }
829
830 intr &= ~0x00000002;
831 }
832
833 if (intr & 0x00100000) {
834 u32 stat = nv_rd32(priv, 0x6100ac);
835 u32 mask = 0, crtc = ~0;
836
837 while (!mask && ++crtc < priv->head.nr)
838 mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800));
839
840 if (stat & 0x00000001) {
841 nv_wr32(priv, 0x6100ac, 0x00000001);
842 nvd0_display_unk1_handler(priv, crtc, mask);
843 stat &= ~0x00000001;
844 }
845
846 if (stat & 0x00000002) {
847 nv_wr32(priv, 0x6100ac, 0x00000002);
848 nvd0_display_unk2_handler(priv, crtc, mask);
849 stat &= ~0x00000002;
850 }
851
852 if (stat & 0x00000004) {
853 nv_wr32(priv, 0x6100ac, 0x00000004);
854 nvd0_display_unk4_handler(priv, crtc, mask);
855 stat &= ~0x00000004;
856 }
857
858 if (stat) {
859 nv_info(priv, "unknown intr24 0x%08x\n", stat);
860 nv_wr32(priv, 0x6100ac, stat);
861 }
862
863 intr &= ~0x00100000;
864 }
865
866 for (i = 0; i < priv->head.nr; i++) {
ebb945a9
BS
867 u32 mask = 0x01000000 << i;
868 if (mask & intr) {
869 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
870 if (stat & 0x00000001)
871 nvd0_disp_intr_vblank(priv, i);
872 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
873 nv_rd32(priv, 0x6100c0 + (i * 0x800));
874 }
875 }
876}
877
878static int
879nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
46654061
BS
880 struct nouveau_oclass *oclass, void *data, u32 size,
881 struct nouveau_object **pobject)
ebb945a9 882{
46654061 883 struct nv50_disp_priv *priv;
ebb945a9
BS
884 int ret;
885
886 ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
887 "display", &priv);
888 *pobject = nv_object(priv);
889 if (ret)
890 return ret;
891
46654061
BS
892 nv_engine(priv)->sclass = nvd0_disp_base_oclass;
893 nv_engine(priv)->cclass = &nv50_disp_cclass;
ebb945a9 894 nv_subdev(priv)->intr = nvd0_disp_intr;
46654061
BS
895 priv->sclass = nvd0_disp_sclass;
896 priv->head.nr = nv_rd32(priv, 0x022448);
897 priv->dac.nr = 3;
898 priv->sor.nr = 4;
35b21d39
BS
899 priv->dac.power = nv50_dac_power;
900 priv->dac.sense = nv50_dac_sense;
74b66850 901 priv->sor.power = nv50_sor_power;
0a9e2b95 902 priv->sor.hda_eld = nvd0_hda_eld;
1c30cd09 903 priv->sor.hdmi = nvd0_hdmi_ctrl;
6c5a0424
BS
904 priv->sor.dp_train = nvd0_sor_dp_train;
905 priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
906 priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
ebb945a9
BS
907
908 INIT_LIST_HEAD(&priv->base.vblank.list);
909 spin_lock_init(&priv->base.vblank.lock);
910 return 0;
911}
912
913struct nouveau_oclass
914nvd0_disp_oclass = {
46654061 915 .handle = NV_ENGINE(DISP, 0x90),
ebb945a9
BS
916 .ofuncs = &(struct nouveau_ofuncs) {
917 .ctor = nvd0_disp_ctor,
918 .dtor = _nouveau_disp_dtor,
919 .init = _nouveau_disp_init,
920 .fini = _nouveau_disp_fini,
921 },
922};
This page took 0.078817 seconds and 5 git commands to generate.