blob: 2283c442a10d48e06761720e5ff7100fa9b74e4a [file] [log] [blame]
Ben Skeggsebb945a2012-07-20 08:17:34 +10001/*
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
Ben Skeggs370c00f2012-08-14 14:11:49 +100025#include <core/object.h>
26#include <core/parent.h>
27#include <core/handle.h>
28#include <core/class.h>
Ben Skeggs117e16332014-02-21 11:06:40 +100029#include <core/enum.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100030
Ben Skeggs186ecad2012-11-09 12:09:48 +100031#include <subdev/bios.h>
32#include <subdev/bios/dcb.h>
33#include <subdev/bios/disp.h>
34#include <subdev/bios/init.h>
35#include <subdev/bios/pll.h>
Ben Skeggs88524bc2013-03-05 10:53:54 +100036#include <subdev/devinit.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100037#include <subdev/timer.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100038#include <subdev/fb.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100039
Ben Skeggs70cabe42012-08-14 10:04:04 +100040#include "nv50.h"
41
42/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +100043 * EVO channel base class
Ben Skeggs70cabe42012-08-14 10:04:04 +100044 ******************************************************************************/
45
Ben Skeggs370c00f2012-08-14 14:11:49 +100046int
47nv50_disp_chan_create_(struct nouveau_object *parent,
48 struct nouveau_object *engine,
49 struct nouveau_oclass *oclass, int chid,
50 int length, void **pobject)
51{
52 struct nv50_disp_base *base = (void *)parent;
53 struct nv50_disp_chan *chan;
54 int ret;
55
56 if (base->chan & (1 << chid))
57 return -EBUSY;
58 base->chan |= (1 << chid);
59
60 ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
61 (1ULL << NVDEV_ENGINE_DMAOBJ),
62 length, pobject);
63 chan = *pobject;
64 if (ret)
65 return ret;
66
67 chan->chid = chid;
68 return 0;
69}
70
71void
72nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
73{
74 struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
75 base->chan &= ~(1 << chan->chid);
76 nouveau_namedb_destroy(&chan->base);
77}
78
79u32
Ben Skeggs70cabe42012-08-14 10:04:04 +100080nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
81{
Ben Skeggs370c00f2012-08-14 14:11:49 +100082 struct nv50_disp_priv *priv = (void *)object->engine;
83 struct nv50_disp_chan *chan = (void *)object;
84 return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
85}
86
87void
88nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
89{
90 struct nv50_disp_priv *priv = (void *)object->engine;
91 struct nv50_disp_chan *chan = (void *)object;
92 nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
93}
94
95/*******************************************************************************
96 * EVO DMA channel base class
97 ******************************************************************************/
98
99static int
100nv50_disp_dmac_object_attach(struct nouveau_object *parent,
101 struct nouveau_object *object, u32 name)
102{
103 struct nv50_disp_base *base = (void *)parent->parent;
104 struct nv50_disp_chan *chan = (void *)parent;
105 u32 addr = nv_gpuobj(object)->node->offset;
106 u32 chid = chan->chid;
107 u32 data = (chid << 28) | (addr << 10) | chid;
108 return nouveau_ramht_insert(base->ramht, chid, name, data);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000109}
110
111static void
Ben Skeggs370c00f2012-08-14 14:11:49 +1000112nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
Ben Skeggs70cabe42012-08-14 10:04:04 +1000113{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000114 struct nv50_disp_base *base = (void *)parent->parent;
115 nouveau_ramht_remove(base->ramht, cookie);
116}
117
118int
119nv50_disp_dmac_create_(struct nouveau_object *parent,
120 struct nouveau_object *engine,
121 struct nouveau_oclass *oclass, u32 pushbuf, int chid,
122 int length, void **pobject)
123{
124 struct nv50_disp_dmac *dmac;
125 int ret;
126
127 ret = nv50_disp_chan_create_(parent, engine, oclass, chid,
128 length, pobject);
129 dmac = *pobject;
130 if (ret)
131 return ret;
132
133 dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
134 if (!dmac->pushdma)
135 return -ENOENT;
136
137 switch (nv_mclass(dmac->pushdma)) {
138 case 0x0002:
139 case 0x003d:
140 if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
141 return -EINVAL;
142
143 switch (dmac->pushdma->target) {
144 case NV_MEM_TARGET_VRAM:
145 dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
146 break;
Ben Skeggs944234d2012-10-30 10:03:38 +1000147 case NV_MEM_TARGET_PCI_NOSNOOP:
148 dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
149 break;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000150 default:
151 return -EINVAL;
152 }
153 break;
154 default:
155 return -EINVAL;
156 }
157
158 return 0;
159}
160
161void
162nv50_disp_dmac_dtor(struct nouveau_object *object)
163{
164 struct nv50_disp_dmac *dmac = (void *)object;
165 nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
166 nv50_disp_chan_destroy(&dmac->base);
167}
168
169static int
170nv50_disp_dmac_init(struct nouveau_object *object)
171{
172 struct nv50_disp_priv *priv = (void *)object->engine;
173 struct nv50_disp_dmac *dmac = (void *)object;
174 int chid = dmac->base.chid;
175 int ret;
176
177 ret = nv50_disp_chan_init(&dmac->base);
178 if (ret)
179 return ret;
180
181 /* enable error reporting */
182 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
183
184 /* initialise channel for dma command submission */
185 nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
186 nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
187 nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
188 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
189 nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
190 nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
191
192 /* wait for it to go inactive */
193 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
194 nv_error(dmac, "init timeout, 0x%08x\n",
195 nv_rd32(priv, 0x610200 + (chid * 0x10)));
196 return -EBUSY;
197 }
198
199 return 0;
200}
201
202static int
203nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
204{
205 struct nv50_disp_priv *priv = (void *)object->engine;
206 struct nv50_disp_dmac *dmac = (void *)object;
207 int chid = dmac->base.chid;
208
209 /* deactivate channel */
210 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
211 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
212 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
213 nv_error(dmac, "fini timeout, 0x%08x\n",
214 nv_rd32(priv, 0x610200 + (chid * 0x10)));
215 if (suspend)
216 return -EBUSY;
217 }
218
219 /* disable error reporting */
220 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
221
222 return nv50_disp_chan_fini(&dmac->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000223}
224
225/*******************************************************************************
226 * EVO master channel object
227 ******************************************************************************/
228
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000229static void
230nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
231 const struct nv50_disp_mthd_list *list, int inst)
232{
233 struct nouveau_object *disp = nv_object(priv);
234 int i;
235
236 for (i = 0; list->data[i].mthd; i++) {
237 if (list->data[i].addr) {
238 u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
239 u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
240 u32 mthd = list->data[i].mthd + (list->mthd * inst);
241 const char *name = list->data[i].name;
242 char mods[16];
243
244 if (prev != next)
245 snprintf(mods, sizeof(mods), "-> 0x%08x", next);
246 else
247 snprintf(mods, sizeof(mods), "%13c", ' ');
248
249 nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
250 mthd, prev, mods, name ? " // " : "",
251 name ? name : "");
252 }
253 }
254}
255
256void
257nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
258 const struct nv50_disp_mthd_chan *chan)
259{
260 struct nouveau_object *disp = nv_object(priv);
261 const struct nv50_disp_impl *impl = (void *)disp->oclass;
262 const struct nv50_disp_mthd_list *list;
263 int i, j;
264
265 if (debug > nv_subdev(priv)->debug)
266 return;
267
268 for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
269 u32 base = head * chan->addr;
270 for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
271 const char *cname = chan->name;
272 const char *sname = "";
273 char cname_[16], sname_[16];
274
275 if (chan->addr) {
276 snprintf(cname_, sizeof(cname_), "%s %d",
277 chan->name, head);
278 cname = cname_;
279 }
280
281 if (chan->data[i].nr > 1) {
282 snprintf(sname_, sizeof(sname_), " - %s %d",
283 chan->data[i].name, j);
284 sname = sname_;
285 }
286
287 nv_printk_(disp, debug, "%s%s:\n", cname, sname);
288 nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
289 list, j);
290 }
291 }
292}
293
294const struct nv50_disp_mthd_list
295nv50_disp_mast_mthd_base = {
296 .mthd = 0x0000,
297 .addr = 0x000000,
298 .data = {
299 { 0x0080, 0x000000 },
300 { 0x0084, 0x610bb8 },
301 { 0x0088, 0x610b9c },
302 { 0x008c, 0x000000 },
303 {}
304 }
305};
306
307static const struct nv50_disp_mthd_list
308nv50_disp_mast_mthd_dac = {
309 .mthd = 0x0080,
310 .addr = 0x000008,
311 .data = {
312 { 0x0400, 0x610b58 },
313 { 0x0404, 0x610bdc },
314 { 0x0420, 0x610828 },
315 {}
316 }
317};
318
319const struct nv50_disp_mthd_list
320nv50_disp_mast_mthd_sor = {
321 .mthd = 0x0040,
322 .addr = 0x000008,
323 .data = {
324 { 0x0600, 0x610b70 },
325 {}
326 }
327};
328
329const struct nv50_disp_mthd_list
330nv50_disp_mast_mthd_pior = {
331 .mthd = 0x0040,
332 .addr = 0x000008,
333 .data = {
334 { 0x0700, 0x610b80 },
335 {}
336 }
337};
338
339static const struct nv50_disp_mthd_list
340nv50_disp_mast_mthd_head = {
341 .mthd = 0x0400,
342 .addr = 0x000540,
343 .data = {
344 { 0x0800, 0x610ad8 },
345 { 0x0804, 0x610ad0 },
346 { 0x0808, 0x610a48 },
347 { 0x080c, 0x610a78 },
348 { 0x0810, 0x610ac0 },
349 { 0x0814, 0x610af8 },
350 { 0x0818, 0x610b00 },
351 { 0x081c, 0x610ae8 },
352 { 0x0820, 0x610af0 },
353 { 0x0824, 0x610b08 },
354 { 0x0828, 0x610b10 },
355 { 0x082c, 0x610a68 },
356 { 0x0830, 0x610a60 },
357 { 0x0834, 0x000000 },
358 { 0x0838, 0x610a40 },
359 { 0x0840, 0x610a24 },
360 { 0x0844, 0x610a2c },
361 { 0x0848, 0x610aa8 },
362 { 0x084c, 0x610ab0 },
363 { 0x0860, 0x610a84 },
364 { 0x0864, 0x610a90 },
365 { 0x0868, 0x610b18 },
366 { 0x086c, 0x610b20 },
367 { 0x0870, 0x610ac8 },
368 { 0x0874, 0x610a38 },
369 { 0x0880, 0x610a58 },
370 { 0x0884, 0x610a9c },
371 { 0x08a0, 0x610a70 },
372 { 0x08a4, 0x610a50 },
373 { 0x08a8, 0x610ae0 },
374 { 0x08c0, 0x610b28 },
375 { 0x08c4, 0x610b30 },
376 { 0x08c8, 0x610b40 },
377 { 0x08d4, 0x610b38 },
378 { 0x08d8, 0x610b48 },
379 { 0x08dc, 0x610b50 },
380 { 0x0900, 0x610a18 },
381 { 0x0904, 0x610ab8 },
382 {}
383 }
384};
385
386static const struct nv50_disp_mthd_chan
387nv50_disp_mast_mthd_chan = {
388 .name = "Core",
389 .addr = 0x000000,
390 .data = {
391 { "Global", 1, &nv50_disp_mast_mthd_base },
392 { "DAC", 3, &nv50_disp_mast_mthd_dac },
393 { "SOR", 2, &nv50_disp_mast_mthd_sor },
394 { "PIOR", 3, &nv50_disp_mast_mthd_pior },
395 { "HEAD", 2, &nv50_disp_mast_mthd_head },
396 {}
397 }
398};
399
Ben Skeggs70cabe42012-08-14 10:04:04 +1000400static int
401nv50_disp_mast_ctor(struct nouveau_object *parent,
402 struct nouveau_object *engine,
403 struct nouveau_oclass *oclass, void *data, u32 size,
404 struct nouveau_object **pobject)
405{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000406 struct nv50_display_mast_class *args = data;
407 struct nv50_disp_dmac *mast;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000408 int ret;
409
Ben Skeggs370c00f2012-08-14 14:11:49 +1000410 if (size < sizeof(*args))
411 return -EINVAL;
412
413 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
414 0, sizeof(*mast), (void **)&mast);
415 *pobject = nv_object(mast);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000416 if (ret)
417 return ret;
418
Ben Skeggs370c00f2012-08-14 14:11:49 +1000419 nv_parent(mast)->object_attach = nv50_disp_dmac_object_attach;
420 nv_parent(mast)->object_detach = nv50_disp_dmac_object_detach;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000421 return 0;
422}
423
Ben Skeggs70cabe42012-08-14 10:04:04 +1000424static int
425nv50_disp_mast_init(struct nouveau_object *object)
426{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000427 struct nv50_disp_priv *priv = (void *)object->engine;
428 struct nv50_disp_dmac *mast = (void *)object;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000429 int ret;
430
Ben Skeggs370c00f2012-08-14 14:11:49 +1000431 ret = nv50_disp_chan_init(&mast->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000432 if (ret)
433 return ret;
434
Ben Skeggs370c00f2012-08-14 14:11:49 +1000435 /* enable error reporting */
436 nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
437
438 /* attempt to unstick channel from some unknown state */
439 if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
440 nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
441 if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
442 nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
443
444 /* initialise channel for dma command submission */
445 nv_wr32(priv, 0x610204, mast->push);
446 nv_wr32(priv, 0x610208, 0x00010000);
447 nv_wr32(priv, 0x61020c, 0x00000000);
448 nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
449 nv_wr32(priv, 0x640000, 0x00000000);
450 nv_wr32(priv, 0x610200, 0x01000013);
451
452 /* wait for it to go inactive */
453 if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
454 nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
455 return -EBUSY;
456 }
457
Ben Skeggs70cabe42012-08-14 10:04:04 +1000458 return 0;
459}
460
461static int
462nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
463{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000464 struct nv50_disp_priv *priv = (void *)object->engine;
465 struct nv50_disp_dmac *mast = (void *)object;
466
467 /* deactivate channel */
468 nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
469 nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
470 if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
471 nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
472 if (suspend)
473 return -EBUSY;
474 }
475
476 /* disable error reporting */
477 nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
478
479 return nv50_disp_chan_fini(&mast->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000480}
481
482struct nouveau_ofuncs
483nv50_disp_mast_ofuncs = {
484 .ctor = nv50_disp_mast_ctor,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000485 .dtor = nv50_disp_dmac_dtor,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000486 .init = nv50_disp_mast_init,
487 .fini = nv50_disp_mast_fini,
488 .rd32 = nv50_disp_chan_rd32,
489 .wr32 = nv50_disp_chan_wr32,
490};
491
492/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000493 * EVO sync channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000494 ******************************************************************************/
495
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000496static const struct nv50_disp_mthd_list
497nv50_disp_sync_mthd_base = {
498 .mthd = 0x0000,
499 .addr = 0x000000,
500 .data = {
501 { 0x0080, 0x000000 },
502 { 0x0084, 0x0008c4 },
503 { 0x0088, 0x0008d0 },
504 { 0x008c, 0x0008dc },
505 { 0x0090, 0x0008e4 },
506 { 0x0094, 0x610884 },
507 { 0x00a0, 0x6108a0 },
508 { 0x00a4, 0x610878 },
509 { 0x00c0, 0x61086c },
510 { 0x00e0, 0x610858 },
511 { 0x00e4, 0x610860 },
512 { 0x00e8, 0x6108ac },
513 { 0x00ec, 0x6108b4 },
514 { 0x0100, 0x610894 },
515 { 0x0110, 0x6108bc },
516 { 0x0114, 0x61088c },
517 {}
518 }
519};
520
521const struct nv50_disp_mthd_list
522nv50_disp_sync_mthd_image = {
523 .mthd = 0x0400,
524 .addr = 0x000000,
525 .data = {
526 { 0x0800, 0x6108f0 },
527 { 0x0804, 0x6108fc },
528 { 0x0808, 0x61090c },
529 { 0x080c, 0x610914 },
530 { 0x0810, 0x610904 },
531 {}
532 }
533};
534
535static const struct nv50_disp_mthd_chan
536nv50_disp_sync_mthd_chan = {
537 .name = "Base",
538 .addr = 0x000540,
539 .data = {
540 { "Global", 1, &nv50_disp_sync_mthd_base },
541 { "Image", 2, &nv50_disp_sync_mthd_image },
542 {}
543 }
544};
545
Ben Skeggs70cabe42012-08-14 10:04:04 +1000546static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000547nv50_disp_sync_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000548 struct nouveau_object *engine,
549 struct nouveau_oclass *oclass, void *data, u32 size,
550 struct nouveau_object **pobject)
551{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000552 struct nv50_display_sync_class *args = data;
553 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000554 int ret;
555
Dan Carpenteraf1ac182013-01-23 11:27:56 +0300556 if (size < sizeof(*args) || args->head > 1)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000557 return -EINVAL;
558
559 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
560 1 + args->head, sizeof(*dmac),
561 (void **)&dmac);
562 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000563 if (ret)
564 return ret;
565
Ben Skeggs370c00f2012-08-14 14:11:49 +1000566 nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
567 nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000568 return 0;
569}
570
Ben Skeggs70cabe42012-08-14 10:04:04 +1000571struct nouveau_ofuncs
Ben Skeggs370c00f2012-08-14 14:11:49 +1000572nv50_disp_sync_ofuncs = {
573 .ctor = nv50_disp_sync_ctor,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000574 .dtor = nv50_disp_dmac_dtor,
575 .init = nv50_disp_dmac_init,
576 .fini = nv50_disp_dmac_fini,
577 .rd32 = nv50_disp_chan_rd32,
578 .wr32 = nv50_disp_chan_wr32,
579};
580
581/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000582 * EVO overlay channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000583 ******************************************************************************/
584
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000585const struct nv50_disp_mthd_list
586nv50_disp_ovly_mthd_base = {
587 .mthd = 0x0000,
588 .addr = 0x000000,
589 .data = {
590 { 0x0080, 0x000000 },
591 { 0x0084, 0x0009a0 },
592 { 0x0088, 0x0009c0 },
593 { 0x008c, 0x0009c8 },
594 { 0x0090, 0x6109b4 },
595 { 0x0094, 0x610970 },
596 { 0x00a0, 0x610998 },
597 { 0x00a4, 0x610964 },
598 { 0x00c0, 0x610958 },
599 { 0x00e0, 0x6109a8 },
600 { 0x00e4, 0x6109d0 },
601 { 0x00e8, 0x6109d8 },
602 { 0x0100, 0x61094c },
603 { 0x0104, 0x610984 },
604 { 0x0108, 0x61098c },
605 { 0x0800, 0x6109f8 },
606 { 0x0808, 0x610a08 },
607 { 0x080c, 0x610a10 },
608 { 0x0810, 0x610a00 },
609 {}
610 }
611};
612
613static const struct nv50_disp_mthd_chan
614nv50_disp_ovly_mthd_chan = {
615 .name = "Overlay",
616 .addr = 0x000540,
617 .data = {
618 { "Global", 1, &nv50_disp_ovly_mthd_base },
619 {}
620 }
621};
622
Ben Skeggs70cabe42012-08-14 10:04:04 +1000623static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000624nv50_disp_ovly_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000625 struct nouveau_object *engine,
626 struct nouveau_oclass *oclass, void *data, u32 size,
627 struct nouveau_object **pobject)
628{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000629 struct nv50_display_ovly_class *args = data;
630 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000631 int ret;
632
Dan Carpenteraf1ac182013-01-23 11:27:56 +0300633 if (size < sizeof(*args) || args->head > 1)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000634 return -EINVAL;
635
636 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
637 3 + args->head, sizeof(*dmac),
638 (void **)&dmac);
639 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000640 if (ret)
641 return ret;
642
Ben Skeggs370c00f2012-08-14 14:11:49 +1000643 nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
644 nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000645 return 0;
646}
647
Ben Skeggs370c00f2012-08-14 14:11:49 +1000648struct nouveau_ofuncs
649nv50_disp_ovly_ofuncs = {
650 .ctor = nv50_disp_ovly_ctor,
651 .dtor = nv50_disp_dmac_dtor,
652 .init = nv50_disp_dmac_init,
653 .fini = nv50_disp_dmac_fini,
654 .rd32 = nv50_disp_chan_rd32,
655 .wr32 = nv50_disp_chan_wr32,
656};
657
658/*******************************************************************************
659 * EVO PIO channel base class
660 ******************************************************************************/
661
662static int
663nv50_disp_pioc_create_(struct nouveau_object *parent,
664 struct nouveau_object *engine,
665 struct nouveau_oclass *oclass, int chid,
666 int length, void **pobject)
667{
668 return nv50_disp_chan_create_(parent, engine, oclass, chid,
669 length, pobject);
670}
671
Ben Skeggs70cabe42012-08-14 10:04:04 +1000672static void
673nv50_disp_pioc_dtor(struct nouveau_object *object)
674{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000675 struct nv50_disp_pioc *pioc = (void *)object;
676 nv50_disp_chan_destroy(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000677}
678
679static int
680nv50_disp_pioc_init(struct nouveau_object *object)
681{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000682 struct nv50_disp_priv *priv = (void *)object->engine;
683 struct nv50_disp_pioc *pioc = (void *)object;
684 int chid = pioc->base.chid;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000685 int ret;
686
Ben Skeggs370c00f2012-08-14 14:11:49 +1000687 ret = nv50_disp_chan_init(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000688 if (ret)
689 return ret;
690
Ben Skeggs370c00f2012-08-14 14:11:49 +1000691 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
692 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
693 nv_error(pioc, "timeout0: 0x%08x\n",
694 nv_rd32(priv, 0x610200 + (chid * 0x10)));
695 return -EBUSY;
696 }
697
698 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
699 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
700 nv_error(pioc, "timeout1: 0x%08x\n",
701 nv_rd32(priv, 0x610200 + (chid * 0x10)));
702 return -EBUSY;
703 }
704
Ben Skeggs70cabe42012-08-14 10:04:04 +1000705 return 0;
706}
707
708static int
709nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
710{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000711 struct nv50_disp_priv *priv = (void *)object->engine;
712 struct nv50_disp_pioc *pioc = (void *)object;
713 int chid = pioc->base.chid;
714
715 nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
716 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
717 nv_error(pioc, "timeout: 0x%08x\n",
718 nv_rd32(priv, 0x610200 + (chid * 0x10)));
719 if (suspend)
720 return -EBUSY;
721 }
722
723 return nv50_disp_chan_fini(&pioc->base, suspend);
724}
725
726/*******************************************************************************
727 * EVO immediate overlay channel objects
728 ******************************************************************************/
729
730static int
731nv50_disp_oimm_ctor(struct nouveau_object *parent,
732 struct nouveau_object *engine,
733 struct nouveau_oclass *oclass, void *data, u32 size,
734 struct nouveau_object **pobject)
735{
736 struct nv50_display_oimm_class *args = data;
737 struct nv50_disp_pioc *pioc;
738 int ret;
739
740 if (size < sizeof(*args) || args->head > 1)
741 return -EINVAL;
742
743 ret = nv50_disp_pioc_create_(parent, engine, oclass, 5 + args->head,
744 sizeof(*pioc), (void **)&pioc);
745 *pobject = nv_object(pioc);
746 if (ret)
747 return ret;
748
749 return 0;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000750}
751
752struct nouveau_ofuncs
Ben Skeggs370c00f2012-08-14 14:11:49 +1000753nv50_disp_oimm_ofuncs = {
754 .ctor = nv50_disp_oimm_ctor,
755 .dtor = nv50_disp_pioc_dtor,
756 .init = nv50_disp_pioc_init,
757 .fini = nv50_disp_pioc_fini,
758 .rd32 = nv50_disp_chan_rd32,
759 .wr32 = nv50_disp_chan_wr32,
760};
761
762/*******************************************************************************
763 * EVO cursor channel objects
764 ******************************************************************************/
765
766static int
767nv50_disp_curs_ctor(struct nouveau_object *parent,
768 struct nouveau_object *engine,
769 struct nouveau_oclass *oclass, void *data, u32 size,
770 struct nouveau_object **pobject)
771{
772 struct nv50_display_curs_class *args = data;
773 struct nv50_disp_pioc *pioc;
774 int ret;
775
776 if (size < sizeof(*args) || args->head > 1)
777 return -EINVAL;
778
779 ret = nv50_disp_pioc_create_(parent, engine, oclass, 7 + args->head,
780 sizeof(*pioc), (void **)&pioc);
781 *pobject = nv_object(pioc);
782 if (ret)
783 return ret;
784
785 return 0;
786}
787
788struct nouveau_ofuncs
789nv50_disp_curs_ofuncs = {
790 .ctor = nv50_disp_curs_ctor,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000791 .dtor = nv50_disp_pioc_dtor,
792 .init = nv50_disp_pioc_init,
793 .fini = nv50_disp_pioc_fini,
794 .rd32 = nv50_disp_chan_rd32,
795 .wr32 = nv50_disp_chan_wr32,
796};
797
798/*******************************************************************************
799 * Base display object
800 ******************************************************************************/
801
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000802int
803nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
804 void *data, u32 size)
805{
806 struct nv50_disp_priv *priv = (void *)object->engine;
807 struct nv04_display_scanoutpos *args = data;
808 const int head = (mthd & NV50_DISP_MTHD_HEAD);
809 u32 blanke, blanks, total;
810
811 if (size < sizeof(*args) || head >= priv->head.nr)
812 return -EINVAL;
813 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
814 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
815 total = nv_rd32(priv, 0x610afc + (head * 0x540));
816
817 args->vblanke = (blanke & 0xffff0000) >> 16;
818 args->hblanke = (blanke & 0x0000ffff);
819 args->vblanks = (blanks & 0xffff0000) >> 16;
820 args->hblanks = (blanks & 0x0000ffff);
821 args->vtotal = ( total & 0xffff0000) >> 16;
822 args->htotal = ( total & 0x0000ffff);
823
824 args->time[0] = ktime_to_ns(ktime_get());
825 args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
826 args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
827 args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
828 return 0;
829}
830
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000831static void
Ben Skeggs8e8832e2014-05-13 15:30:15 +1000832nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000833{
Maarten Lankhorstc8f28f82013-03-05 14:59:26 +0100834 nv_mask(event->priv, 0x61002c, (4 << head), (4 << head));
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000835}
836
837static void
Ben Skeggs8e8832e2014-05-13 15:30:15 +1000838nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000839{
Maarten Lankhorstc8f28f82013-03-05 14:59:26 +0100840 nv_mask(event->priv, 0x61002c, (4 << head), 0);
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000841}
842
Ben Skeggs70cabe42012-08-14 10:04:04 +1000843static int
844nv50_disp_base_ctor(struct nouveau_object *parent,
845 struct nouveau_object *engine,
846 struct nouveau_oclass *oclass, void *data, u32 size,
847 struct nouveau_object **pobject)
848{
849 struct nv50_disp_priv *priv = (void *)engine;
850 struct nv50_disp_base *base;
851 int ret;
852
853 ret = nouveau_parent_create(parent, engine, oclass, 0,
854 priv->sclass, 0, &base);
855 *pobject = nv_object(base);
856 if (ret)
857 return ret;
858
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000859 priv->base.vblank->priv = priv;
860 priv->base.vblank->enable = nv50_disp_base_vblank_enable;
861 priv->base.vblank->disable = nv50_disp_base_vblank_disable;
Ben Skeggs2ecda482013-04-24 18:04:22 +1000862 return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
863 &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000864}
865
866static void
867nv50_disp_base_dtor(struct nouveau_object *object)
868{
869 struct nv50_disp_base *base = (void *)object;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000870 nouveau_ramht_ref(NULL, &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000871 nouveau_parent_destroy(&base->base);
872}
873
874static int
875nv50_disp_base_init(struct nouveau_object *object)
876{
Ben Skeggsab772142012-08-14 11:29:57 +1000877 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000878 struct nv50_disp_base *base = (void *)object;
Ben Skeggsab772142012-08-14 11:29:57 +1000879 int ret, i;
880 u32 tmp;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000881
882 ret = nouveau_parent_init(&base->base);
883 if (ret)
884 return ret;
885
Ben Skeggsab772142012-08-14 11:29:57 +1000886 /* The below segments of code copying values from one register to
887 * another appear to inform EVO of the display capabilities or
888 * something similar. NFI what the 0x614004 caps are for..
889 */
890 tmp = nv_rd32(priv, 0x614004);
891 nv_wr32(priv, 0x610184, tmp);
892
893 /* ... CRTC caps */
894 for (i = 0; i < priv->head.nr; i++) {
895 tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
896 nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
897 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
898 nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
899 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
900 nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
901 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
902 nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
903 }
904
905 /* ... DAC caps */
906 for (i = 0; i < priv->dac.nr; i++) {
907 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
908 nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
909 }
910
911 /* ... SOR caps */
912 for (i = 0; i < priv->sor.nr; i++) {
913 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
914 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
915 }
916
Ben Skeggs476e84e2013-02-11 09:24:23 +1000917 /* ... PIOR caps */
Emil Velikovb969fa52013-07-30 01:01:10 +0100918 for (i = 0; i < priv->pior.nr; i++) {
Ben Skeggsab772142012-08-14 11:29:57 +1000919 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
920 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
921 }
922
Ben Skeggs446b05a2012-08-14 12:50:14 +1000923 /* steal display away from vbios, or something like that */
924 if (nv_rd32(priv, 0x610024) & 0x00000100) {
925 nv_wr32(priv, 0x610024, 0x00000100);
926 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
927 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
928 nv_error(priv, "timeout acquiring display\n");
929 return -EBUSY;
930 }
931 }
932
933 /* point at display engine memory area (hash table, objects) */
Ben Skeggs370c00f2012-08-14 14:11:49 +1000934 nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
Ben Skeggs446b05a2012-08-14 12:50:14 +1000935
936 /* enable supervisor interrupts, disable everything else */
Ben Skeggs370c00f2012-08-14 14:11:49 +1000937 nv_wr32(priv, 0x61002c, 0x00000370);
938 nv_wr32(priv, 0x610028, 0x00000000);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000939 return 0;
940}
941
942static int
943nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
944{
Ben Skeggs446b05a2012-08-14 12:50:14 +1000945 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000946 struct nv50_disp_base *base = (void *)object;
Ben Skeggs446b05a2012-08-14 12:50:14 +1000947
948 /* disable all interrupts */
949 nv_wr32(priv, 0x610024, 0x00000000);
950 nv_wr32(priv, 0x610020, 0x00000000);
951
Ben Skeggs70cabe42012-08-14 10:04:04 +1000952 return nouveau_parent_fini(&base->base, suspend);
953}
954
955struct nouveau_ofuncs
956nv50_disp_base_ofuncs = {
957 .ctor = nv50_disp_base_ctor,
958 .dtor = nv50_disp_base_dtor,
959 .init = nv50_disp_base_init,
960 .fini = nv50_disp_base_fini,
961};
962
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000963static struct nouveau_omthds
964nv50_disp_base_omthds[] = {
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000965 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000966 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
Ben Skeggs4a230fa2012-11-09 11:25:37 +1000967 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000968 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
969 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
Ben Skeggsa2bc2832013-02-11 09:11:08 +1000970 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
971 { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
972 { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000973 {},
974};
975
Ben Skeggs70cabe42012-08-14 10:04:04 +1000976static struct nouveau_oclass
977nv50_disp_base_oclass[] = {
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000978 { NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds },
Ben Skeggs370c00f2012-08-14 14:11:49 +1000979 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000980};
981
982static struct nouveau_oclass
983nv50_disp_sclass[] = {
Ben Skeggs370c00f2012-08-14 14:11:49 +1000984 { NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
985 { NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
986 { NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
987 { NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
988 { NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
Ben Skeggs70cabe42012-08-14 10:04:04 +1000989 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000990};
991
Ben Skeggs70cabe42012-08-14 10:04:04 +1000992/*******************************************************************************
993 * Display context, tracks instmem allocation and prevents more than one
994 * client using the display hardware at any time.
995 ******************************************************************************/
996
997static int
998nv50_disp_data_ctor(struct nouveau_object *parent,
999 struct nouveau_object *engine,
1000 struct nouveau_oclass *oclass, void *data, u32 size,
1001 struct nouveau_object **pobject)
1002{
Ben Skeggs370c00f2012-08-14 14:11:49 +10001003 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001004 struct nouveau_engctx *ectx;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001005 int ret = -EBUSY;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001006
Ben Skeggs370c00f2012-08-14 14:11:49 +10001007 /* no context needed for channel objects... */
1008 if (nv_mclass(parent) != NV_DEVICE_CLASS) {
1009 atomic_inc(&parent->refcount);
1010 *pobject = parent;
Ben Skeggs43e6e512013-04-26 00:12:59 +10001011 return 1;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001012 }
Ben Skeggs70cabe42012-08-14 10:04:04 +10001013
Ben Skeggs370c00f2012-08-14 14:11:49 +10001014 /* allocate display hardware to client */
1015 mutex_lock(&nv_subdev(priv)->mutex);
1016 if (list_empty(&nv_engine(priv)->contexts)) {
1017 ret = nouveau_engctx_create(parent, engine, oclass, NULL,
1018 0x10000, 0x10000,
1019 NVOBJ_FLAG_HEAP, &ectx);
1020 *pobject = nv_object(ectx);
1021 }
1022 mutex_unlock(&nv_subdev(priv)->mutex);
1023 return ret;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001024}
1025
1026struct nouveau_oclass
1027nv50_disp_cclass = {
1028 .handle = NV_ENGCTX(DISP, 0x50),
1029 .ofuncs = &(struct nouveau_ofuncs) {
1030 .ctor = nv50_disp_data_ctor,
1031 .dtor = _nouveau_engctx_dtor,
1032 .init = _nouveau_engctx_init,
1033 .fini = _nouveau_engctx_fini,
1034 .rd32 = _nouveau_engctx_rd32,
1035 .wr32 = _nouveau_engctx_wr32,
1036 },
1037};
1038
1039/*******************************************************************************
1040 * Display engine implementation
1041 ******************************************************************************/
1042
Ben Skeggs117e16332014-02-21 11:06:40 +10001043static const struct nouveau_enum
1044nv50_disp_intr_error_type[] = {
1045 { 3, "ILLEGAL_MTHD" },
1046 { 4, "INVALID_VALUE" },
1047 { 5, "INVALID_STATE" },
1048 { 7, "INVALID_HANDLE" },
1049 {}
1050};
1051
1052static const struct nouveau_enum
1053nv50_disp_intr_error_code[] = {
1054 { 0x00, "" },
1055 {}
1056};
1057
Ben Skeggsebb945a2012-07-20 08:17:34 +10001058static void
Ben Skeggs117e16332014-02-21 11:06:40 +10001059nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001060{
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001061 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs117e16332014-02-21 11:06:40 +10001062 u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
1063 u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
1064 u32 code = (addr & 0x00ff0000) >> 16;
1065 u32 type = (addr & 0x00007000) >> 12;
1066 u32 mthd = (addr & 0x00000ffc);
1067 const struct nouveau_enum *ec, *et;
1068 char ecunk[6], etunk[6];
Ben Skeggs186ecad2012-11-09 12:09:48 +10001069
Ben Skeggs117e16332014-02-21 11:06:40 +10001070 et = nouveau_enum_find(nv50_disp_intr_error_type, type);
1071 if (!et)
1072 snprintf(etunk, sizeof(etunk), "UNK%02X", type);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001073
Ben Skeggs117e16332014-02-21 11:06:40 +10001074 ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
1075 if (!ec)
1076 snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001077
Ben Skeggs117e16332014-02-21 11:06:40 +10001078 nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
1079 et ? et->name : etunk, ec ? ec->name : ecunk,
1080 chid, mthd, data);
1081
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001082 if (chid == 0) {
1083 switch (mthd) {
1084 case 0x0080:
1085 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
1086 impl->mthd.core);
1087 break;
1088 default:
1089 break;
1090 }
1091 } else
1092 if (chid <= 2) {
1093 switch (mthd) {
1094 case 0x0080:
1095 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
1096 impl->mthd.base);
1097 break;
1098 default:
1099 break;
1100 }
1101 } else
1102 if (chid <= 4) {
1103 switch (mthd) {
1104 case 0x0080:
1105 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
1106 impl->mthd.ovly);
1107 break;
1108 default:
1109 break;
1110 }
1111 }
1112
Ben Skeggs117e16332014-02-21 11:06:40 +10001113 nv_wr32(priv, 0x610020, 0x00010000 << chid);
1114 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001115}
1116
Ben Skeggs415f12e2014-05-21 11:24:43 +10001117static struct nvkm_output *
1118exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
1119 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001120 struct nvbios_outp *info)
1121{
1122 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001123 struct nvkm_output *outp;
1124 u16 mask, type;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001125
Ben Skeggs415f12e2014-05-21 11:24:43 +10001126 if (or < 4) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001127 type = DCB_OUTPUT_ANALOG;
1128 mask = 0;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001129 } else
Ben Skeggs415f12e2014-05-21 11:24:43 +10001130 if (or < 8) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001131 switch (ctrl & 0x00000f00) {
1132 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
1133 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
1134 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
1135 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
1136 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
1137 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
1138 default:
1139 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001140 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001141 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001142 or -= 4;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001143 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001144 or = or - 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001145 type = 0x0010;
1146 mask = 0;
1147 switch (ctrl & 0x00000f00) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001148 case 0x00000000: type |= priv->pior.type[or]; break;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001149 default:
1150 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001151 return NULL;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001152 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001153 }
1154
1155 mask = 0x00c0 & (mask << 6);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001156 mask |= 0x0001 << or;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001157 mask |= 0x0100 << head;
1158
Ben Skeggs415f12e2014-05-21 11:24:43 +10001159 list_for_each_entry(outp, &priv->base.outp, head) {
1160 if ((outp->info.hasht & 0xff) == type &&
1161 (outp->info.hashm & mask) == mask) {
1162 *data = nvbios_outp_match(bios, outp->info.hasht,
1163 outp->info.hashm,
1164 ver, hdr, cnt, len, info);
1165 if (!*data)
1166 return NULL;
1167 return outp;
1168 }
1169 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001170
Ben Skeggs415f12e2014-05-21 11:24:43 +10001171 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001172}
1173
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001174static struct nvkm_output *
Ben Skeggs186ecad2012-11-09 12:09:48 +10001175exec_script(struct nv50_disp_priv *priv, int head, int id)
1176{
1177 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001178 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001179 struct nvbios_outp info;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001180 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001181 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001182 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001183 int i;
1184
Ben Skeggs476e84e2013-02-11 09:24:23 +10001185 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001186 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001187 ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
1188
Ben Skeggs476e84e2013-02-11 09:24:23 +10001189 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001190 if (!(ctrl & (1 << head))) {
1191 if (nv_device(priv)->chipset < 0x90 ||
1192 nv_device(priv)->chipset == 0x92 ||
1193 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001194 reg = 0x610b74;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001195 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001196 reg = 0x610798;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001197 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001198 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1199 ctrl = nv_rd32(priv, reg + (i * 8));
1200 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001201 }
1202
Ben Skeggs476e84e2013-02-11 09:24:23 +10001203 /* PIOR */
1204 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001205 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001206 ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
1207 i += 8;
1208 }
1209
Ben Skeggs186ecad2012-11-09 12:09:48 +10001210 if (!(ctrl & (1 << head)))
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001211 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001212 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001213
Ben Skeggs415f12e2014-05-21 11:24:43 +10001214 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
1215 if (outp) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001216 struct nvbios_init init = {
1217 .subdev = nv_subdev(priv),
1218 .bios = bios,
1219 .offset = info.script[id],
Ben Skeggs415f12e2014-05-21 11:24:43 +10001220 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001221 .crtc = head,
1222 .execute = 1,
1223 };
1224
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001225 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001226 }
1227
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001228 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001229}
1230
Ben Skeggs415f12e2014-05-21 11:24:43 +10001231static struct nvkm_output *
1232exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001233{
1234 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001235 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001236 struct nvbios_outp info1;
1237 struct nvbios_ocfg info2;
1238 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001239 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001240 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001241 int i;
1242
Ben Skeggs476e84e2013-02-11 09:24:23 +10001243 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001244 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001245 ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
1246
Ben Skeggs476e84e2013-02-11 09:24:23 +10001247 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001248 if (!(ctrl & (1 << head))) {
1249 if (nv_device(priv)->chipset < 0x90 ||
1250 nv_device(priv)->chipset == 0x92 ||
1251 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001252 reg = 0x610b70;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001253 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001254 reg = 0x610794;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001255 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001256 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1257 ctrl = nv_rd32(priv, reg + (i * 8));
1258 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001259 }
1260
Ben Skeggs476e84e2013-02-11 09:24:23 +10001261 /* PIOR */
1262 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001263 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001264 ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
1265 i += 8;
1266 }
1267
Ben Skeggs186ecad2012-11-09 12:09:48 +10001268 if (!(ctrl & (1 << head)))
Ben Skeggs415f12e2014-05-21 11:24:43 +10001269 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001270 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001271
Ben Skeggs415f12e2014-05-21 11:24:43 +10001272 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
Ben Skeggsba5e01b2014-06-17 09:39:18 +10001273 if (!outp)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001274 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001275
Ben Skeggs415f12e2014-05-21 11:24:43 +10001276 if (outp->info.location == 0) {
1277 switch (outp->info.type) {
Ben Skeggs476e84e2013-02-11 09:24:23 +10001278 case DCB_OUTPUT_TMDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001279 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001280 if (pclk >= 165000)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001281 *conf |= 0x0100;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001282 break;
1283 case DCB_OUTPUT_LVDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001284 *conf = priv->sor.lvdsconf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001285 break;
1286 case DCB_OUTPUT_DP:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001287 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001288 break;
1289 case DCB_OUTPUT_ANALOG:
1290 default:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001291 *conf = 0x00ff;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001292 break;
1293 }
1294 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001295 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001296 pclk = pclk / 2;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001297 }
1298
Ben Skeggs415f12e2014-05-21 11:24:43 +10001299 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001300 if (data && id < 0xff) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001301 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1302 if (data) {
1303 struct nvbios_init init = {
1304 .subdev = nv_subdev(priv),
1305 .bios = bios,
1306 .offset = data,
Ben Skeggs415f12e2014-05-21 11:24:43 +10001307 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001308 .crtc = head,
1309 .execute = 1,
1310 };
1311
Ben Skeggs46c13c12013-02-16 13:49:21 +10001312 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001313 }
1314 }
1315
Ben Skeggs415f12e2014-05-21 11:24:43 +10001316 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001317}
1318
1319static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001320nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001321{
Ben Skeggs16d4c032013-02-20 18:56:33 +10001322 exec_script(priv, head, 1);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001323}
1324
1325static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001326nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
1327{
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001328 struct nvkm_output *outp = exec_script(priv, head, 2);
1329
1330 /* the binary driver does this outside of the supervisor handling
1331 * (after the third supervisor from a detach). we (currently?)
1332 * allow both detach/attach to happen in the same set of
1333 * supervisor interrupts, so it would make sense to execute this
1334 * (full power down?) script after all the detach phases of the
1335 * supervisor handling. like with training if needed from the
1336 * second supervisor, nvidia doesn't do this, so who knows if it's
1337 * entirely safe, but it does appear to work..
1338 *
1339 * without this script being run, on some configurations i've
1340 * seen, switching from DP to TMDS on a DP connector may result
1341 * in a blank screen (SOR_PWR off/on can restore it)
1342 */
1343 if (outp && outp->info.type == DCB_OUTPUT_DP) {
1344 struct nvkm_output_dp *outpdp = (void *)outp;
1345 struct nvbios_init init = {
1346 .subdev = nv_subdev(priv),
1347 .bios = nouveau_bios(priv),
1348 .outp = &outp->info,
1349 .crtc = head,
1350 .offset = outpdp->info.script[4],
1351 .execute = 1,
1352 };
1353
1354 nvbios_exec(&init);
1355 atomic_set(&outpdp->lt.done, 0);
1356 }
Ben Skeggs16d4c032013-02-20 18:56:33 +10001357}
1358
1359static void
1360nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
1361{
Ben Skeggs88524bc2013-03-05 10:53:54 +10001362 struct nouveau_devinit *devinit = nouveau_devinit(priv);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001363 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1364 if (pclk)
Ben Skeggs88524bc2013-03-05 10:53:54 +10001365 devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001366}
1367
1368static void
1369nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
1370 struct dcb_output *outp, u32 pclk)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001371{
1372 const int link = !(outp->sorconf.link & 1);
1373 const int or = ffs(outp->or) - 1;
1374 const u32 soff = ( or * 0x800);
1375 const u32 loff = (link * 0x080) + soff;
1376 const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
Ben Skeggs186ecad2012-11-09 12:09:48 +10001377 const u32 symbol = 100000;
1378 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
1379 u32 clksor = nv_rd32(priv, 0x614300 + soff);
1380 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
1381 int TU, VTUi, VTUf, VTUa;
1382 u64 link_data_rate, link_ratio, unk;
1383 u32 best_diff = 64 * symbol;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001384 u32 link_nr, link_bw, bits, r;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001385
1386 /* calculate packed data rate for each lane */
1387 if (dpctrl > 0x00030000) link_nr = 4;
1388 else if (dpctrl > 0x00010000) link_nr = 2;
1389 else link_nr = 1;
1390
1391 if (clksor & 0x000c0000)
1392 link_bw = 270000;
1393 else
1394 link_bw = 162000;
1395
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001396 if ((ctrl & 0xf0000) == 0x60000) bits = 30;
1397 else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
1398 else bits = 18;
1399
Ben Skeggs186ecad2012-11-09 12:09:48 +10001400 link_data_rate = (pclk * bits / 8) / link_nr;
1401
1402 /* calculate ratio of packed data rate to link symbol rate */
1403 link_ratio = link_data_rate * symbol;
1404 r = do_div(link_ratio, link_bw);
1405
1406 for (TU = 64; TU >= 32; TU--) {
1407 /* calculate average number of valid symbols in each TU */
1408 u32 tu_valid = link_ratio * TU;
1409 u32 calc, diff;
1410
1411 /* find a hw representation for the fraction.. */
1412 VTUi = tu_valid / symbol;
1413 calc = VTUi * symbol;
1414 diff = tu_valid - calc;
1415 if (diff) {
1416 if (diff >= (symbol / 2)) {
1417 VTUf = symbol / (symbol - diff);
1418 if (symbol - (VTUf * diff))
1419 VTUf++;
1420
1421 if (VTUf <= 15) {
1422 VTUa = 1;
1423 calc += symbol - (symbol / VTUf);
1424 } else {
1425 VTUa = 0;
1426 VTUf = 1;
1427 calc += symbol;
1428 }
1429 } else {
1430 VTUa = 0;
1431 VTUf = min((int)(symbol / diff), 15);
1432 calc += symbol / VTUf;
1433 }
1434
1435 diff = calc - tu_valid;
1436 } else {
1437 /* no remainder, but the hw doesn't like the fractional
1438 * part to be zero. decrement the integer part and
1439 * have the fraction add a whole symbol back
1440 */
1441 VTUa = 0;
1442 VTUf = 1;
1443 VTUi--;
1444 }
1445
1446 if (diff < best_diff) {
1447 best_diff = diff;
1448 bestTU = TU;
1449 bestVTUa = VTUa;
1450 bestVTUf = VTUf;
1451 bestVTUi = VTUi;
1452 if (diff == 0)
1453 break;
1454 }
1455 }
1456
1457 if (!bestTU) {
1458 nv_error(priv, "unable to find suitable dp config\n");
1459 return;
1460 }
1461
1462 /* XXX close to vbios numbers, but not right */
1463 unk = (symbol - link_ratio) * bestTU;
1464 unk *= link_ratio;
1465 r = do_div(unk, symbol);
1466 r = do_div(unk, symbol);
1467 unk += 6;
1468
1469 nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
1470 nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
1471 bestVTUf << 16 |
1472 bestVTUi << 8 | unk);
1473}
1474
1475static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001476nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001477{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001478 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001479 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1480 u32 hval, hreg = 0x614200 + (head * 0x800);
1481 u32 oval, oreg;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001482 u32 mask, conf;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001483
Ben Skeggs415f12e2014-05-21 11:24:43 +10001484 outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
1485 if (!outp)
1486 return;
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001487
Ben Skeggs55f083c2014-05-20 10:18:03 +10001488 /* we allow both encoder attach and detach operations to occur
1489 * within a single supervisor (ie. modeset) sequence. the
1490 * encoder detach scripts quite often switch off power to the
1491 * lanes, which requires the link to be re-trained.
1492 *
1493 * this is not generally an issue as the sink "must" (heh)
1494 * signal an irq when it's lost sync so the driver can
1495 * re-train.
1496 *
1497 * however, on some boards, if one does not configure at least
1498 * the gpu side of the link *before* attaching, then various
1499 * things can go horribly wrong (PDISP disappearing from mmio,
1500 * third supervisor never happens, etc).
1501 *
1502 * the solution is simply to retrain here, if necessary. last
1503 * i checked, the binary driver userspace does not appear to
1504 * trigger this situation (it forces an UPDATE between steps).
1505 */
Ben Skeggsb17932c2014-05-27 15:00:36 +10001506 if (outp->info.type == DCB_OUTPUT_DP) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001507 u32 soff = (ffs(outp->info.or) - 1) * 0x08;
Ben Skeggsb17932c2014-05-27 15:00:36 +10001508 u32 ctrl, datarate;
1509
1510 if (outp->info.location == 0) {
1511 ctrl = nv_rd32(priv, 0x610794 + soff);
1512 soff = 1;
1513 } else {
1514 ctrl = nv_rd32(priv, 0x610b80 + soff);
1515 soff = 2;
1516 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001517
1518 switch ((ctrl & 0x000f0000) >> 16) {
Ben Skeggs0713b452014-07-01 10:54:52 +10001519 case 6: datarate = pclk * 30; break;
1520 case 5: datarate = pclk * 24; break;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001521 case 2:
1522 default:
Ben Skeggs0713b452014-07-01 10:54:52 +10001523 datarate = pclk * 18;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001524 break;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001525 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001526
Ben Skeggs55f083c2014-05-20 10:18:03 +10001527 if (nvkm_output_dp_train(outp, datarate / soff, true))
1528 ERR("link not trained before attach\n");
Ben Skeggs16d4c032013-02-20 18:56:33 +10001529 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001530
1531 exec_clkcmp(priv, head, 0, pclk, &conf);
1532
1533 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
1534 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
1535 oval = 0x00000000;
1536 hval = 0x00000000;
1537 mask = 0xffffffff;
1538 } else
1539 if (!outp->info.location) {
1540 if (outp->info.type == DCB_OUTPUT_DP)
1541 nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
1542 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
1543 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1544 hval = 0x00000000;
1545 mask = 0x00000707;
1546 } else {
1547 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
1548 oval = 0x00000001;
1549 hval = 0x00000001;
1550 mask = 0x00000707;
1551 }
1552
1553 nv_mask(priv, hreg, 0x0000000f, hval);
1554 nv_mask(priv, oreg, mask, oval);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001555}
1556
1557/* If programming a TMDS output on a SOR that can also be configured for
1558 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
1559 *
1560 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
1561 * the VBIOS scripts on at least one board I have only switch it off on
1562 * link 0, causing a blank display if the output has previously been
1563 * programmed for DisplayPort.
1564 */
1565static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001566nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001567{
1568 struct nouveau_bios *bios = nouveau_bios(priv);
1569 const int link = !(outp->sorconf.link & 1);
1570 const int or = ffs(outp->or) - 1;
1571 const u32 loff = (or * 0x800) + (link * 0x80);
1572 const u16 mask = (outp->sorconf.link << 6) | outp->or;
1573 u8 ver, hdr;
1574
1575 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
1576 nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
1577}
1578
1579static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001580nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001581{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001582 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001583 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001584 u32 conf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001585
Ben Skeggs415f12e2014-05-21 11:24:43 +10001586 outp = exec_clkcmp(priv, head, 1, pclk, &conf);
1587 if (!outp)
1588 return;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001589
Ben Skeggs415f12e2014-05-21 11:24:43 +10001590 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
1591 nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001592}
1593
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001594void
1595nv50_disp_intr_supervisor(struct work_struct *work)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001596{
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001597 struct nv50_disp_priv *priv =
1598 container_of(work, struct nv50_disp_priv, supervisor);
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001599 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001600 u32 super = nv_rd32(priv, 0x610030);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001601 int head;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001602
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001603 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001604
Ben Skeggs16d4c032013-02-20 18:56:33 +10001605 if (priv->super & 0x00000010) {
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001606 nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001607 for (head = 0; head < priv->head.nr; head++) {
1608 if (!(super & (0x00000020 << head)))
1609 continue;
1610 if (!(super & (0x00000080 << head)))
1611 continue;
1612 nv50_disp_intr_unk10_0(priv, head);
1613 }
1614 } else
1615 if (priv->super & 0x00000020) {
1616 for (head = 0; head < priv->head.nr; head++) {
1617 if (!(super & (0x00000080 << head)))
1618 continue;
1619 nv50_disp_intr_unk20_0(priv, head);
1620 }
1621 for (head = 0; head < priv->head.nr; head++) {
1622 if (!(super & (0x00000200 << head)))
1623 continue;
1624 nv50_disp_intr_unk20_1(priv, head);
1625 }
1626 for (head = 0; head < priv->head.nr; head++) {
1627 if (!(super & (0x00000080 << head)))
1628 continue;
1629 nv50_disp_intr_unk20_2(priv, head);
1630 }
1631 } else
1632 if (priv->super & 0x00000040) {
1633 for (head = 0; head < priv->head.nr; head++) {
1634 if (!(super & (0x00000080 << head)))
1635 continue;
1636 nv50_disp_intr_unk40_0(priv, head);
1637 }
1638 }
1639
1640 nv_wr32(priv, 0x610030, 0x80000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001641}
1642
Ben Skeggs70cabe42012-08-14 10:04:04 +10001643void
Ben Skeggsebb945a2012-07-20 08:17:34 +10001644nv50_disp_intr(struct nouveau_subdev *subdev)
1645{
1646 struct nv50_disp_priv *priv = (void *)subdev;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001647 u32 intr0 = nv_rd32(priv, 0x610020);
1648 u32 intr1 = nv_rd32(priv, 0x610024);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001649
Ben Skeggs117e16332014-02-21 11:06:40 +10001650 while (intr0 & 0x001f0000) {
1651 u32 chid = __ffs(intr0 & 0x001f0000) - 16;
1652 nv50_disp_intr_error(priv, chid);
1653 intr0 &= ~(0x00010000 << chid);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001654 }
1655
1656 if (intr1 & 0x00000004) {
Ben Skeggs8e8832e2014-05-13 15:30:15 +10001657 nouveau_event_trigger(priv->base.vblank, 1, 0);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001658 nv_wr32(priv, 0x610024, 0x00000004);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001659 intr1 &= ~0x00000004;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001660 }
1661
Ben Skeggs186ecad2012-11-09 12:09:48 +10001662 if (intr1 & 0x00000008) {
Ben Skeggs8e8832e2014-05-13 15:30:15 +10001663 nouveau_event_trigger(priv->base.vblank, 1, 1);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001664 nv_wr32(priv, 0x610024, 0x00000008);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001665 intr1 &= ~0x00000008;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001666 }
1667
Ben Skeggs186ecad2012-11-09 12:09:48 +10001668 if (intr1 & 0x00000070) {
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001669 priv->super = (intr1 & 0x00000070);
1670 schedule_work(&priv->supervisor);
1671 nv_wr32(priv, 0x610024, priv->super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001672 intr1 &= ~0x00000070;
1673 }
Ben Skeggsebb945a2012-07-20 08:17:34 +10001674}
1675
1676static int
1677nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
Ben Skeggs370c00f2012-08-14 14:11:49 +10001678 struct nouveau_oclass *oclass, void *data, u32 size,
1679 struct nouveau_object **pobject)
Ben Skeggsebb945a2012-07-20 08:17:34 +10001680{
1681 struct nv50_disp_priv *priv;
1682 int ret;
1683
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001684 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
Ben Skeggsebb945a2012-07-20 08:17:34 +10001685 "display", &priv);
1686 *pobject = nv_object(priv);
1687 if (ret)
1688 return ret;
1689
Ben Skeggs70cabe42012-08-14 10:04:04 +10001690 nv_engine(priv)->sclass = nv50_disp_base_oclass;
1691 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001692 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001693 INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001694 priv->sclass = nv50_disp_sclass;
1695 priv->head.nr = 2;
1696 priv->dac.nr = 3;
1697 priv->sor.nr = 2;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001698 priv->pior.nr = 3;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001699 priv->dac.power = nv50_dac_power;
Ben Skeggs7ebb38b2012-11-09 09:38:06 +10001700 priv->dac.sense = nv50_dac_sense;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001701 priv->sor.power = nv50_sor_power;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001702 priv->pior.power = nv50_pior_power;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001703 return 0;
1704}
1705
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001706struct nouveau_oclass *
Ben Skeggsb8407c92014-05-17 11:19:54 +10001707nv50_disp_outp_sclass[] = {
1708 &nv50_pior_dp_impl.base.base,
1709 NULL
1710};
1711
1712struct nouveau_oclass *
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001713nv50_disp_oclass = &(struct nv50_disp_impl) {
1714 .base.base.handle = NV_ENGINE(DISP, 0x50),
1715 .base.base.ofuncs = &(struct nouveau_ofuncs) {
Ben Skeggsebb945a2012-07-20 08:17:34 +10001716 .ctor = nv50_disp_ctor,
1717 .dtor = _nouveau_disp_dtor,
1718 .init = _nouveau_disp_init,
1719 .fini = _nouveau_disp_fini,
1720 },
Ben Skeggsb8407c92014-05-17 11:19:54 +10001721 .base.outp = nv50_disp_outp_sclass,
Ben Skeggsd67d92c2014-02-20 15:14:10 +10001722 .mthd.core = &nv50_disp_mast_mthd_chan,
1723 .mthd.base = &nv50_disp_sync_mthd_chan,
1724 .mthd.ovly = &nv50_disp_ovly_mthd_chan,
1725 .mthd.prev = 0x000004,
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001726}.base.base;