blob: 8dafd410656833cd2a9b78e94e4500bbc9b9b872 [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>
Ben Skeggsbf0eb892014-08-10 04:10:26 +100026#include <core/client.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100027#include <core/parent.h>
28#include <core/handle.h>
Ben Skeggs117e16332014-02-21 11:06:40 +100029#include <core/enum.h>
Ben Skeggsbf0eb892014-08-10 04:10:26 +100030#include <nvif/unpack.h>
31#include <nvif/class.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100032
Ben Skeggs186ecad2012-11-09 12:09:48 +100033#include <subdev/bios.h>
34#include <subdev/bios/dcb.h>
35#include <subdev/bios/disp.h>
36#include <subdev/bios/init.h>
37#include <subdev/bios/pll.h>
Ben Skeggs88524bc2013-03-05 10:53:54 +100038#include <subdev/devinit.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100039#include <subdev/timer.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100040#include <subdev/fb.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100041
Ben Skeggs70cabe42012-08-14 10:04:04 +100042#include "nv50.h"
43
44/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +100045 * EVO channel base class
Ben Skeggs70cabe42012-08-14 10:04:04 +100046 ******************************************************************************/
47
Ben Skeggs2c04ae02014-08-10 04:10:25 +100048static int
Ben Skeggs370c00f2012-08-14 14:11:49 +100049nv50_disp_chan_create_(struct nouveau_object *parent,
50 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +100051 struct nouveau_oclass *oclass, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +100052 int length, void **pobject)
53{
Ben Skeggs2c04ae02014-08-10 04:10:25 +100054 const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
Ben Skeggs370c00f2012-08-14 14:11:49 +100055 struct nv50_disp_base *base = (void *)parent;
56 struct nv50_disp_chan *chan;
Ben Skeggs2c04ae02014-08-10 04:10:25 +100057 int chid = impl->chid + head;
Ben Skeggs370c00f2012-08-14 14:11:49 +100058 int ret;
59
60 if (base->chan & (1 << chid))
61 return -EBUSY;
62 base->chan |= (1 << chid);
63
64 ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
65 (1ULL << NVDEV_ENGINE_DMAOBJ),
66 length, pobject);
67 chan = *pobject;
68 if (ret)
69 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +100070 chan->chid = chid;
Ben Skeggs2c04ae02014-08-10 04:10:25 +100071
72 nv_parent(chan)->object_attach = impl->attach;
73 nv_parent(chan)->object_detach = impl->detach;
Ben Skeggs370c00f2012-08-14 14:11:49 +100074 return 0;
75}
76
Ben Skeggs2c04ae02014-08-10 04:10:25 +100077static void
Ben Skeggs370c00f2012-08-14 14:11:49 +100078nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
79{
80 struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
81 base->chan &= ~(1 << chan->chid);
82 nouveau_namedb_destroy(&chan->base);
83}
84
85u32
Ben Skeggs70cabe42012-08-14 10:04:04 +100086nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
87{
Ben Skeggs370c00f2012-08-14 14:11:49 +100088 struct nv50_disp_priv *priv = (void *)object->engine;
89 struct nv50_disp_chan *chan = (void *)object;
90 return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
91}
92
93void
94nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
95{
96 struct nv50_disp_priv *priv = (void *)object->engine;
97 struct nv50_disp_chan *chan = (void *)object;
98 nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
99}
100
101/*******************************************************************************
102 * EVO DMA channel base class
103 ******************************************************************************/
104
105static int
106nv50_disp_dmac_object_attach(struct nouveau_object *parent,
107 struct nouveau_object *object, u32 name)
108{
109 struct nv50_disp_base *base = (void *)parent->parent;
110 struct nv50_disp_chan *chan = (void *)parent;
111 u32 addr = nv_gpuobj(object)->node->offset;
112 u32 chid = chan->chid;
113 u32 data = (chid << 28) | (addr << 10) | chid;
114 return nouveau_ramht_insert(base->ramht, chid, name, data);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000115}
116
117static void
Ben Skeggs370c00f2012-08-14 14:11:49 +1000118nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
Ben Skeggs70cabe42012-08-14 10:04:04 +1000119{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000120 struct nv50_disp_base *base = (void *)parent->parent;
121 nouveau_ramht_remove(base->ramht, cookie);
122}
123
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000124static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000125nv50_disp_dmac_create_(struct nouveau_object *parent,
126 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000127 struct nouveau_oclass *oclass, u32 pushbuf, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000128 int length, void **pobject)
129{
130 struct nv50_disp_dmac *dmac;
131 int ret;
132
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000133 ret = nv50_disp_chan_create_(parent, engine, oclass, head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000134 length, pobject);
135 dmac = *pobject;
136 if (ret)
137 return ret;
138
139 dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
140 if (!dmac->pushdma)
141 return -ENOENT;
142
143 switch (nv_mclass(dmac->pushdma)) {
144 case 0x0002:
145 case 0x003d:
146 if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
147 return -EINVAL;
148
149 switch (dmac->pushdma->target) {
150 case NV_MEM_TARGET_VRAM:
151 dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
152 break;
Ben Skeggs944234d2012-10-30 10:03:38 +1000153 case NV_MEM_TARGET_PCI_NOSNOOP:
154 dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
155 break;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000156 default:
157 return -EINVAL;
158 }
159 break;
160 default:
161 return -EINVAL;
162 }
163
164 return 0;
165}
166
167void
168nv50_disp_dmac_dtor(struct nouveau_object *object)
169{
170 struct nv50_disp_dmac *dmac = (void *)object;
171 nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
172 nv50_disp_chan_destroy(&dmac->base);
173}
174
175static int
176nv50_disp_dmac_init(struct nouveau_object *object)
177{
178 struct nv50_disp_priv *priv = (void *)object->engine;
179 struct nv50_disp_dmac *dmac = (void *)object;
180 int chid = dmac->base.chid;
181 int ret;
182
183 ret = nv50_disp_chan_init(&dmac->base);
184 if (ret)
185 return ret;
186
187 /* enable error reporting */
188 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
189
190 /* initialise channel for dma command submission */
191 nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
192 nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
193 nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
194 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
195 nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
196 nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
197
198 /* wait for it to go inactive */
199 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
200 nv_error(dmac, "init timeout, 0x%08x\n",
201 nv_rd32(priv, 0x610200 + (chid * 0x10)));
202 return -EBUSY;
203 }
204
205 return 0;
206}
207
208static int
209nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
210{
211 struct nv50_disp_priv *priv = (void *)object->engine;
212 struct nv50_disp_dmac *dmac = (void *)object;
213 int chid = dmac->base.chid;
214
215 /* deactivate channel */
216 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
217 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
218 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
219 nv_error(dmac, "fini timeout, 0x%08x\n",
220 nv_rd32(priv, 0x610200 + (chid * 0x10)));
221 if (suspend)
222 return -EBUSY;
223 }
224
225 /* disable error reporting */
226 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
227
228 return nv50_disp_chan_fini(&dmac->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000229}
230
231/*******************************************************************************
232 * EVO master channel object
233 ******************************************************************************/
234
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000235static void
236nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
237 const struct nv50_disp_mthd_list *list, int inst)
238{
239 struct nouveau_object *disp = nv_object(priv);
240 int i;
241
242 for (i = 0; list->data[i].mthd; i++) {
243 if (list->data[i].addr) {
244 u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
245 u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
246 u32 mthd = list->data[i].mthd + (list->mthd * inst);
247 const char *name = list->data[i].name;
248 char mods[16];
249
250 if (prev != next)
251 snprintf(mods, sizeof(mods), "-> 0x%08x", next);
252 else
253 snprintf(mods, sizeof(mods), "%13c", ' ');
254
255 nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
256 mthd, prev, mods, name ? " // " : "",
257 name ? name : "");
258 }
259 }
260}
261
262void
263nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
264 const struct nv50_disp_mthd_chan *chan)
265{
266 struct nouveau_object *disp = nv_object(priv);
267 const struct nv50_disp_impl *impl = (void *)disp->oclass;
268 const struct nv50_disp_mthd_list *list;
269 int i, j;
270
271 if (debug > nv_subdev(priv)->debug)
272 return;
273
274 for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
275 u32 base = head * chan->addr;
276 for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
277 const char *cname = chan->name;
278 const char *sname = "";
279 char cname_[16], sname_[16];
280
281 if (chan->addr) {
282 snprintf(cname_, sizeof(cname_), "%s %d",
283 chan->name, head);
284 cname = cname_;
285 }
286
287 if (chan->data[i].nr > 1) {
288 snprintf(sname_, sizeof(sname_), " - %s %d",
289 chan->data[i].name, j);
290 sname = sname_;
291 }
292
293 nv_printk_(disp, debug, "%s%s:\n", cname, sname);
294 nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
295 list, j);
296 }
297 }
298}
299
300const struct nv50_disp_mthd_list
301nv50_disp_mast_mthd_base = {
302 .mthd = 0x0000,
303 .addr = 0x000000,
304 .data = {
305 { 0x0080, 0x000000 },
306 { 0x0084, 0x610bb8 },
307 { 0x0088, 0x610b9c },
308 { 0x008c, 0x000000 },
309 {}
310 }
311};
312
313static const struct nv50_disp_mthd_list
314nv50_disp_mast_mthd_dac = {
315 .mthd = 0x0080,
316 .addr = 0x000008,
317 .data = {
318 { 0x0400, 0x610b58 },
319 { 0x0404, 0x610bdc },
320 { 0x0420, 0x610828 },
321 {}
322 }
323};
324
325const struct nv50_disp_mthd_list
326nv50_disp_mast_mthd_sor = {
327 .mthd = 0x0040,
328 .addr = 0x000008,
329 .data = {
330 { 0x0600, 0x610b70 },
331 {}
332 }
333};
334
335const struct nv50_disp_mthd_list
336nv50_disp_mast_mthd_pior = {
337 .mthd = 0x0040,
338 .addr = 0x000008,
339 .data = {
340 { 0x0700, 0x610b80 },
341 {}
342 }
343};
344
345static const struct nv50_disp_mthd_list
346nv50_disp_mast_mthd_head = {
347 .mthd = 0x0400,
348 .addr = 0x000540,
349 .data = {
350 { 0x0800, 0x610ad8 },
351 { 0x0804, 0x610ad0 },
352 { 0x0808, 0x610a48 },
353 { 0x080c, 0x610a78 },
354 { 0x0810, 0x610ac0 },
355 { 0x0814, 0x610af8 },
356 { 0x0818, 0x610b00 },
357 { 0x081c, 0x610ae8 },
358 { 0x0820, 0x610af0 },
359 { 0x0824, 0x610b08 },
360 { 0x0828, 0x610b10 },
361 { 0x082c, 0x610a68 },
362 { 0x0830, 0x610a60 },
363 { 0x0834, 0x000000 },
364 { 0x0838, 0x610a40 },
365 { 0x0840, 0x610a24 },
366 { 0x0844, 0x610a2c },
367 { 0x0848, 0x610aa8 },
368 { 0x084c, 0x610ab0 },
369 { 0x0860, 0x610a84 },
370 { 0x0864, 0x610a90 },
371 { 0x0868, 0x610b18 },
372 { 0x086c, 0x610b20 },
373 { 0x0870, 0x610ac8 },
374 { 0x0874, 0x610a38 },
375 { 0x0880, 0x610a58 },
376 { 0x0884, 0x610a9c },
377 { 0x08a0, 0x610a70 },
378 { 0x08a4, 0x610a50 },
379 { 0x08a8, 0x610ae0 },
380 { 0x08c0, 0x610b28 },
381 { 0x08c4, 0x610b30 },
382 { 0x08c8, 0x610b40 },
383 { 0x08d4, 0x610b38 },
384 { 0x08d8, 0x610b48 },
385 { 0x08dc, 0x610b50 },
386 { 0x0900, 0x610a18 },
387 { 0x0904, 0x610ab8 },
388 {}
389 }
390};
391
392static const struct nv50_disp_mthd_chan
393nv50_disp_mast_mthd_chan = {
394 .name = "Core",
395 .addr = 0x000000,
396 .data = {
397 { "Global", 1, &nv50_disp_mast_mthd_base },
398 { "DAC", 3, &nv50_disp_mast_mthd_dac },
399 { "SOR", 2, &nv50_disp_mast_mthd_sor },
400 { "PIOR", 3, &nv50_disp_mast_mthd_pior },
401 { "HEAD", 2, &nv50_disp_mast_mthd_head },
402 {}
403 }
404};
405
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000406int
Ben Skeggs70cabe42012-08-14 10:04:04 +1000407nv50_disp_mast_ctor(struct nouveau_object *parent,
408 struct nouveau_object *engine,
409 struct nouveau_oclass *oclass, void *data, u32 size,
410 struct nouveau_object **pobject)
411{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000412 union {
413 struct nv50_disp_core_channel_dma_v0 v0;
414 } *args = data;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000415 struct nv50_disp_dmac *mast;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000416 int ret;
417
Ben Skeggs648d4df2014-08-10 04:10:27 +1000418 nv_ioctl(parent, "create disp core channel dma size %d\n", size);
419 if (nvif_unpack(args->v0, 0, 0, false)) {
420 nv_ioctl(parent, "create disp core channel dma vers %d "
421 "pushbuf %08x\n",
422 args->v0.version, args->v0.pushbuf);
423 } else
424 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000425
Ben Skeggs648d4df2014-08-10 04:10:27 +1000426 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000427 0, sizeof(*mast), (void **)&mast);
428 *pobject = nv_object(mast);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000429 if (ret)
430 return ret;
431
432 return 0;
433}
434
Ben Skeggs70cabe42012-08-14 10:04:04 +1000435static int
436nv50_disp_mast_init(struct nouveau_object *object)
437{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000438 struct nv50_disp_priv *priv = (void *)object->engine;
439 struct nv50_disp_dmac *mast = (void *)object;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000440 int ret;
441
Ben Skeggs370c00f2012-08-14 14:11:49 +1000442 ret = nv50_disp_chan_init(&mast->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000443 if (ret)
444 return ret;
445
Ben Skeggs370c00f2012-08-14 14:11:49 +1000446 /* enable error reporting */
447 nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
448
449 /* attempt to unstick channel from some unknown state */
450 if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
451 nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
452 if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
453 nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
454
455 /* initialise channel for dma command submission */
456 nv_wr32(priv, 0x610204, mast->push);
457 nv_wr32(priv, 0x610208, 0x00010000);
458 nv_wr32(priv, 0x61020c, 0x00000000);
459 nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
460 nv_wr32(priv, 0x640000, 0x00000000);
461 nv_wr32(priv, 0x610200, 0x01000013);
462
463 /* wait for it to go inactive */
464 if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
465 nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
466 return -EBUSY;
467 }
468
Ben Skeggs70cabe42012-08-14 10:04:04 +1000469 return 0;
470}
471
472static int
473nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
474{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000475 struct nv50_disp_priv *priv = (void *)object->engine;
476 struct nv50_disp_dmac *mast = (void *)object;
477
478 /* deactivate channel */
479 nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
480 nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
481 if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
482 nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
483 if (suspend)
484 return -EBUSY;
485 }
486
487 /* disable error reporting */
488 nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
489
490 return nv50_disp_chan_fini(&mast->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000491}
492
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000493struct nv50_disp_chan_impl
Ben Skeggs70cabe42012-08-14 10:04:04 +1000494nv50_disp_mast_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000495 .base.ctor = nv50_disp_mast_ctor,
496 .base.dtor = nv50_disp_dmac_dtor,
497 .base.init = nv50_disp_mast_init,
498 .base.fini = nv50_disp_mast_fini,
499 .base.rd32 = nv50_disp_chan_rd32,
500 .base.wr32 = nv50_disp_chan_wr32,
501 .chid = 0,
502 .attach = nv50_disp_dmac_object_attach,
503 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000504};
505
506/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000507 * EVO sync channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000508 ******************************************************************************/
509
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000510static const struct nv50_disp_mthd_list
511nv50_disp_sync_mthd_base = {
512 .mthd = 0x0000,
513 .addr = 0x000000,
514 .data = {
515 { 0x0080, 0x000000 },
516 { 0x0084, 0x0008c4 },
517 { 0x0088, 0x0008d0 },
518 { 0x008c, 0x0008dc },
519 { 0x0090, 0x0008e4 },
520 { 0x0094, 0x610884 },
521 { 0x00a0, 0x6108a0 },
522 { 0x00a4, 0x610878 },
523 { 0x00c0, 0x61086c },
524 { 0x00e0, 0x610858 },
525 { 0x00e4, 0x610860 },
526 { 0x00e8, 0x6108ac },
527 { 0x00ec, 0x6108b4 },
528 { 0x0100, 0x610894 },
529 { 0x0110, 0x6108bc },
530 { 0x0114, 0x61088c },
531 {}
532 }
533};
534
535const struct nv50_disp_mthd_list
536nv50_disp_sync_mthd_image = {
537 .mthd = 0x0400,
538 .addr = 0x000000,
539 .data = {
540 { 0x0800, 0x6108f0 },
541 { 0x0804, 0x6108fc },
542 { 0x0808, 0x61090c },
543 { 0x080c, 0x610914 },
544 { 0x0810, 0x610904 },
545 {}
546 }
547};
548
549static const struct nv50_disp_mthd_chan
550nv50_disp_sync_mthd_chan = {
551 .name = "Base",
552 .addr = 0x000540,
553 .data = {
554 { "Global", 1, &nv50_disp_sync_mthd_base },
555 { "Image", 2, &nv50_disp_sync_mthd_image },
556 {}
557 }
558};
559
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000560int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000561nv50_disp_sync_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000562 struct nouveau_object *engine,
563 struct nouveau_oclass *oclass, void *data, u32 size,
564 struct nouveau_object **pobject)
565{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000566 union {
567 struct nv50_disp_base_channel_dma_v0 v0;
568 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000569 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000570 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000571 int ret;
572
Ben Skeggs648d4df2014-08-10 04:10:27 +1000573 nv_ioctl(parent, "create disp base channel dma size %d\n", size);
574 if (nvif_unpack(args->v0, 0, 0, false)) {
575 nv_ioctl(parent, "create disp base channel dma vers %d "
576 "pushbuf %08x head %d\n",
577 args->v0.version, args->v0.pushbuf, args->v0.head);
578 if (args->v0.head > priv->head.nr)
579 return -EINVAL;
580 } else
581 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000582
Ben Skeggs648d4df2014-08-10 04:10:27 +1000583 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
584 args->v0.head, sizeof(*dmac),
585 (void **)&dmac);
Ben Skeggs370c00f2012-08-14 14:11:49 +1000586 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000587 if (ret)
588 return ret;
589
590 return 0;
591}
592
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000593struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000594nv50_disp_sync_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000595 .base.ctor = nv50_disp_sync_ctor,
596 .base.dtor = nv50_disp_dmac_dtor,
597 .base.init = nv50_disp_dmac_init,
598 .base.fini = nv50_disp_dmac_fini,
599 .base.rd32 = nv50_disp_chan_rd32,
600 .base.wr32 = nv50_disp_chan_wr32,
601 .chid = 1,
602 .attach = nv50_disp_dmac_object_attach,
603 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000604};
605
606/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000607 * EVO overlay channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000608 ******************************************************************************/
609
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000610const struct nv50_disp_mthd_list
611nv50_disp_ovly_mthd_base = {
612 .mthd = 0x0000,
613 .addr = 0x000000,
614 .data = {
615 { 0x0080, 0x000000 },
616 { 0x0084, 0x0009a0 },
617 { 0x0088, 0x0009c0 },
618 { 0x008c, 0x0009c8 },
619 { 0x0090, 0x6109b4 },
620 { 0x0094, 0x610970 },
621 { 0x00a0, 0x610998 },
622 { 0x00a4, 0x610964 },
623 { 0x00c0, 0x610958 },
624 { 0x00e0, 0x6109a8 },
625 { 0x00e4, 0x6109d0 },
626 { 0x00e8, 0x6109d8 },
627 { 0x0100, 0x61094c },
628 { 0x0104, 0x610984 },
629 { 0x0108, 0x61098c },
630 { 0x0800, 0x6109f8 },
631 { 0x0808, 0x610a08 },
632 { 0x080c, 0x610a10 },
633 { 0x0810, 0x610a00 },
634 {}
635 }
636};
637
638static const struct nv50_disp_mthd_chan
639nv50_disp_ovly_mthd_chan = {
640 .name = "Overlay",
641 .addr = 0x000540,
642 .data = {
643 { "Global", 1, &nv50_disp_ovly_mthd_base },
644 {}
645 }
646};
647
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000648int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000649nv50_disp_ovly_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000650 struct nouveau_object *engine,
651 struct nouveau_oclass *oclass, void *data, u32 size,
652 struct nouveau_object **pobject)
653{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000654 union {
655 struct nv50_disp_overlay_channel_dma_v0 v0;
656 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000657 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000658 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000659 int ret;
660
Ben Skeggs648d4df2014-08-10 04:10:27 +1000661 nv_ioctl(parent, "create disp overlay channel dma size %d\n", size);
662 if (nvif_unpack(args->v0, 0, 0, false)) {
663 nv_ioctl(parent, "create disp overlay channel dma vers %d "
664 "pushbuf %08x head %d\n",
665 args->v0.version, args->v0.pushbuf, args->v0.head);
666 if (args->v0.head > priv->head.nr)
667 return -EINVAL;
668 } else
669 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000670
Ben Skeggs648d4df2014-08-10 04:10:27 +1000671 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
672 args->v0.head, sizeof(*dmac),
673 (void **)&dmac);
Ben Skeggs370c00f2012-08-14 14:11:49 +1000674 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000675 if (ret)
676 return ret;
677
678 return 0;
679}
680
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000681struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000682nv50_disp_ovly_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000683 .base.ctor = nv50_disp_ovly_ctor,
684 .base.dtor = nv50_disp_dmac_dtor,
685 .base.init = nv50_disp_dmac_init,
686 .base.fini = nv50_disp_dmac_fini,
687 .base.rd32 = nv50_disp_chan_rd32,
688 .base.wr32 = nv50_disp_chan_wr32,
689 .chid = 3,
690 .attach = nv50_disp_dmac_object_attach,
691 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000692};
693
694/*******************************************************************************
695 * EVO PIO channel base class
696 ******************************************************************************/
697
698static int
699nv50_disp_pioc_create_(struct nouveau_object *parent,
700 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000701 struct nouveau_oclass *oclass, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000702 int length, void **pobject)
703{
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000704 return nv50_disp_chan_create_(parent, engine, oclass, head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000705 length, pobject);
706}
707
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000708void
Ben Skeggs70cabe42012-08-14 10:04:04 +1000709nv50_disp_pioc_dtor(struct nouveau_object *object)
710{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000711 struct nv50_disp_pioc *pioc = (void *)object;
712 nv50_disp_chan_destroy(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000713}
714
715static int
716nv50_disp_pioc_init(struct nouveau_object *object)
717{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000718 struct nv50_disp_priv *priv = (void *)object->engine;
719 struct nv50_disp_pioc *pioc = (void *)object;
720 int chid = pioc->base.chid;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000721 int ret;
722
Ben Skeggs370c00f2012-08-14 14:11:49 +1000723 ret = nv50_disp_chan_init(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000724 if (ret)
725 return ret;
726
Ben Skeggs370c00f2012-08-14 14:11:49 +1000727 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
728 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
729 nv_error(pioc, "timeout0: 0x%08x\n",
730 nv_rd32(priv, 0x610200 + (chid * 0x10)));
731 return -EBUSY;
732 }
733
734 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
735 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
736 nv_error(pioc, "timeout1: 0x%08x\n",
737 nv_rd32(priv, 0x610200 + (chid * 0x10)));
738 return -EBUSY;
739 }
740
Ben Skeggs70cabe42012-08-14 10:04:04 +1000741 return 0;
742}
743
744static int
745nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
746{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000747 struct nv50_disp_priv *priv = (void *)object->engine;
748 struct nv50_disp_pioc *pioc = (void *)object;
749 int chid = pioc->base.chid;
750
751 nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
752 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
753 nv_error(pioc, "timeout: 0x%08x\n",
754 nv_rd32(priv, 0x610200 + (chid * 0x10)));
755 if (suspend)
756 return -EBUSY;
757 }
758
759 return nv50_disp_chan_fini(&pioc->base, suspend);
760}
761
762/*******************************************************************************
763 * EVO immediate overlay channel objects
764 ******************************************************************************/
765
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000766int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000767nv50_disp_oimm_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{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000772 union {
773 struct nv50_disp_overlay_v0 v0;
774 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000775 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000776 struct nv50_disp_pioc *pioc;
777 int ret;
778
Ben Skeggs648d4df2014-08-10 04:10:27 +1000779 nv_ioctl(parent, "create disp overlay size %d\n", size);
780 if (nvif_unpack(args->v0, 0, 0, false)) {
781 nv_ioctl(parent, "create disp overlay vers %d head %d\n",
782 args->v0.version, args->v0.head);
783 if (args->v0.head > priv->head.nr)
784 return -EINVAL;
785 } else
786 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000787
Ben Skeggs648d4df2014-08-10 04:10:27 +1000788 ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000789 sizeof(*pioc), (void **)&pioc);
790 *pobject = nv_object(pioc);
791 if (ret)
792 return ret;
793
794 return 0;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000795}
796
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000797struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000798nv50_disp_oimm_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000799 .base.ctor = nv50_disp_oimm_ctor,
800 .base.dtor = nv50_disp_pioc_dtor,
801 .base.init = nv50_disp_pioc_init,
802 .base.fini = nv50_disp_pioc_fini,
803 .base.rd32 = nv50_disp_chan_rd32,
804 .base.wr32 = nv50_disp_chan_wr32,
805 .chid = 5,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000806};
807
808/*******************************************************************************
809 * EVO cursor channel objects
810 ******************************************************************************/
811
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000812int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000813nv50_disp_curs_ctor(struct nouveau_object *parent,
814 struct nouveau_object *engine,
815 struct nouveau_oclass *oclass, void *data, u32 size,
816 struct nouveau_object **pobject)
817{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000818 union {
819 struct nv50_disp_cursor_v0 v0;
820 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000821 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000822 struct nv50_disp_pioc *pioc;
823 int ret;
824
Ben Skeggs648d4df2014-08-10 04:10:27 +1000825 nv_ioctl(parent, "create disp cursor size %d\n", size);
826 if (nvif_unpack(args->v0, 0, 0, false)) {
827 nv_ioctl(parent, "create disp cursor vers %d head %d\n",
828 args->v0.version, args->v0.head);
829 if (args->v0.head > priv->head.nr)
830 return -EINVAL;
831 } else
832 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000833
Ben Skeggs648d4df2014-08-10 04:10:27 +1000834 ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000835 sizeof(*pioc), (void **)&pioc);
836 *pobject = nv_object(pioc);
837 if (ret)
838 return ret;
839
840 return 0;
841}
842
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000843struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000844nv50_disp_curs_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000845 .base.ctor = nv50_disp_curs_ctor,
846 .base.dtor = nv50_disp_pioc_dtor,
847 .base.init = nv50_disp_pioc_init,
848 .base.fini = nv50_disp_pioc_fini,
849 .base.rd32 = nv50_disp_chan_rd32,
850 .base.wr32 = nv50_disp_chan_wr32,
851 .chid = 7,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000852};
853
854/*******************************************************************************
855 * Base display object
856 ******************************************************************************/
857
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000858int
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000859nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000860{
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000861 const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
862 const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
863 const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
864 union {
865 struct nv04_disp_scanoutpos_v0 v0;
866 } *args = data;
867 int ret;
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000868
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000869 nv_ioctl(object, "disp scanoutpos size %d\n", size);
870 if (nvif_unpack(args->v0, 0, 0, false)) {
871 nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
872 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
873 args->v0.hblanke = (blanke & 0x0000ffff);
874 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
875 args->v0.hblanks = (blanks & 0x0000ffff);
876 args->v0.vtotal = ( total & 0xffff0000) >> 16;
877 args->v0.htotal = ( total & 0x0000ffff);
878 args->v0.time[0] = ktime_to_ns(ktime_get());
879 args->v0.vline = /* vline read locks hline */
880 nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
881 args->v0.time[1] = ktime_to_ns(ktime_get());
882 args->v0.hline =
883 nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
884 } else
885 return ret;
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000886
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000887 return 0;
888}
889
Ben Skeggs79ca2772014-08-10 04:10:20 +1000890int
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000891nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
892 void *data, u32 size)
893{
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000894 const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000895 union {
896 struct nv50_disp_mthd_v0 v0;
897 struct nv50_disp_mthd_v1 v1;
898 } *args = data;
899 struct nv50_disp_priv *priv = (void *)object->engine;
900 struct nvkm_output *outp = NULL;
901 struct nvkm_output *temp;
902 u16 type, mask = 0;
903 int head, ret;
904
905 if (mthd != NV50_DISP_MTHD)
906 return -EINVAL;
907
908 nv_ioctl(object, "disp mthd size %d\n", size);
909 if (nvif_unpack(args->v0, 0, 0, true)) {
910 nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
911 args->v0.version, args->v0.method, args->v0.head);
912 mthd = args->v0.method;
913 head = args->v0.head;
914 } else
915 if (nvif_unpack(args->v1, 1, 1, true)) {
916 nv_ioctl(object, "disp mthd vers %d mthd %02x "
917 "type %04x mask %04x\n",
918 args->v1.version, args->v1.method,
919 args->v1.hasht, args->v1.hashm);
920 mthd = args->v1.method;
921 type = args->v1.hasht;
922 mask = args->v1.hashm;
923 head = ffs((mask >> 8) & 0x0f) - 1;
924 } else
925 return ret;
926
927 if (head < 0 || head >= priv->head.nr)
928 return -ENXIO;
929
930 if (mask) {
931 list_for_each_entry(temp, &priv->base.outp, head) {
932 if ((temp->info.hasht == type) &&
933 (temp->info.hashm & mask) == mask) {
934 outp = temp;
935 break;
936 }
937 }
938 if (outp == NULL)
939 return -ENXIO;
940 }
941
942 switch (mthd) {
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000943 case NV50_DISP_SCANOUTPOS:
944 return impl->head.scanoutpos(object, priv, data, size, head);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000945 default:
946 break;
947 }
948
949 switch (mthd * !!outp) {
950 case NV50_DISP_MTHD_V1_DAC_PWR:
951 return priv->dac.power(object, priv, data, size, head, outp);
Ben Skeggsc4abd312014-08-10 04:10:26 +1000952 case NV50_DISP_MTHD_V1_DAC_LOAD:
953 return priv->dac.sense(object, priv, data, size, head, outp);
Ben Skeggsd55b4af2014-08-10 04:10:26 +1000954 case NV50_DISP_MTHD_V1_SOR_PWR:
955 return priv->sor.power(object, priv, data, size, head, outp);
Ben Skeggs120b0c32014-08-10 04:10:26 +1000956 case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
957 if (!priv->sor.hda_eld)
958 return -ENODEV;
959 return priv->sor.hda_eld(object, priv, data, size, head, outp);
Ben Skeggse00f2232014-08-10 04:10:26 +1000960 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
961 if (!priv->sor.hdmi)
962 return -ENODEV;
963 return priv->sor.hdmi(object, priv, data, size, head, outp);
Ben Skeggsa3761fa2014-08-10 04:10:27 +1000964 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
965 union {
966 struct nv50_disp_sor_lvds_script_v0 v0;
967 } *args = data;
968 nv_ioctl(object, "disp sor lvds script size %d\n", size);
969 if (nvif_unpack(args->v0, 0, 0, false)) {
970 nv_ioctl(object, "disp sor lvds script "
971 "vers %d name %04x\n",
972 args->v0.version, args->v0.script);
973 priv->sor.lvdsconf = args->v0.script;
974 return 0;
975 } else
976 return ret;
977 }
978 break;
Ben Skeggsc02ed2b2014-08-10 04:10:27 +1000979 case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
980 struct nvkm_output_dp *outpdp = (void *)outp;
981 union {
982 struct nv50_disp_sor_dp_pwr_v0 v0;
983 } *args = data;
984 nv_ioctl(object, "disp sor dp pwr size %d\n", size);
985 if (nvif_unpack(args->v0, 0, 0, false)) {
986 nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
987 args->v0.version, args->v0.state);
988 if (args->v0.state == 0) {
989 nvkm_notify_put(&outpdp->irq);
990 ((struct nvkm_output_dp_impl *)nv_oclass(outp))
991 ->lnk_pwr(outpdp, 0);
992 atomic_set(&outpdp->lt.done, 0);
993 return 0;
994 } else
995 if (args->v0.state != 0) {
996 nvkm_output_dp_train(&outpdp->base, 0, true);
997 return 0;
998 }
999 } else
1000 return ret;
1001 }
1002 break;
Ben Skeggs67cb49c2014-08-10 04:10:27 +10001003 case NV50_DISP_MTHD_V1_PIOR_PWR:
1004 if (!priv->pior.power)
1005 return -ENODEV;
1006 return priv->pior.power(object, priv, data, size, head, outp);
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001007 default:
1008 break;
1009 }
1010
1011 return -EINVAL;
1012}
1013
1014int
Ben Skeggs70cabe42012-08-14 10:04:04 +10001015nv50_disp_base_ctor(struct nouveau_object *parent,
1016 struct nouveau_object *engine,
1017 struct nouveau_oclass *oclass, void *data, u32 size,
1018 struct nouveau_object **pobject)
1019{
1020 struct nv50_disp_priv *priv = (void *)engine;
1021 struct nv50_disp_base *base;
1022 int ret;
1023
1024 ret = nouveau_parent_create(parent, engine, oclass, 0,
1025 priv->sclass, 0, &base);
1026 *pobject = nv_object(base);
1027 if (ret)
1028 return ret;
1029
Ben Skeggs2ecda482013-04-24 18:04:22 +10001030 return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
1031 &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001032}
1033
Ben Skeggs79ca2772014-08-10 04:10:20 +10001034void
Ben Skeggs70cabe42012-08-14 10:04:04 +10001035nv50_disp_base_dtor(struct nouveau_object *object)
1036{
1037 struct nv50_disp_base *base = (void *)object;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001038 nouveau_ramht_ref(NULL, &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001039 nouveau_parent_destroy(&base->base);
1040}
1041
1042static int
1043nv50_disp_base_init(struct nouveau_object *object)
1044{
Ben Skeggsab772142012-08-14 11:29:57 +10001045 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001046 struct nv50_disp_base *base = (void *)object;
Ben Skeggsab772142012-08-14 11:29:57 +10001047 int ret, i;
1048 u32 tmp;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001049
1050 ret = nouveau_parent_init(&base->base);
1051 if (ret)
1052 return ret;
1053
Ben Skeggsab772142012-08-14 11:29:57 +10001054 /* The below segments of code copying values from one register to
1055 * another appear to inform EVO of the display capabilities or
1056 * something similar. NFI what the 0x614004 caps are for..
1057 */
1058 tmp = nv_rd32(priv, 0x614004);
1059 nv_wr32(priv, 0x610184, tmp);
1060
1061 /* ... CRTC caps */
1062 for (i = 0; i < priv->head.nr; i++) {
1063 tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
1064 nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
1065 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
1066 nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
1067 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
1068 nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
1069 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
1070 nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
1071 }
1072
1073 /* ... DAC caps */
1074 for (i = 0; i < priv->dac.nr; i++) {
1075 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
1076 nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
1077 }
1078
1079 /* ... SOR caps */
1080 for (i = 0; i < priv->sor.nr; i++) {
1081 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
1082 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
1083 }
1084
Ben Skeggs476e84e2013-02-11 09:24:23 +10001085 /* ... PIOR caps */
Emil Velikovb969fa52013-07-30 01:01:10 +01001086 for (i = 0; i < priv->pior.nr; i++) {
Ben Skeggsab772142012-08-14 11:29:57 +10001087 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
1088 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
1089 }
1090
Ben Skeggs446b05a2012-08-14 12:50:14 +10001091 /* steal display away from vbios, or something like that */
1092 if (nv_rd32(priv, 0x610024) & 0x00000100) {
1093 nv_wr32(priv, 0x610024, 0x00000100);
1094 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
1095 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
1096 nv_error(priv, "timeout acquiring display\n");
1097 return -EBUSY;
1098 }
1099 }
1100
1101 /* point at display engine memory area (hash table, objects) */
Ben Skeggs370c00f2012-08-14 14:11:49 +10001102 nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
Ben Skeggs446b05a2012-08-14 12:50:14 +10001103
1104 /* enable supervisor interrupts, disable everything else */
Ben Skeggs370c00f2012-08-14 14:11:49 +10001105 nv_wr32(priv, 0x61002c, 0x00000370);
1106 nv_wr32(priv, 0x610028, 0x00000000);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001107 return 0;
1108}
1109
1110static int
1111nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
1112{
Ben Skeggs446b05a2012-08-14 12:50:14 +10001113 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001114 struct nv50_disp_base *base = (void *)object;
Ben Skeggs446b05a2012-08-14 12:50:14 +10001115
1116 /* disable all interrupts */
1117 nv_wr32(priv, 0x610024, 0x00000000);
1118 nv_wr32(priv, 0x610020, 0x00000000);
1119
Ben Skeggs70cabe42012-08-14 10:04:04 +10001120 return nouveau_parent_fini(&base->base, suspend);
1121}
1122
1123struct nouveau_ofuncs
1124nv50_disp_base_ofuncs = {
1125 .ctor = nv50_disp_base_ctor,
1126 .dtor = nv50_disp_base_dtor,
1127 .init = nv50_disp_base_init,
1128 .fini = nv50_disp_base_fini,
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001129 .mthd = nv50_disp_base_mthd,
Ben Skeggs70cabe42012-08-14 10:04:04 +10001130};
1131
1132static struct nouveau_oclass
1133nv50_disp_base_oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001134 { NV50_DISP, &nv50_disp_base_ofuncs },
Ben Skeggs370c00f2012-08-14 14:11:49 +10001135 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +10001136};
1137
1138static struct nouveau_oclass
1139nv50_disp_sclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001140 { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
1141 { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
1142 { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
1143 { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
1144 { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
Ben Skeggs70cabe42012-08-14 10:04:04 +10001145 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +10001146};
1147
Ben Skeggs70cabe42012-08-14 10:04:04 +10001148/*******************************************************************************
1149 * Display context, tracks instmem allocation and prevents more than one
1150 * client using the display hardware at any time.
1151 ******************************************************************************/
1152
1153static int
1154nv50_disp_data_ctor(struct nouveau_object *parent,
1155 struct nouveau_object *engine,
1156 struct nouveau_oclass *oclass, void *data, u32 size,
1157 struct nouveau_object **pobject)
1158{
Ben Skeggs370c00f2012-08-14 14:11:49 +10001159 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001160 struct nouveau_engctx *ectx;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001161 int ret = -EBUSY;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001162
Ben Skeggs370c00f2012-08-14 14:11:49 +10001163 /* no context needed for channel objects... */
Ben Skeggs586491e2014-08-10 04:10:24 +10001164 if (nv_mclass(parent) != NV_DEVICE) {
Ben Skeggs370c00f2012-08-14 14:11:49 +10001165 atomic_inc(&parent->refcount);
1166 *pobject = parent;
Ben Skeggs43e6e512013-04-26 00:12:59 +10001167 return 1;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001168 }
Ben Skeggs70cabe42012-08-14 10:04:04 +10001169
Ben Skeggs370c00f2012-08-14 14:11:49 +10001170 /* allocate display hardware to client */
1171 mutex_lock(&nv_subdev(priv)->mutex);
1172 if (list_empty(&nv_engine(priv)->contexts)) {
1173 ret = nouveau_engctx_create(parent, engine, oclass, NULL,
1174 0x10000, 0x10000,
1175 NVOBJ_FLAG_HEAP, &ectx);
1176 *pobject = nv_object(ectx);
1177 }
1178 mutex_unlock(&nv_subdev(priv)->mutex);
1179 return ret;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001180}
1181
1182struct nouveau_oclass
1183nv50_disp_cclass = {
1184 .handle = NV_ENGCTX(DISP, 0x50),
1185 .ofuncs = &(struct nouveau_ofuncs) {
1186 .ctor = nv50_disp_data_ctor,
1187 .dtor = _nouveau_engctx_dtor,
1188 .init = _nouveau_engctx_init,
1189 .fini = _nouveau_engctx_fini,
1190 .rd32 = _nouveau_engctx_rd32,
1191 .wr32 = _nouveau_engctx_wr32,
1192 },
1193};
1194
1195/*******************************************************************************
1196 * Display engine implementation
1197 ******************************************************************************/
1198
Ben Skeggs79ca2772014-08-10 04:10:20 +10001199static void
1200nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
1201{
1202 struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
1203 nv_mask(disp, 0x61002c, (4 << head), 0);
1204}
1205
1206static void
1207nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
1208{
1209 struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
1210 nv_mask(disp, 0x61002c, (4 << head), (4 << head));
1211}
1212
1213const struct nvkm_event_func
1214nv50_disp_vblank_func = {
1215 .ctor = nouveau_disp_vblank_ctor,
1216 .init = nv50_disp_vblank_init,
1217 .fini = nv50_disp_vblank_fini,
1218};
1219
Ben Skeggs117e16332014-02-21 11:06:40 +10001220static const struct nouveau_enum
1221nv50_disp_intr_error_type[] = {
1222 { 3, "ILLEGAL_MTHD" },
1223 { 4, "INVALID_VALUE" },
1224 { 5, "INVALID_STATE" },
1225 { 7, "INVALID_HANDLE" },
1226 {}
1227};
1228
1229static const struct nouveau_enum
1230nv50_disp_intr_error_code[] = {
1231 { 0x00, "" },
1232 {}
1233};
1234
Ben Skeggsebb945a2012-07-20 08:17:34 +10001235static void
Ben Skeggs117e16332014-02-21 11:06:40 +10001236nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001237{
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001238 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs117e16332014-02-21 11:06:40 +10001239 u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
1240 u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
1241 u32 code = (addr & 0x00ff0000) >> 16;
1242 u32 type = (addr & 0x00007000) >> 12;
1243 u32 mthd = (addr & 0x00000ffc);
1244 const struct nouveau_enum *ec, *et;
1245 char ecunk[6], etunk[6];
Ben Skeggs186ecad2012-11-09 12:09:48 +10001246
Ben Skeggs117e16332014-02-21 11:06:40 +10001247 et = nouveau_enum_find(nv50_disp_intr_error_type, type);
1248 if (!et)
1249 snprintf(etunk, sizeof(etunk), "UNK%02X", type);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001250
Ben Skeggs117e16332014-02-21 11:06:40 +10001251 ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
1252 if (!ec)
1253 snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001254
Ben Skeggs117e16332014-02-21 11:06:40 +10001255 nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
1256 et ? et->name : etunk, ec ? ec->name : ecunk,
1257 chid, mthd, data);
1258
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001259 if (chid == 0) {
1260 switch (mthd) {
1261 case 0x0080:
1262 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
1263 impl->mthd.core);
1264 break;
1265 default:
1266 break;
1267 }
1268 } else
1269 if (chid <= 2) {
1270 switch (mthd) {
1271 case 0x0080:
1272 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
1273 impl->mthd.base);
1274 break;
1275 default:
1276 break;
1277 }
1278 } else
1279 if (chid <= 4) {
1280 switch (mthd) {
1281 case 0x0080:
1282 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
1283 impl->mthd.ovly);
1284 break;
1285 default:
1286 break;
1287 }
1288 }
1289
Ben Skeggs117e16332014-02-21 11:06:40 +10001290 nv_wr32(priv, 0x610020, 0x00010000 << chid);
1291 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001292}
1293
Ben Skeggs415f12e2014-05-21 11:24:43 +10001294static struct nvkm_output *
1295exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
1296 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001297 struct nvbios_outp *info)
1298{
1299 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001300 struct nvkm_output *outp;
1301 u16 mask, type;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001302
Ben Skeggs415f12e2014-05-21 11:24:43 +10001303 if (or < 4) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001304 type = DCB_OUTPUT_ANALOG;
1305 mask = 0;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001306 } else
Ben Skeggs415f12e2014-05-21 11:24:43 +10001307 if (or < 8) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001308 switch (ctrl & 0x00000f00) {
1309 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
1310 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
1311 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
1312 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
1313 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
1314 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
1315 default:
1316 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001317 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001318 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001319 or -= 4;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001320 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001321 or = or - 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001322 type = 0x0010;
1323 mask = 0;
1324 switch (ctrl & 0x00000f00) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001325 case 0x00000000: type |= priv->pior.type[or]; break;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001326 default:
1327 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001328 return NULL;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001329 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001330 }
1331
1332 mask = 0x00c0 & (mask << 6);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001333 mask |= 0x0001 << or;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001334 mask |= 0x0100 << head;
1335
Ben Skeggs415f12e2014-05-21 11:24:43 +10001336 list_for_each_entry(outp, &priv->base.outp, head) {
1337 if ((outp->info.hasht & 0xff) == type &&
1338 (outp->info.hashm & mask) == mask) {
1339 *data = nvbios_outp_match(bios, outp->info.hasht,
1340 outp->info.hashm,
1341 ver, hdr, cnt, len, info);
1342 if (!*data)
1343 return NULL;
1344 return outp;
1345 }
1346 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001347
Ben Skeggs415f12e2014-05-21 11:24:43 +10001348 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001349}
1350
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001351static struct nvkm_output *
Ben Skeggs186ecad2012-11-09 12:09:48 +10001352exec_script(struct nv50_disp_priv *priv, int head, int id)
1353{
1354 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001355 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001356 struct nvbios_outp info;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001357 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001358 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001359 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001360 int i;
1361
Ben Skeggs476e84e2013-02-11 09:24:23 +10001362 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001363 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001364 ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
1365
Ben Skeggs476e84e2013-02-11 09:24:23 +10001366 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001367 if (!(ctrl & (1 << head))) {
1368 if (nv_device(priv)->chipset < 0x90 ||
1369 nv_device(priv)->chipset == 0x92 ||
1370 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001371 reg = 0x610b74;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001372 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001373 reg = 0x610798;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001374 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001375 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1376 ctrl = nv_rd32(priv, reg + (i * 8));
1377 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001378 }
1379
Ben Skeggs476e84e2013-02-11 09:24:23 +10001380 /* PIOR */
1381 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001382 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001383 ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
1384 i += 8;
1385 }
1386
Ben Skeggs186ecad2012-11-09 12:09:48 +10001387 if (!(ctrl & (1 << head)))
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001388 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001389 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001390
Ben Skeggs415f12e2014-05-21 11:24:43 +10001391 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
1392 if (outp) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001393 struct nvbios_init init = {
1394 .subdev = nv_subdev(priv),
1395 .bios = bios,
1396 .offset = info.script[id],
Ben Skeggs415f12e2014-05-21 11:24:43 +10001397 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001398 .crtc = head,
1399 .execute = 1,
1400 };
1401
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001402 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001403 }
1404
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001405 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001406}
1407
Ben Skeggs415f12e2014-05-21 11:24:43 +10001408static struct nvkm_output *
1409exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001410{
1411 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001412 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001413 struct nvbios_outp info1;
1414 struct nvbios_ocfg info2;
1415 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001416 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001417 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001418 int i;
1419
Ben Skeggs476e84e2013-02-11 09:24:23 +10001420 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001421 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001422 ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
1423
Ben Skeggs476e84e2013-02-11 09:24:23 +10001424 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001425 if (!(ctrl & (1 << head))) {
1426 if (nv_device(priv)->chipset < 0x90 ||
1427 nv_device(priv)->chipset == 0x92 ||
1428 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001429 reg = 0x610b70;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001430 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001431 reg = 0x610794;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001432 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001433 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1434 ctrl = nv_rd32(priv, reg + (i * 8));
1435 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001436 }
1437
Ben Skeggs476e84e2013-02-11 09:24:23 +10001438 /* PIOR */
1439 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001440 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001441 ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
1442 i += 8;
1443 }
1444
Ben Skeggs186ecad2012-11-09 12:09:48 +10001445 if (!(ctrl & (1 << head)))
Ben Skeggs415f12e2014-05-21 11:24:43 +10001446 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001447 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001448
Ben Skeggs415f12e2014-05-21 11:24:43 +10001449 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
Ben Skeggsba5e01b2014-06-17 09:39:18 +10001450 if (!outp)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001451 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001452
Ben Skeggs415f12e2014-05-21 11:24:43 +10001453 if (outp->info.location == 0) {
1454 switch (outp->info.type) {
Ben Skeggs476e84e2013-02-11 09:24:23 +10001455 case DCB_OUTPUT_TMDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001456 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001457 if (pclk >= 165000)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001458 *conf |= 0x0100;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001459 break;
1460 case DCB_OUTPUT_LVDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001461 *conf = priv->sor.lvdsconf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001462 break;
1463 case DCB_OUTPUT_DP:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001464 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001465 break;
1466 case DCB_OUTPUT_ANALOG:
1467 default:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001468 *conf = 0x00ff;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001469 break;
1470 }
1471 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001472 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001473 pclk = pclk / 2;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001474 }
1475
Ben Skeggs415f12e2014-05-21 11:24:43 +10001476 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001477 if (data && id < 0xff) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001478 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1479 if (data) {
1480 struct nvbios_init init = {
1481 .subdev = nv_subdev(priv),
1482 .bios = bios,
1483 .offset = data,
Ben Skeggs415f12e2014-05-21 11:24:43 +10001484 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001485 .crtc = head,
1486 .execute = 1,
1487 };
1488
Ben Skeggs46c13c12013-02-16 13:49:21 +10001489 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001490 }
1491 }
1492
Ben Skeggs415f12e2014-05-21 11:24:43 +10001493 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001494}
1495
1496static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001497nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001498{
Ben Skeggs16d4c032013-02-20 18:56:33 +10001499 exec_script(priv, head, 1);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001500}
1501
1502static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001503nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
1504{
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001505 struct nvkm_output *outp = exec_script(priv, head, 2);
1506
1507 /* the binary driver does this outside of the supervisor handling
1508 * (after the third supervisor from a detach). we (currently?)
1509 * allow both detach/attach to happen in the same set of
1510 * supervisor interrupts, so it would make sense to execute this
1511 * (full power down?) script after all the detach phases of the
1512 * supervisor handling. like with training if needed from the
1513 * second supervisor, nvidia doesn't do this, so who knows if it's
1514 * entirely safe, but it does appear to work..
1515 *
1516 * without this script being run, on some configurations i've
1517 * seen, switching from DP to TMDS on a DP connector may result
1518 * in a blank screen (SOR_PWR off/on can restore it)
1519 */
1520 if (outp && outp->info.type == DCB_OUTPUT_DP) {
1521 struct nvkm_output_dp *outpdp = (void *)outp;
1522 struct nvbios_init init = {
1523 .subdev = nv_subdev(priv),
1524 .bios = nouveau_bios(priv),
1525 .outp = &outp->info,
1526 .crtc = head,
1527 .offset = outpdp->info.script[4],
1528 .execute = 1,
1529 };
1530
1531 nvbios_exec(&init);
1532 atomic_set(&outpdp->lt.done, 0);
1533 }
Ben Skeggs16d4c032013-02-20 18:56:33 +10001534}
1535
1536static void
1537nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
1538{
Ben Skeggs88524bc2013-03-05 10:53:54 +10001539 struct nouveau_devinit *devinit = nouveau_devinit(priv);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001540 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1541 if (pclk)
Ben Skeggs88524bc2013-03-05 10:53:54 +10001542 devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001543}
1544
1545static void
1546nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
1547 struct dcb_output *outp, u32 pclk)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001548{
1549 const int link = !(outp->sorconf.link & 1);
1550 const int or = ffs(outp->or) - 1;
1551 const u32 soff = ( or * 0x800);
1552 const u32 loff = (link * 0x080) + soff;
1553 const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
Ben Skeggs186ecad2012-11-09 12:09:48 +10001554 const u32 symbol = 100000;
1555 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
1556 u32 clksor = nv_rd32(priv, 0x614300 + soff);
1557 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
1558 int TU, VTUi, VTUf, VTUa;
1559 u64 link_data_rate, link_ratio, unk;
1560 u32 best_diff = 64 * symbol;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001561 u32 link_nr, link_bw, bits, r;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001562
1563 /* calculate packed data rate for each lane */
1564 if (dpctrl > 0x00030000) link_nr = 4;
1565 else if (dpctrl > 0x00010000) link_nr = 2;
1566 else link_nr = 1;
1567
1568 if (clksor & 0x000c0000)
1569 link_bw = 270000;
1570 else
1571 link_bw = 162000;
1572
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001573 if ((ctrl & 0xf0000) == 0x60000) bits = 30;
1574 else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
1575 else bits = 18;
1576
Ben Skeggs186ecad2012-11-09 12:09:48 +10001577 link_data_rate = (pclk * bits / 8) / link_nr;
1578
1579 /* calculate ratio of packed data rate to link symbol rate */
1580 link_ratio = link_data_rate * symbol;
1581 r = do_div(link_ratio, link_bw);
1582
1583 for (TU = 64; TU >= 32; TU--) {
1584 /* calculate average number of valid symbols in each TU */
1585 u32 tu_valid = link_ratio * TU;
1586 u32 calc, diff;
1587
1588 /* find a hw representation for the fraction.. */
1589 VTUi = tu_valid / symbol;
1590 calc = VTUi * symbol;
1591 diff = tu_valid - calc;
1592 if (diff) {
1593 if (diff >= (symbol / 2)) {
1594 VTUf = symbol / (symbol - diff);
1595 if (symbol - (VTUf * diff))
1596 VTUf++;
1597
1598 if (VTUf <= 15) {
1599 VTUa = 1;
1600 calc += symbol - (symbol / VTUf);
1601 } else {
1602 VTUa = 0;
1603 VTUf = 1;
1604 calc += symbol;
1605 }
1606 } else {
1607 VTUa = 0;
1608 VTUf = min((int)(symbol / diff), 15);
1609 calc += symbol / VTUf;
1610 }
1611
1612 diff = calc - tu_valid;
1613 } else {
1614 /* no remainder, but the hw doesn't like the fractional
1615 * part to be zero. decrement the integer part and
1616 * have the fraction add a whole symbol back
1617 */
1618 VTUa = 0;
1619 VTUf = 1;
1620 VTUi--;
1621 }
1622
1623 if (diff < best_diff) {
1624 best_diff = diff;
1625 bestTU = TU;
1626 bestVTUa = VTUa;
1627 bestVTUf = VTUf;
1628 bestVTUi = VTUi;
1629 if (diff == 0)
1630 break;
1631 }
1632 }
1633
1634 if (!bestTU) {
1635 nv_error(priv, "unable to find suitable dp config\n");
1636 return;
1637 }
1638
1639 /* XXX close to vbios numbers, but not right */
1640 unk = (symbol - link_ratio) * bestTU;
1641 unk *= link_ratio;
1642 r = do_div(unk, symbol);
1643 r = do_div(unk, symbol);
1644 unk += 6;
1645
1646 nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
1647 nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
1648 bestVTUf << 16 |
1649 bestVTUi << 8 | unk);
1650}
1651
1652static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001653nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001654{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001655 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001656 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1657 u32 hval, hreg = 0x614200 + (head * 0x800);
1658 u32 oval, oreg;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001659 u32 mask, conf;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001660
Ben Skeggs415f12e2014-05-21 11:24:43 +10001661 outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
1662 if (!outp)
1663 return;
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001664
Ben Skeggs55f083c2014-05-20 10:18:03 +10001665 /* we allow both encoder attach and detach operations to occur
1666 * within a single supervisor (ie. modeset) sequence. the
1667 * encoder detach scripts quite often switch off power to the
1668 * lanes, which requires the link to be re-trained.
1669 *
1670 * this is not generally an issue as the sink "must" (heh)
1671 * signal an irq when it's lost sync so the driver can
1672 * re-train.
1673 *
1674 * however, on some boards, if one does not configure at least
1675 * the gpu side of the link *before* attaching, then various
1676 * things can go horribly wrong (PDISP disappearing from mmio,
1677 * third supervisor never happens, etc).
1678 *
1679 * the solution is simply to retrain here, if necessary. last
1680 * i checked, the binary driver userspace does not appear to
1681 * trigger this situation (it forces an UPDATE between steps).
1682 */
Ben Skeggsb17932c2014-05-27 15:00:36 +10001683 if (outp->info.type == DCB_OUTPUT_DP) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001684 u32 soff = (ffs(outp->info.or) - 1) * 0x08;
Ben Skeggsb17932c2014-05-27 15:00:36 +10001685 u32 ctrl, datarate;
1686
1687 if (outp->info.location == 0) {
1688 ctrl = nv_rd32(priv, 0x610794 + soff);
1689 soff = 1;
1690 } else {
1691 ctrl = nv_rd32(priv, 0x610b80 + soff);
1692 soff = 2;
1693 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001694
1695 switch ((ctrl & 0x000f0000) >> 16) {
Ben Skeggs0713b452014-07-01 10:54:52 +10001696 case 6: datarate = pclk * 30; break;
1697 case 5: datarate = pclk * 24; break;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001698 case 2:
1699 default:
Ben Skeggs0713b452014-07-01 10:54:52 +10001700 datarate = pclk * 18;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001701 break;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001702 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001703
Ben Skeggs55f083c2014-05-20 10:18:03 +10001704 if (nvkm_output_dp_train(outp, datarate / soff, true))
1705 ERR("link not trained before attach\n");
Ben Skeggs16d4c032013-02-20 18:56:33 +10001706 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001707
1708 exec_clkcmp(priv, head, 0, pclk, &conf);
1709
1710 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
1711 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
1712 oval = 0x00000000;
1713 hval = 0x00000000;
1714 mask = 0xffffffff;
1715 } else
1716 if (!outp->info.location) {
1717 if (outp->info.type == DCB_OUTPUT_DP)
1718 nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
1719 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
1720 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1721 hval = 0x00000000;
1722 mask = 0x00000707;
1723 } else {
1724 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
1725 oval = 0x00000001;
1726 hval = 0x00000001;
1727 mask = 0x00000707;
1728 }
1729
1730 nv_mask(priv, hreg, 0x0000000f, hval);
1731 nv_mask(priv, oreg, mask, oval);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001732}
1733
1734/* If programming a TMDS output on a SOR that can also be configured for
1735 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
1736 *
1737 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
1738 * the VBIOS scripts on at least one board I have only switch it off on
1739 * link 0, causing a blank display if the output has previously been
1740 * programmed for DisplayPort.
1741 */
1742static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001743nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001744{
1745 struct nouveau_bios *bios = nouveau_bios(priv);
1746 const int link = !(outp->sorconf.link & 1);
1747 const int or = ffs(outp->or) - 1;
1748 const u32 loff = (or * 0x800) + (link * 0x80);
1749 const u16 mask = (outp->sorconf.link << 6) | outp->or;
1750 u8 ver, hdr;
1751
1752 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
1753 nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
1754}
1755
1756static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001757nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001758{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001759 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001760 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001761 u32 conf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001762
Ben Skeggs415f12e2014-05-21 11:24:43 +10001763 outp = exec_clkcmp(priv, head, 1, pclk, &conf);
1764 if (!outp)
1765 return;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001766
Ben Skeggs415f12e2014-05-21 11:24:43 +10001767 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
1768 nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001769}
1770
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001771void
1772nv50_disp_intr_supervisor(struct work_struct *work)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001773{
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001774 struct nv50_disp_priv *priv =
1775 container_of(work, struct nv50_disp_priv, supervisor);
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001776 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001777 u32 super = nv_rd32(priv, 0x610030);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001778 int head;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001779
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001780 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001781
Ben Skeggs16d4c032013-02-20 18:56:33 +10001782 if (priv->super & 0x00000010) {
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001783 nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001784 for (head = 0; head < priv->head.nr; head++) {
1785 if (!(super & (0x00000020 << head)))
1786 continue;
1787 if (!(super & (0x00000080 << head)))
1788 continue;
1789 nv50_disp_intr_unk10_0(priv, head);
1790 }
1791 } else
1792 if (priv->super & 0x00000020) {
1793 for (head = 0; head < priv->head.nr; head++) {
1794 if (!(super & (0x00000080 << head)))
1795 continue;
1796 nv50_disp_intr_unk20_0(priv, head);
1797 }
1798 for (head = 0; head < priv->head.nr; head++) {
1799 if (!(super & (0x00000200 << head)))
1800 continue;
1801 nv50_disp_intr_unk20_1(priv, head);
1802 }
1803 for (head = 0; head < priv->head.nr; head++) {
1804 if (!(super & (0x00000080 << head)))
1805 continue;
1806 nv50_disp_intr_unk20_2(priv, head);
1807 }
1808 } else
1809 if (priv->super & 0x00000040) {
1810 for (head = 0; head < priv->head.nr; head++) {
1811 if (!(super & (0x00000080 << head)))
1812 continue;
1813 nv50_disp_intr_unk40_0(priv, head);
1814 }
1815 }
1816
1817 nv_wr32(priv, 0x610030, 0x80000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001818}
1819
Ben Skeggs70cabe42012-08-14 10:04:04 +10001820void
Ben Skeggsebb945a2012-07-20 08:17:34 +10001821nv50_disp_intr(struct nouveau_subdev *subdev)
1822{
1823 struct nv50_disp_priv *priv = (void *)subdev;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001824 u32 intr0 = nv_rd32(priv, 0x610020);
1825 u32 intr1 = nv_rd32(priv, 0x610024);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001826
Ben Skeggs117e16332014-02-21 11:06:40 +10001827 while (intr0 & 0x001f0000) {
1828 u32 chid = __ffs(intr0 & 0x001f0000) - 16;
1829 nv50_disp_intr_error(priv, chid);
1830 intr0 &= ~(0x00010000 << chid);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001831 }
1832
1833 if (intr1 & 0x00000004) {
Ben Skeggs79ca2772014-08-10 04:10:20 +10001834 nouveau_disp_vblank(&priv->base, 0);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001835 nv_wr32(priv, 0x610024, 0x00000004);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001836 intr1 &= ~0x00000004;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001837 }
1838
Ben Skeggs186ecad2012-11-09 12:09:48 +10001839 if (intr1 & 0x00000008) {
Ben Skeggs79ca2772014-08-10 04:10:20 +10001840 nouveau_disp_vblank(&priv->base, 1);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001841 nv_wr32(priv, 0x610024, 0x00000008);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001842 intr1 &= ~0x00000008;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001843 }
1844
Ben Skeggs186ecad2012-11-09 12:09:48 +10001845 if (intr1 & 0x00000070) {
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001846 priv->super = (intr1 & 0x00000070);
1847 schedule_work(&priv->supervisor);
1848 nv_wr32(priv, 0x610024, priv->super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001849 intr1 &= ~0x00000070;
1850 }
Ben Skeggsebb945a2012-07-20 08:17:34 +10001851}
1852
1853static int
1854nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
Ben Skeggs370c00f2012-08-14 14:11:49 +10001855 struct nouveau_oclass *oclass, void *data, u32 size,
1856 struct nouveau_object **pobject)
Ben Skeggsebb945a2012-07-20 08:17:34 +10001857{
1858 struct nv50_disp_priv *priv;
1859 int ret;
1860
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001861 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
Ben Skeggsebb945a2012-07-20 08:17:34 +10001862 "display", &priv);
1863 *pobject = nv_object(priv);
1864 if (ret)
1865 return ret;
1866
Ben Skeggs70cabe42012-08-14 10:04:04 +10001867 nv_engine(priv)->sclass = nv50_disp_base_oclass;
1868 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001869 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001870 INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001871 priv->sclass = nv50_disp_sclass;
1872 priv->head.nr = 2;
1873 priv->dac.nr = 3;
1874 priv->sor.nr = 2;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001875 priv->pior.nr = 3;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001876 priv->dac.power = nv50_dac_power;
Ben Skeggs7ebb38b2012-11-09 09:38:06 +10001877 priv->dac.sense = nv50_dac_sense;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001878 priv->sor.power = nv50_sor_power;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001879 priv->pior.power = nv50_pior_power;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001880 return 0;
1881}
1882
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001883struct nouveau_oclass *
Ben Skeggsb8407c92014-05-17 11:19:54 +10001884nv50_disp_outp_sclass[] = {
1885 &nv50_pior_dp_impl.base.base,
1886 NULL
1887};
1888
1889struct nouveau_oclass *
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001890nv50_disp_oclass = &(struct nv50_disp_impl) {
1891 .base.base.handle = NV_ENGINE(DISP, 0x50),
1892 .base.base.ofuncs = &(struct nouveau_ofuncs) {
Ben Skeggsebb945a2012-07-20 08:17:34 +10001893 .ctor = nv50_disp_ctor,
1894 .dtor = _nouveau_disp_dtor,
1895 .init = _nouveau_disp_init,
1896 .fini = _nouveau_disp_fini,
1897 },
Ben Skeggs79ca2772014-08-10 04:10:20 +10001898 .base.vblank = &nv50_disp_vblank_func,
Ben Skeggsb8407c92014-05-17 11:19:54 +10001899 .base.outp = nv50_disp_outp_sclass,
Ben Skeggsd67d92c2014-02-20 15:14:10 +10001900 .mthd.core = &nv50_disp_mast_mthd_chan,
1901 .mthd.base = &nv50_disp_sync_mthd_chan,
1902 .mthd.ovly = &nv50_disp_ovly_mthd_chan,
1903 .mthd.prev = 0x000004,
Ben Skeggs4952b4d2014-08-10 04:10:27 +10001904 .head.scanoutpos = nv50_disp_base_scanoutpos,
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001905}.base.base;