blob: 858386bdd4bd4739cdb87c0e884ca4f7f8d78697 [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
Ben Skeggsb76f1522014-08-10 04:10:28 +100085int
86nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
87{
88 struct nv50_disp_chan *chan = (void *)object;
89 *addr = nv_device_resource_start(nv_device(object), 0) +
90 0x640000 + (chan->chid * 0x1000);
91 *size = 0x001000;
92 return 0;
93}
94
Ben Skeggs370c00f2012-08-14 14:11:49 +100095u32
Ben Skeggs70cabe42012-08-14 10:04:04 +100096nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
97{
Ben Skeggs370c00f2012-08-14 14:11:49 +100098 struct nv50_disp_priv *priv = (void *)object->engine;
99 struct nv50_disp_chan *chan = (void *)object;
100 return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
101}
102
103void
104nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
105{
106 struct nv50_disp_priv *priv = (void *)object->engine;
107 struct nv50_disp_chan *chan = (void *)object;
108 nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
109}
110
111/*******************************************************************************
112 * EVO DMA channel base class
113 ******************************************************************************/
114
115static int
116nv50_disp_dmac_object_attach(struct nouveau_object *parent,
117 struct nouveau_object *object, u32 name)
118{
119 struct nv50_disp_base *base = (void *)parent->parent;
120 struct nv50_disp_chan *chan = (void *)parent;
121 u32 addr = nv_gpuobj(object)->node->offset;
122 u32 chid = chan->chid;
123 u32 data = (chid << 28) | (addr << 10) | chid;
124 return nouveau_ramht_insert(base->ramht, chid, name, data);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000125}
126
127static void
Ben Skeggs370c00f2012-08-14 14:11:49 +1000128nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
Ben Skeggs70cabe42012-08-14 10:04:04 +1000129{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000130 struct nv50_disp_base *base = (void *)parent->parent;
131 nouveau_ramht_remove(base->ramht, cookie);
132}
133
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000134static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000135nv50_disp_dmac_create_(struct nouveau_object *parent,
136 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000137 struct nouveau_oclass *oclass, u32 pushbuf, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000138 int length, void **pobject)
139{
140 struct nv50_disp_dmac *dmac;
141 int ret;
142
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000143 ret = nv50_disp_chan_create_(parent, engine, oclass, head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000144 length, pobject);
145 dmac = *pobject;
146 if (ret)
147 return ret;
148
149 dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
150 if (!dmac->pushdma)
151 return -ENOENT;
152
153 switch (nv_mclass(dmac->pushdma)) {
154 case 0x0002:
155 case 0x003d:
156 if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
157 return -EINVAL;
158
159 switch (dmac->pushdma->target) {
160 case NV_MEM_TARGET_VRAM:
161 dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
162 break;
Ben Skeggs944234d2012-10-30 10:03:38 +1000163 case NV_MEM_TARGET_PCI_NOSNOOP:
164 dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
165 break;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000166 default:
167 return -EINVAL;
168 }
169 break;
170 default:
171 return -EINVAL;
172 }
173
174 return 0;
175}
176
177void
178nv50_disp_dmac_dtor(struct nouveau_object *object)
179{
180 struct nv50_disp_dmac *dmac = (void *)object;
181 nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
182 nv50_disp_chan_destroy(&dmac->base);
183}
184
185static int
186nv50_disp_dmac_init(struct nouveau_object *object)
187{
188 struct nv50_disp_priv *priv = (void *)object->engine;
189 struct nv50_disp_dmac *dmac = (void *)object;
190 int chid = dmac->base.chid;
191 int ret;
192
193 ret = nv50_disp_chan_init(&dmac->base);
194 if (ret)
195 return ret;
196
197 /* enable error reporting */
198 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
199
200 /* initialise channel for dma command submission */
201 nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
202 nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
203 nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
204 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
205 nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
206 nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
207
208 /* wait for it to go inactive */
209 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
210 nv_error(dmac, "init timeout, 0x%08x\n",
211 nv_rd32(priv, 0x610200 + (chid * 0x10)));
212 return -EBUSY;
213 }
214
215 return 0;
216}
217
218static int
219nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
220{
221 struct nv50_disp_priv *priv = (void *)object->engine;
222 struct nv50_disp_dmac *dmac = (void *)object;
223 int chid = dmac->base.chid;
224
225 /* deactivate channel */
226 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
227 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
228 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
229 nv_error(dmac, "fini timeout, 0x%08x\n",
230 nv_rd32(priv, 0x610200 + (chid * 0x10)));
231 if (suspend)
232 return -EBUSY;
233 }
234
235 /* disable error reporting */
236 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
237
238 return nv50_disp_chan_fini(&dmac->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000239}
240
241/*******************************************************************************
242 * EVO master channel object
243 ******************************************************************************/
244
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000245static void
246nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
247 const struct nv50_disp_mthd_list *list, int inst)
248{
249 struct nouveau_object *disp = nv_object(priv);
250 int i;
251
252 for (i = 0; list->data[i].mthd; i++) {
253 if (list->data[i].addr) {
254 u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
255 u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
256 u32 mthd = list->data[i].mthd + (list->mthd * inst);
257 const char *name = list->data[i].name;
258 char mods[16];
259
260 if (prev != next)
261 snprintf(mods, sizeof(mods), "-> 0x%08x", next);
262 else
263 snprintf(mods, sizeof(mods), "%13c", ' ');
264
265 nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
266 mthd, prev, mods, name ? " // " : "",
267 name ? name : "");
268 }
269 }
270}
271
272void
273nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
274 const struct nv50_disp_mthd_chan *chan)
275{
276 struct nouveau_object *disp = nv_object(priv);
277 const struct nv50_disp_impl *impl = (void *)disp->oclass;
278 const struct nv50_disp_mthd_list *list;
279 int i, j;
280
281 if (debug > nv_subdev(priv)->debug)
282 return;
283
284 for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
285 u32 base = head * chan->addr;
286 for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
287 const char *cname = chan->name;
288 const char *sname = "";
289 char cname_[16], sname_[16];
290
291 if (chan->addr) {
292 snprintf(cname_, sizeof(cname_), "%s %d",
293 chan->name, head);
294 cname = cname_;
295 }
296
297 if (chan->data[i].nr > 1) {
298 snprintf(sname_, sizeof(sname_), " - %s %d",
299 chan->data[i].name, j);
300 sname = sname_;
301 }
302
303 nv_printk_(disp, debug, "%s%s:\n", cname, sname);
304 nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
305 list, j);
306 }
307 }
308}
309
310const struct nv50_disp_mthd_list
311nv50_disp_mast_mthd_base = {
312 .mthd = 0x0000,
313 .addr = 0x000000,
314 .data = {
315 { 0x0080, 0x000000 },
316 { 0x0084, 0x610bb8 },
317 { 0x0088, 0x610b9c },
318 { 0x008c, 0x000000 },
319 {}
320 }
321};
322
323static const struct nv50_disp_mthd_list
324nv50_disp_mast_mthd_dac = {
325 .mthd = 0x0080,
326 .addr = 0x000008,
327 .data = {
328 { 0x0400, 0x610b58 },
329 { 0x0404, 0x610bdc },
330 { 0x0420, 0x610828 },
331 {}
332 }
333};
334
335const struct nv50_disp_mthd_list
336nv50_disp_mast_mthd_sor = {
337 .mthd = 0x0040,
338 .addr = 0x000008,
339 .data = {
340 { 0x0600, 0x610b70 },
341 {}
342 }
343};
344
345const struct nv50_disp_mthd_list
346nv50_disp_mast_mthd_pior = {
347 .mthd = 0x0040,
348 .addr = 0x000008,
349 .data = {
350 { 0x0700, 0x610b80 },
351 {}
352 }
353};
354
355static const struct nv50_disp_mthd_list
356nv50_disp_mast_mthd_head = {
357 .mthd = 0x0400,
358 .addr = 0x000540,
359 .data = {
360 { 0x0800, 0x610ad8 },
361 { 0x0804, 0x610ad0 },
362 { 0x0808, 0x610a48 },
363 { 0x080c, 0x610a78 },
364 { 0x0810, 0x610ac0 },
365 { 0x0814, 0x610af8 },
366 { 0x0818, 0x610b00 },
367 { 0x081c, 0x610ae8 },
368 { 0x0820, 0x610af0 },
369 { 0x0824, 0x610b08 },
370 { 0x0828, 0x610b10 },
371 { 0x082c, 0x610a68 },
372 { 0x0830, 0x610a60 },
373 { 0x0834, 0x000000 },
374 { 0x0838, 0x610a40 },
375 { 0x0840, 0x610a24 },
376 { 0x0844, 0x610a2c },
377 { 0x0848, 0x610aa8 },
378 { 0x084c, 0x610ab0 },
379 { 0x0860, 0x610a84 },
380 { 0x0864, 0x610a90 },
381 { 0x0868, 0x610b18 },
382 { 0x086c, 0x610b20 },
383 { 0x0870, 0x610ac8 },
384 { 0x0874, 0x610a38 },
385 { 0x0880, 0x610a58 },
386 { 0x0884, 0x610a9c },
387 { 0x08a0, 0x610a70 },
388 { 0x08a4, 0x610a50 },
389 { 0x08a8, 0x610ae0 },
390 { 0x08c0, 0x610b28 },
391 { 0x08c4, 0x610b30 },
392 { 0x08c8, 0x610b40 },
393 { 0x08d4, 0x610b38 },
394 { 0x08d8, 0x610b48 },
395 { 0x08dc, 0x610b50 },
396 { 0x0900, 0x610a18 },
397 { 0x0904, 0x610ab8 },
398 {}
399 }
400};
401
402static const struct nv50_disp_mthd_chan
403nv50_disp_mast_mthd_chan = {
404 .name = "Core",
405 .addr = 0x000000,
406 .data = {
407 { "Global", 1, &nv50_disp_mast_mthd_base },
408 { "DAC", 3, &nv50_disp_mast_mthd_dac },
409 { "SOR", 2, &nv50_disp_mast_mthd_sor },
410 { "PIOR", 3, &nv50_disp_mast_mthd_pior },
411 { "HEAD", 2, &nv50_disp_mast_mthd_head },
412 {}
413 }
414};
415
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000416int
Ben Skeggs70cabe42012-08-14 10:04:04 +1000417nv50_disp_mast_ctor(struct nouveau_object *parent,
418 struct nouveau_object *engine,
419 struct nouveau_oclass *oclass, void *data, u32 size,
420 struct nouveau_object **pobject)
421{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000422 union {
423 struct nv50_disp_core_channel_dma_v0 v0;
424 } *args = data;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000425 struct nv50_disp_dmac *mast;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000426 int ret;
427
Ben Skeggs648d4df2014-08-10 04:10:27 +1000428 nv_ioctl(parent, "create disp core channel dma size %d\n", size);
429 if (nvif_unpack(args->v0, 0, 0, false)) {
430 nv_ioctl(parent, "create disp core channel dma vers %d "
431 "pushbuf %08x\n",
432 args->v0.version, args->v0.pushbuf);
433 } else
434 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000435
Ben Skeggs648d4df2014-08-10 04:10:27 +1000436 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000437 0, sizeof(*mast), (void **)&mast);
438 *pobject = nv_object(mast);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000439 if (ret)
440 return ret;
441
442 return 0;
443}
444
Ben Skeggs70cabe42012-08-14 10:04:04 +1000445static int
446nv50_disp_mast_init(struct nouveau_object *object)
447{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000448 struct nv50_disp_priv *priv = (void *)object->engine;
449 struct nv50_disp_dmac *mast = (void *)object;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000450 int ret;
451
Ben Skeggs370c00f2012-08-14 14:11:49 +1000452 ret = nv50_disp_chan_init(&mast->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000453 if (ret)
454 return ret;
455
Ben Skeggs370c00f2012-08-14 14:11:49 +1000456 /* enable error reporting */
457 nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
458
459 /* attempt to unstick channel from some unknown state */
460 if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
461 nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
462 if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
463 nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
464
465 /* initialise channel for dma command submission */
466 nv_wr32(priv, 0x610204, mast->push);
467 nv_wr32(priv, 0x610208, 0x00010000);
468 nv_wr32(priv, 0x61020c, 0x00000000);
469 nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
470 nv_wr32(priv, 0x640000, 0x00000000);
471 nv_wr32(priv, 0x610200, 0x01000013);
472
473 /* wait for it to go inactive */
474 if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
475 nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
476 return -EBUSY;
477 }
478
Ben Skeggs70cabe42012-08-14 10:04:04 +1000479 return 0;
480}
481
482static int
483nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
484{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000485 struct nv50_disp_priv *priv = (void *)object->engine;
486 struct nv50_disp_dmac *mast = (void *)object;
487
488 /* deactivate channel */
489 nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
490 nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
491 if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
492 nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
493 if (suspend)
494 return -EBUSY;
495 }
496
497 /* disable error reporting */
498 nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
499
500 return nv50_disp_chan_fini(&mast->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000501}
502
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000503struct nv50_disp_chan_impl
Ben Skeggs70cabe42012-08-14 10:04:04 +1000504nv50_disp_mast_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000505 .base.ctor = nv50_disp_mast_ctor,
506 .base.dtor = nv50_disp_dmac_dtor,
507 .base.init = nv50_disp_mast_init,
508 .base.fini = nv50_disp_mast_fini,
Ben Skeggsb76f1522014-08-10 04:10:28 +1000509 .base.map = nv50_disp_chan_map,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000510 .base.rd32 = nv50_disp_chan_rd32,
511 .base.wr32 = nv50_disp_chan_wr32,
512 .chid = 0,
513 .attach = nv50_disp_dmac_object_attach,
514 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000515};
516
517/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000518 * EVO sync channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000519 ******************************************************************************/
520
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000521static const struct nv50_disp_mthd_list
522nv50_disp_sync_mthd_base = {
523 .mthd = 0x0000,
524 .addr = 0x000000,
525 .data = {
526 { 0x0080, 0x000000 },
527 { 0x0084, 0x0008c4 },
528 { 0x0088, 0x0008d0 },
529 { 0x008c, 0x0008dc },
530 { 0x0090, 0x0008e4 },
531 { 0x0094, 0x610884 },
532 { 0x00a0, 0x6108a0 },
533 { 0x00a4, 0x610878 },
534 { 0x00c0, 0x61086c },
535 { 0x00e0, 0x610858 },
536 { 0x00e4, 0x610860 },
537 { 0x00e8, 0x6108ac },
538 { 0x00ec, 0x6108b4 },
539 { 0x0100, 0x610894 },
540 { 0x0110, 0x6108bc },
541 { 0x0114, 0x61088c },
542 {}
543 }
544};
545
546const struct nv50_disp_mthd_list
547nv50_disp_sync_mthd_image = {
548 .mthd = 0x0400,
549 .addr = 0x000000,
550 .data = {
551 { 0x0800, 0x6108f0 },
552 { 0x0804, 0x6108fc },
553 { 0x0808, 0x61090c },
554 { 0x080c, 0x610914 },
555 { 0x0810, 0x610904 },
556 {}
557 }
558};
559
560static const struct nv50_disp_mthd_chan
561nv50_disp_sync_mthd_chan = {
562 .name = "Base",
563 .addr = 0x000540,
564 .data = {
565 { "Global", 1, &nv50_disp_sync_mthd_base },
566 { "Image", 2, &nv50_disp_sync_mthd_image },
567 {}
568 }
569};
570
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000571int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000572nv50_disp_sync_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000573 struct nouveau_object *engine,
574 struct nouveau_oclass *oclass, void *data, u32 size,
575 struct nouveau_object **pobject)
576{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000577 union {
578 struct nv50_disp_base_channel_dma_v0 v0;
579 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000580 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000581 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000582 int ret;
583
Ben Skeggs648d4df2014-08-10 04:10:27 +1000584 nv_ioctl(parent, "create disp base channel dma size %d\n", size);
585 if (nvif_unpack(args->v0, 0, 0, false)) {
586 nv_ioctl(parent, "create disp base channel dma vers %d "
587 "pushbuf %08x head %d\n",
588 args->v0.version, args->v0.pushbuf, args->v0.head);
589 if (args->v0.head > priv->head.nr)
590 return -EINVAL;
591 } else
592 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000593
Ben Skeggs648d4df2014-08-10 04:10:27 +1000594 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
595 args->v0.head, sizeof(*dmac),
596 (void **)&dmac);
Ben Skeggs370c00f2012-08-14 14:11:49 +1000597 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000598 if (ret)
599 return ret;
600
601 return 0;
602}
603
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000604struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000605nv50_disp_sync_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000606 .base.ctor = nv50_disp_sync_ctor,
607 .base.dtor = nv50_disp_dmac_dtor,
608 .base.init = nv50_disp_dmac_init,
609 .base.fini = nv50_disp_dmac_fini,
Ben Skeggsb76f1522014-08-10 04:10:28 +1000610 .base.map = nv50_disp_chan_map,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000611 .base.rd32 = nv50_disp_chan_rd32,
612 .base.wr32 = nv50_disp_chan_wr32,
613 .chid = 1,
614 .attach = nv50_disp_dmac_object_attach,
615 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000616};
617
618/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000619 * EVO overlay channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000620 ******************************************************************************/
621
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000622const struct nv50_disp_mthd_list
623nv50_disp_ovly_mthd_base = {
624 .mthd = 0x0000,
625 .addr = 0x000000,
626 .data = {
627 { 0x0080, 0x000000 },
628 { 0x0084, 0x0009a0 },
629 { 0x0088, 0x0009c0 },
630 { 0x008c, 0x0009c8 },
631 { 0x0090, 0x6109b4 },
632 { 0x0094, 0x610970 },
633 { 0x00a0, 0x610998 },
634 { 0x00a4, 0x610964 },
635 { 0x00c0, 0x610958 },
636 { 0x00e0, 0x6109a8 },
637 { 0x00e4, 0x6109d0 },
638 { 0x00e8, 0x6109d8 },
639 { 0x0100, 0x61094c },
640 { 0x0104, 0x610984 },
641 { 0x0108, 0x61098c },
642 { 0x0800, 0x6109f8 },
643 { 0x0808, 0x610a08 },
644 { 0x080c, 0x610a10 },
645 { 0x0810, 0x610a00 },
646 {}
647 }
648};
649
650static const struct nv50_disp_mthd_chan
651nv50_disp_ovly_mthd_chan = {
652 .name = "Overlay",
653 .addr = 0x000540,
654 .data = {
655 { "Global", 1, &nv50_disp_ovly_mthd_base },
656 {}
657 }
658};
659
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000660int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000661nv50_disp_ovly_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000662 struct nouveau_object *engine,
663 struct nouveau_oclass *oclass, void *data, u32 size,
664 struct nouveau_object **pobject)
665{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000666 union {
667 struct nv50_disp_overlay_channel_dma_v0 v0;
668 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000669 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000670 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000671 int ret;
672
Ben Skeggs648d4df2014-08-10 04:10:27 +1000673 nv_ioctl(parent, "create disp overlay channel dma size %d\n", size);
674 if (nvif_unpack(args->v0, 0, 0, false)) {
675 nv_ioctl(parent, "create disp overlay channel dma vers %d "
676 "pushbuf %08x head %d\n",
677 args->v0.version, args->v0.pushbuf, args->v0.head);
678 if (args->v0.head > priv->head.nr)
679 return -EINVAL;
680 } else
681 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000682
Ben Skeggs648d4df2014-08-10 04:10:27 +1000683 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
684 args->v0.head, sizeof(*dmac),
685 (void **)&dmac);
Ben Skeggs370c00f2012-08-14 14:11:49 +1000686 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000687 if (ret)
688 return ret;
689
690 return 0;
691}
692
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000693struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000694nv50_disp_ovly_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000695 .base.ctor = nv50_disp_ovly_ctor,
696 .base.dtor = nv50_disp_dmac_dtor,
697 .base.init = nv50_disp_dmac_init,
698 .base.fini = nv50_disp_dmac_fini,
Ben Skeggsb76f1522014-08-10 04:10:28 +1000699 .base.map = nv50_disp_chan_map,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000700 .base.rd32 = nv50_disp_chan_rd32,
701 .base.wr32 = nv50_disp_chan_wr32,
702 .chid = 3,
703 .attach = nv50_disp_dmac_object_attach,
704 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000705};
706
707/*******************************************************************************
708 * EVO PIO channel base class
709 ******************************************************************************/
710
711static int
712nv50_disp_pioc_create_(struct nouveau_object *parent,
713 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000714 struct nouveau_oclass *oclass, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000715 int length, void **pobject)
716{
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000717 return nv50_disp_chan_create_(parent, engine, oclass, head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000718 length, pobject);
719}
720
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000721void
Ben Skeggs70cabe42012-08-14 10:04:04 +1000722nv50_disp_pioc_dtor(struct nouveau_object *object)
723{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000724 struct nv50_disp_pioc *pioc = (void *)object;
725 nv50_disp_chan_destroy(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000726}
727
728static int
729nv50_disp_pioc_init(struct nouveau_object *object)
730{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000731 struct nv50_disp_priv *priv = (void *)object->engine;
732 struct nv50_disp_pioc *pioc = (void *)object;
733 int chid = pioc->base.chid;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000734 int ret;
735
Ben Skeggs370c00f2012-08-14 14:11:49 +1000736 ret = nv50_disp_chan_init(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000737 if (ret)
738 return ret;
739
Ben Skeggs370c00f2012-08-14 14:11:49 +1000740 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
741 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
742 nv_error(pioc, "timeout0: 0x%08x\n",
743 nv_rd32(priv, 0x610200 + (chid * 0x10)));
744 return -EBUSY;
745 }
746
747 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
748 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
749 nv_error(pioc, "timeout1: 0x%08x\n",
750 nv_rd32(priv, 0x610200 + (chid * 0x10)));
751 return -EBUSY;
752 }
753
Ben Skeggs70cabe42012-08-14 10:04:04 +1000754 return 0;
755}
756
757static int
758nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
759{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000760 struct nv50_disp_priv *priv = (void *)object->engine;
761 struct nv50_disp_pioc *pioc = (void *)object;
762 int chid = pioc->base.chid;
763
764 nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
765 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
766 nv_error(pioc, "timeout: 0x%08x\n",
767 nv_rd32(priv, 0x610200 + (chid * 0x10)));
768 if (suspend)
769 return -EBUSY;
770 }
771
772 return nv50_disp_chan_fini(&pioc->base, suspend);
773}
774
775/*******************************************************************************
776 * EVO immediate overlay channel objects
777 ******************************************************************************/
778
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000779int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000780nv50_disp_oimm_ctor(struct nouveau_object *parent,
781 struct nouveau_object *engine,
782 struct nouveau_oclass *oclass, void *data, u32 size,
783 struct nouveau_object **pobject)
784{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000785 union {
786 struct nv50_disp_overlay_v0 v0;
787 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000788 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000789 struct nv50_disp_pioc *pioc;
790 int ret;
791
Ben Skeggs648d4df2014-08-10 04:10:27 +1000792 nv_ioctl(parent, "create disp overlay size %d\n", size);
793 if (nvif_unpack(args->v0, 0, 0, false)) {
794 nv_ioctl(parent, "create disp overlay vers %d head %d\n",
795 args->v0.version, args->v0.head);
796 if (args->v0.head > priv->head.nr)
797 return -EINVAL;
798 } else
799 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000800
Ben Skeggs648d4df2014-08-10 04:10:27 +1000801 ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000802 sizeof(*pioc), (void **)&pioc);
803 *pobject = nv_object(pioc);
804 if (ret)
805 return ret;
806
807 return 0;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000808}
809
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000810struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000811nv50_disp_oimm_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000812 .base.ctor = nv50_disp_oimm_ctor,
813 .base.dtor = nv50_disp_pioc_dtor,
814 .base.init = nv50_disp_pioc_init,
815 .base.fini = nv50_disp_pioc_fini,
Ben Skeggsb76f1522014-08-10 04:10:28 +1000816 .base.map = nv50_disp_chan_map,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000817 .base.rd32 = nv50_disp_chan_rd32,
818 .base.wr32 = nv50_disp_chan_wr32,
819 .chid = 5,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000820};
821
822/*******************************************************************************
823 * EVO cursor channel objects
824 ******************************************************************************/
825
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000826int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000827nv50_disp_curs_ctor(struct nouveau_object *parent,
828 struct nouveau_object *engine,
829 struct nouveau_oclass *oclass, void *data, u32 size,
830 struct nouveau_object **pobject)
831{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000832 union {
833 struct nv50_disp_cursor_v0 v0;
834 } *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000835 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000836 struct nv50_disp_pioc *pioc;
837 int ret;
838
Ben Skeggs648d4df2014-08-10 04:10:27 +1000839 nv_ioctl(parent, "create disp cursor size %d\n", size);
840 if (nvif_unpack(args->v0, 0, 0, false)) {
841 nv_ioctl(parent, "create disp cursor vers %d head %d\n",
842 args->v0.version, args->v0.head);
843 if (args->v0.head > priv->head.nr)
844 return -EINVAL;
845 } else
846 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000847
Ben Skeggs648d4df2014-08-10 04:10:27 +1000848 ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000849 sizeof(*pioc), (void **)&pioc);
850 *pobject = nv_object(pioc);
851 if (ret)
852 return ret;
853
854 return 0;
855}
856
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000857struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000858nv50_disp_curs_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000859 .base.ctor = nv50_disp_curs_ctor,
860 .base.dtor = nv50_disp_pioc_dtor,
861 .base.init = nv50_disp_pioc_init,
862 .base.fini = nv50_disp_pioc_fini,
Ben Skeggsb76f1522014-08-10 04:10:28 +1000863 .base.map = nv50_disp_chan_map,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000864 .base.rd32 = nv50_disp_chan_rd32,
865 .base.wr32 = nv50_disp_chan_wr32,
866 .chid = 7,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000867};
868
869/*******************************************************************************
870 * Base display object
871 ******************************************************************************/
872
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000873int
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000874nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000875{
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000876 const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
877 const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
878 const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
879 union {
880 struct nv04_disp_scanoutpos_v0 v0;
881 } *args = data;
882 int ret;
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000883
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000884 nv_ioctl(object, "disp scanoutpos size %d\n", size);
885 if (nvif_unpack(args->v0, 0, 0, false)) {
886 nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
887 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
888 args->v0.hblanke = (blanke & 0x0000ffff);
889 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
890 args->v0.hblanks = (blanks & 0x0000ffff);
891 args->v0.vtotal = ( total & 0xffff0000) >> 16;
892 args->v0.htotal = ( total & 0x0000ffff);
893 args->v0.time[0] = ktime_to_ns(ktime_get());
894 args->v0.vline = /* vline read locks hline */
895 nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
896 args->v0.time[1] = ktime_to_ns(ktime_get());
897 args->v0.hline =
898 nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
899 } else
900 return ret;
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000901
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000902 return 0;
903}
904
Ben Skeggs79ca2772014-08-10 04:10:20 +1000905int
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000906nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
907 void *data, u32 size)
908{
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000909 const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000910 union {
911 struct nv50_disp_mthd_v0 v0;
912 struct nv50_disp_mthd_v1 v1;
913 } *args = data;
914 struct nv50_disp_priv *priv = (void *)object->engine;
915 struct nvkm_output *outp = NULL;
916 struct nvkm_output *temp;
917 u16 type, mask = 0;
918 int head, ret;
919
920 if (mthd != NV50_DISP_MTHD)
921 return -EINVAL;
922
923 nv_ioctl(object, "disp mthd size %d\n", size);
924 if (nvif_unpack(args->v0, 0, 0, true)) {
925 nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
926 args->v0.version, args->v0.method, args->v0.head);
927 mthd = args->v0.method;
928 head = args->v0.head;
929 } else
930 if (nvif_unpack(args->v1, 1, 1, true)) {
931 nv_ioctl(object, "disp mthd vers %d mthd %02x "
932 "type %04x mask %04x\n",
933 args->v1.version, args->v1.method,
934 args->v1.hasht, args->v1.hashm);
935 mthd = args->v1.method;
936 type = args->v1.hasht;
937 mask = args->v1.hashm;
938 head = ffs((mask >> 8) & 0x0f) - 1;
939 } else
940 return ret;
941
942 if (head < 0 || head >= priv->head.nr)
943 return -ENXIO;
944
945 if (mask) {
946 list_for_each_entry(temp, &priv->base.outp, head) {
947 if ((temp->info.hasht == type) &&
948 (temp->info.hashm & mask) == mask) {
949 outp = temp;
950 break;
951 }
952 }
953 if (outp == NULL)
954 return -ENXIO;
955 }
956
957 switch (mthd) {
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000958 case NV50_DISP_SCANOUTPOS:
959 return impl->head.scanoutpos(object, priv, data, size, head);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000960 default:
961 break;
962 }
963
964 switch (mthd * !!outp) {
965 case NV50_DISP_MTHD_V1_DAC_PWR:
966 return priv->dac.power(object, priv, data, size, head, outp);
Ben Skeggsc4abd312014-08-10 04:10:26 +1000967 case NV50_DISP_MTHD_V1_DAC_LOAD:
968 return priv->dac.sense(object, priv, data, size, head, outp);
Ben Skeggsd55b4af2014-08-10 04:10:26 +1000969 case NV50_DISP_MTHD_V1_SOR_PWR:
970 return priv->sor.power(object, priv, data, size, head, outp);
Ben Skeggs120b0c32014-08-10 04:10:26 +1000971 case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
972 if (!priv->sor.hda_eld)
973 return -ENODEV;
974 return priv->sor.hda_eld(object, priv, data, size, head, outp);
Ben Skeggse00f2232014-08-10 04:10:26 +1000975 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
976 if (!priv->sor.hdmi)
977 return -ENODEV;
978 return priv->sor.hdmi(object, priv, data, size, head, outp);
Ben Skeggsa3761fa2014-08-10 04:10:27 +1000979 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
980 union {
981 struct nv50_disp_sor_lvds_script_v0 v0;
982 } *args = data;
983 nv_ioctl(object, "disp sor lvds script size %d\n", size);
984 if (nvif_unpack(args->v0, 0, 0, false)) {
985 nv_ioctl(object, "disp sor lvds script "
986 "vers %d name %04x\n",
987 args->v0.version, args->v0.script);
988 priv->sor.lvdsconf = args->v0.script;
989 return 0;
990 } else
991 return ret;
992 }
993 break;
Ben Skeggsc02ed2b2014-08-10 04:10:27 +1000994 case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
995 struct nvkm_output_dp *outpdp = (void *)outp;
996 union {
997 struct nv50_disp_sor_dp_pwr_v0 v0;
998 } *args = data;
999 nv_ioctl(object, "disp sor dp pwr size %d\n", size);
1000 if (nvif_unpack(args->v0, 0, 0, false)) {
1001 nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
1002 args->v0.version, args->v0.state);
1003 if (args->v0.state == 0) {
1004 nvkm_notify_put(&outpdp->irq);
1005 ((struct nvkm_output_dp_impl *)nv_oclass(outp))
1006 ->lnk_pwr(outpdp, 0);
1007 atomic_set(&outpdp->lt.done, 0);
1008 return 0;
1009 } else
1010 if (args->v0.state != 0) {
1011 nvkm_output_dp_train(&outpdp->base, 0, true);
1012 return 0;
1013 }
1014 } else
1015 return ret;
1016 }
1017 break;
Ben Skeggs67cb49c2014-08-10 04:10:27 +10001018 case NV50_DISP_MTHD_V1_PIOR_PWR:
1019 if (!priv->pior.power)
1020 return -ENODEV;
1021 return priv->pior.power(object, priv, data, size, head, outp);
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001022 default:
1023 break;
1024 }
1025
1026 return -EINVAL;
1027}
1028
1029int
Ben Skeggs70cabe42012-08-14 10:04:04 +10001030nv50_disp_base_ctor(struct nouveau_object *parent,
1031 struct nouveau_object *engine,
1032 struct nouveau_oclass *oclass, void *data, u32 size,
1033 struct nouveau_object **pobject)
1034{
1035 struct nv50_disp_priv *priv = (void *)engine;
1036 struct nv50_disp_base *base;
1037 int ret;
1038
1039 ret = nouveau_parent_create(parent, engine, oclass, 0,
1040 priv->sclass, 0, &base);
1041 *pobject = nv_object(base);
1042 if (ret)
1043 return ret;
1044
Ben Skeggs2ecda482013-04-24 18:04:22 +10001045 return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
1046 &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001047}
1048
Ben Skeggs79ca2772014-08-10 04:10:20 +10001049void
Ben Skeggs70cabe42012-08-14 10:04:04 +10001050nv50_disp_base_dtor(struct nouveau_object *object)
1051{
1052 struct nv50_disp_base *base = (void *)object;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001053 nouveau_ramht_ref(NULL, &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001054 nouveau_parent_destroy(&base->base);
1055}
1056
1057static int
1058nv50_disp_base_init(struct nouveau_object *object)
1059{
Ben Skeggsab772142012-08-14 11:29:57 +10001060 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001061 struct nv50_disp_base *base = (void *)object;
Ben Skeggsab772142012-08-14 11:29:57 +10001062 int ret, i;
1063 u32 tmp;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001064
1065 ret = nouveau_parent_init(&base->base);
1066 if (ret)
1067 return ret;
1068
Ben Skeggsab772142012-08-14 11:29:57 +10001069 /* The below segments of code copying values from one register to
1070 * another appear to inform EVO of the display capabilities or
1071 * something similar. NFI what the 0x614004 caps are for..
1072 */
1073 tmp = nv_rd32(priv, 0x614004);
1074 nv_wr32(priv, 0x610184, tmp);
1075
1076 /* ... CRTC caps */
1077 for (i = 0; i < priv->head.nr; i++) {
1078 tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
1079 nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
1080 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
1081 nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
1082 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
1083 nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
1084 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
1085 nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
1086 }
1087
1088 /* ... DAC caps */
1089 for (i = 0; i < priv->dac.nr; i++) {
1090 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
1091 nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
1092 }
1093
1094 /* ... SOR caps */
1095 for (i = 0; i < priv->sor.nr; i++) {
1096 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
1097 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
1098 }
1099
Ben Skeggs476e84e2013-02-11 09:24:23 +10001100 /* ... PIOR caps */
Emil Velikovb969fa52013-07-30 01:01:10 +01001101 for (i = 0; i < priv->pior.nr; i++) {
Ben Skeggsab772142012-08-14 11:29:57 +10001102 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
1103 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
1104 }
1105
Ben Skeggs446b05a2012-08-14 12:50:14 +10001106 /* steal display away from vbios, or something like that */
1107 if (nv_rd32(priv, 0x610024) & 0x00000100) {
1108 nv_wr32(priv, 0x610024, 0x00000100);
1109 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
1110 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
1111 nv_error(priv, "timeout acquiring display\n");
1112 return -EBUSY;
1113 }
1114 }
1115
1116 /* point at display engine memory area (hash table, objects) */
Ben Skeggs370c00f2012-08-14 14:11:49 +10001117 nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
Ben Skeggs446b05a2012-08-14 12:50:14 +10001118
1119 /* enable supervisor interrupts, disable everything else */
Ben Skeggs370c00f2012-08-14 14:11:49 +10001120 nv_wr32(priv, 0x61002c, 0x00000370);
1121 nv_wr32(priv, 0x610028, 0x00000000);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001122 return 0;
1123}
1124
1125static int
1126nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
1127{
Ben Skeggs446b05a2012-08-14 12:50:14 +10001128 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001129 struct nv50_disp_base *base = (void *)object;
Ben Skeggs446b05a2012-08-14 12:50:14 +10001130
1131 /* disable all interrupts */
1132 nv_wr32(priv, 0x610024, 0x00000000);
1133 nv_wr32(priv, 0x610020, 0x00000000);
1134
Ben Skeggs70cabe42012-08-14 10:04:04 +10001135 return nouveau_parent_fini(&base->base, suspend);
1136}
1137
1138struct nouveau_ofuncs
1139nv50_disp_base_ofuncs = {
1140 .ctor = nv50_disp_base_ctor,
1141 .dtor = nv50_disp_base_dtor,
1142 .init = nv50_disp_base_init,
1143 .fini = nv50_disp_base_fini,
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001144 .mthd = nv50_disp_base_mthd,
Ben Skeggs70cabe42012-08-14 10:04:04 +10001145};
1146
1147static struct nouveau_oclass
1148nv50_disp_base_oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001149 { NV50_DISP, &nv50_disp_base_ofuncs },
Ben Skeggs370c00f2012-08-14 14:11:49 +10001150 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +10001151};
1152
1153static struct nouveau_oclass
1154nv50_disp_sclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001155 { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
1156 { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
1157 { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
1158 { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
1159 { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
Ben Skeggs70cabe42012-08-14 10:04:04 +10001160 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +10001161};
1162
Ben Skeggs70cabe42012-08-14 10:04:04 +10001163/*******************************************************************************
1164 * Display context, tracks instmem allocation and prevents more than one
1165 * client using the display hardware at any time.
1166 ******************************************************************************/
1167
1168static int
1169nv50_disp_data_ctor(struct nouveau_object *parent,
1170 struct nouveau_object *engine,
1171 struct nouveau_oclass *oclass, void *data, u32 size,
1172 struct nouveau_object **pobject)
1173{
Ben Skeggs370c00f2012-08-14 14:11:49 +10001174 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001175 struct nouveau_engctx *ectx;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001176 int ret = -EBUSY;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001177
Ben Skeggs370c00f2012-08-14 14:11:49 +10001178 /* no context needed for channel objects... */
Ben Skeggs586491e2014-08-10 04:10:24 +10001179 if (nv_mclass(parent) != NV_DEVICE) {
Ben Skeggs370c00f2012-08-14 14:11:49 +10001180 atomic_inc(&parent->refcount);
1181 *pobject = parent;
Ben Skeggs43e6e512013-04-26 00:12:59 +10001182 return 1;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001183 }
Ben Skeggs70cabe42012-08-14 10:04:04 +10001184
Ben Skeggs370c00f2012-08-14 14:11:49 +10001185 /* allocate display hardware to client */
1186 mutex_lock(&nv_subdev(priv)->mutex);
1187 if (list_empty(&nv_engine(priv)->contexts)) {
1188 ret = nouveau_engctx_create(parent, engine, oclass, NULL,
1189 0x10000, 0x10000,
1190 NVOBJ_FLAG_HEAP, &ectx);
1191 *pobject = nv_object(ectx);
1192 }
1193 mutex_unlock(&nv_subdev(priv)->mutex);
1194 return ret;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001195}
1196
1197struct nouveau_oclass
1198nv50_disp_cclass = {
1199 .handle = NV_ENGCTX(DISP, 0x50),
1200 .ofuncs = &(struct nouveau_ofuncs) {
1201 .ctor = nv50_disp_data_ctor,
1202 .dtor = _nouveau_engctx_dtor,
1203 .init = _nouveau_engctx_init,
1204 .fini = _nouveau_engctx_fini,
1205 .rd32 = _nouveau_engctx_rd32,
1206 .wr32 = _nouveau_engctx_wr32,
1207 },
1208};
1209
1210/*******************************************************************************
1211 * Display engine implementation
1212 ******************************************************************************/
1213
Ben Skeggs79ca2772014-08-10 04:10:20 +10001214static void
1215nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
1216{
1217 struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
1218 nv_mask(disp, 0x61002c, (4 << head), 0);
1219}
1220
1221static void
1222nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
1223{
1224 struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
1225 nv_mask(disp, 0x61002c, (4 << head), (4 << head));
1226}
1227
1228const struct nvkm_event_func
1229nv50_disp_vblank_func = {
1230 .ctor = nouveau_disp_vblank_ctor,
1231 .init = nv50_disp_vblank_init,
1232 .fini = nv50_disp_vblank_fini,
1233};
1234
Ben Skeggs117e16332014-02-21 11:06:40 +10001235static const struct nouveau_enum
1236nv50_disp_intr_error_type[] = {
1237 { 3, "ILLEGAL_MTHD" },
1238 { 4, "INVALID_VALUE" },
1239 { 5, "INVALID_STATE" },
1240 { 7, "INVALID_HANDLE" },
1241 {}
1242};
1243
1244static const struct nouveau_enum
1245nv50_disp_intr_error_code[] = {
1246 { 0x00, "" },
1247 {}
1248};
1249
Ben Skeggsebb945a2012-07-20 08:17:34 +10001250static void
Ben Skeggs117e16332014-02-21 11:06:40 +10001251nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001252{
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001253 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs117e16332014-02-21 11:06:40 +10001254 u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
1255 u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
1256 u32 code = (addr & 0x00ff0000) >> 16;
1257 u32 type = (addr & 0x00007000) >> 12;
1258 u32 mthd = (addr & 0x00000ffc);
1259 const struct nouveau_enum *ec, *et;
1260 char ecunk[6], etunk[6];
Ben Skeggs186ecad2012-11-09 12:09:48 +10001261
Ben Skeggs117e16332014-02-21 11:06:40 +10001262 et = nouveau_enum_find(nv50_disp_intr_error_type, type);
1263 if (!et)
1264 snprintf(etunk, sizeof(etunk), "UNK%02X", type);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001265
Ben Skeggs117e16332014-02-21 11:06:40 +10001266 ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
1267 if (!ec)
1268 snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001269
Ben Skeggs117e16332014-02-21 11:06:40 +10001270 nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
1271 et ? et->name : etunk, ec ? ec->name : ecunk,
1272 chid, mthd, data);
1273
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001274 if (chid == 0) {
1275 switch (mthd) {
1276 case 0x0080:
1277 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
1278 impl->mthd.core);
1279 break;
1280 default:
1281 break;
1282 }
1283 } else
1284 if (chid <= 2) {
1285 switch (mthd) {
1286 case 0x0080:
1287 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
1288 impl->mthd.base);
1289 break;
1290 default:
1291 break;
1292 }
1293 } else
1294 if (chid <= 4) {
1295 switch (mthd) {
1296 case 0x0080:
1297 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
1298 impl->mthd.ovly);
1299 break;
1300 default:
1301 break;
1302 }
1303 }
1304
Ben Skeggs117e16332014-02-21 11:06:40 +10001305 nv_wr32(priv, 0x610020, 0x00010000 << chid);
1306 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001307}
1308
Ben Skeggs415f12e2014-05-21 11:24:43 +10001309static struct nvkm_output *
1310exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
1311 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001312 struct nvbios_outp *info)
1313{
1314 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001315 struct nvkm_output *outp;
1316 u16 mask, type;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001317
Ben Skeggs415f12e2014-05-21 11:24:43 +10001318 if (or < 4) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001319 type = DCB_OUTPUT_ANALOG;
1320 mask = 0;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001321 } else
Ben Skeggs415f12e2014-05-21 11:24:43 +10001322 if (or < 8) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001323 switch (ctrl & 0x00000f00) {
1324 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
1325 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
1326 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
1327 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
1328 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
1329 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
1330 default:
1331 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001332 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001333 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001334 or -= 4;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001335 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001336 or = or - 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001337 type = 0x0010;
1338 mask = 0;
1339 switch (ctrl & 0x00000f00) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001340 case 0x00000000: type |= priv->pior.type[or]; break;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001341 default:
1342 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001343 return NULL;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001344 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001345 }
1346
1347 mask = 0x00c0 & (mask << 6);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001348 mask |= 0x0001 << or;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001349 mask |= 0x0100 << head;
1350
Ben Skeggs415f12e2014-05-21 11:24:43 +10001351 list_for_each_entry(outp, &priv->base.outp, head) {
1352 if ((outp->info.hasht & 0xff) == type &&
1353 (outp->info.hashm & mask) == mask) {
1354 *data = nvbios_outp_match(bios, outp->info.hasht,
1355 outp->info.hashm,
1356 ver, hdr, cnt, len, info);
1357 if (!*data)
1358 return NULL;
1359 return outp;
1360 }
1361 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001362
Ben Skeggs415f12e2014-05-21 11:24:43 +10001363 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001364}
1365
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001366static struct nvkm_output *
Ben Skeggs186ecad2012-11-09 12:09:48 +10001367exec_script(struct nv50_disp_priv *priv, int head, int id)
1368{
1369 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001370 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001371 struct nvbios_outp info;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001372 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001373 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001374 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001375 int i;
1376
Ben Skeggs476e84e2013-02-11 09:24:23 +10001377 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001378 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001379 ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
1380
Ben Skeggs476e84e2013-02-11 09:24:23 +10001381 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001382 if (!(ctrl & (1 << head))) {
1383 if (nv_device(priv)->chipset < 0x90 ||
1384 nv_device(priv)->chipset == 0x92 ||
1385 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001386 reg = 0x610b74;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001387 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001388 reg = 0x610798;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001389 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001390 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1391 ctrl = nv_rd32(priv, reg + (i * 8));
1392 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001393 }
1394
Ben Skeggs476e84e2013-02-11 09:24:23 +10001395 /* PIOR */
1396 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001397 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001398 ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
1399 i += 8;
1400 }
1401
Ben Skeggs186ecad2012-11-09 12:09:48 +10001402 if (!(ctrl & (1 << head)))
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001403 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001404 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001405
Ben Skeggs415f12e2014-05-21 11:24:43 +10001406 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
1407 if (outp) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001408 struct nvbios_init init = {
1409 .subdev = nv_subdev(priv),
1410 .bios = bios,
1411 .offset = info.script[id],
Ben Skeggs415f12e2014-05-21 11:24:43 +10001412 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001413 .crtc = head,
1414 .execute = 1,
1415 };
1416
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001417 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001418 }
1419
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001420 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001421}
1422
Ben Skeggs415f12e2014-05-21 11:24:43 +10001423static struct nvkm_output *
1424exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001425{
1426 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001427 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001428 struct nvbios_outp info1;
1429 struct nvbios_ocfg info2;
1430 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001431 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001432 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001433 int i;
1434
Ben Skeggs476e84e2013-02-11 09:24:23 +10001435 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001436 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001437 ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
1438
Ben Skeggs476e84e2013-02-11 09:24:23 +10001439 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001440 if (!(ctrl & (1 << head))) {
1441 if (nv_device(priv)->chipset < 0x90 ||
1442 nv_device(priv)->chipset == 0x92 ||
1443 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001444 reg = 0x610b70;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001445 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001446 reg = 0x610794;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001447 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001448 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1449 ctrl = nv_rd32(priv, reg + (i * 8));
1450 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001451 }
1452
Ben Skeggs476e84e2013-02-11 09:24:23 +10001453 /* PIOR */
1454 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001455 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001456 ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
1457 i += 8;
1458 }
1459
Ben Skeggs186ecad2012-11-09 12:09:48 +10001460 if (!(ctrl & (1 << head)))
Ben Skeggs415f12e2014-05-21 11:24:43 +10001461 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001462 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001463
Ben Skeggs415f12e2014-05-21 11:24:43 +10001464 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
Ben Skeggsba5e01b2014-06-17 09:39:18 +10001465 if (!outp)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001466 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001467
Ben Skeggs415f12e2014-05-21 11:24:43 +10001468 if (outp->info.location == 0) {
1469 switch (outp->info.type) {
Ben Skeggs476e84e2013-02-11 09:24:23 +10001470 case DCB_OUTPUT_TMDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001471 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001472 if (pclk >= 165000)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001473 *conf |= 0x0100;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001474 break;
1475 case DCB_OUTPUT_LVDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001476 *conf = priv->sor.lvdsconf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001477 break;
1478 case DCB_OUTPUT_DP:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001479 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001480 break;
1481 case DCB_OUTPUT_ANALOG:
1482 default:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001483 *conf = 0x00ff;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001484 break;
1485 }
1486 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001487 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001488 pclk = pclk / 2;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001489 }
1490
Ben Skeggs415f12e2014-05-21 11:24:43 +10001491 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001492 if (data && id < 0xff) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001493 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1494 if (data) {
1495 struct nvbios_init init = {
1496 .subdev = nv_subdev(priv),
1497 .bios = bios,
1498 .offset = data,
Ben Skeggs415f12e2014-05-21 11:24:43 +10001499 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001500 .crtc = head,
1501 .execute = 1,
1502 };
1503
Ben Skeggs46c13c12013-02-16 13:49:21 +10001504 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001505 }
1506 }
1507
Ben Skeggs415f12e2014-05-21 11:24:43 +10001508 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001509}
1510
1511static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001512nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001513{
Ben Skeggs16d4c032013-02-20 18:56:33 +10001514 exec_script(priv, head, 1);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001515}
1516
1517static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001518nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
1519{
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001520 struct nvkm_output *outp = exec_script(priv, head, 2);
1521
1522 /* the binary driver does this outside of the supervisor handling
1523 * (after the third supervisor from a detach). we (currently?)
1524 * allow both detach/attach to happen in the same set of
1525 * supervisor interrupts, so it would make sense to execute this
1526 * (full power down?) script after all the detach phases of the
1527 * supervisor handling. like with training if needed from the
1528 * second supervisor, nvidia doesn't do this, so who knows if it's
1529 * entirely safe, but it does appear to work..
1530 *
1531 * without this script being run, on some configurations i've
1532 * seen, switching from DP to TMDS on a DP connector may result
1533 * in a blank screen (SOR_PWR off/on can restore it)
1534 */
1535 if (outp && outp->info.type == DCB_OUTPUT_DP) {
1536 struct nvkm_output_dp *outpdp = (void *)outp;
1537 struct nvbios_init init = {
1538 .subdev = nv_subdev(priv),
1539 .bios = nouveau_bios(priv),
1540 .outp = &outp->info,
1541 .crtc = head,
1542 .offset = outpdp->info.script[4],
1543 .execute = 1,
1544 };
1545
1546 nvbios_exec(&init);
1547 atomic_set(&outpdp->lt.done, 0);
1548 }
Ben Skeggs16d4c032013-02-20 18:56:33 +10001549}
1550
1551static void
1552nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
1553{
Ben Skeggs88524bc2013-03-05 10:53:54 +10001554 struct nouveau_devinit *devinit = nouveau_devinit(priv);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001555 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1556 if (pclk)
Ben Skeggs88524bc2013-03-05 10:53:54 +10001557 devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001558}
1559
1560static void
1561nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
1562 struct dcb_output *outp, u32 pclk)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001563{
1564 const int link = !(outp->sorconf.link & 1);
1565 const int or = ffs(outp->or) - 1;
1566 const u32 soff = ( or * 0x800);
1567 const u32 loff = (link * 0x080) + soff;
1568 const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
Ben Skeggs186ecad2012-11-09 12:09:48 +10001569 const u32 symbol = 100000;
1570 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
1571 u32 clksor = nv_rd32(priv, 0x614300 + soff);
1572 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
1573 int TU, VTUi, VTUf, VTUa;
1574 u64 link_data_rate, link_ratio, unk;
1575 u32 best_diff = 64 * symbol;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001576 u32 link_nr, link_bw, bits, r;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001577
1578 /* calculate packed data rate for each lane */
1579 if (dpctrl > 0x00030000) link_nr = 4;
1580 else if (dpctrl > 0x00010000) link_nr = 2;
1581 else link_nr = 1;
1582
1583 if (clksor & 0x000c0000)
1584 link_bw = 270000;
1585 else
1586 link_bw = 162000;
1587
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001588 if ((ctrl & 0xf0000) == 0x60000) bits = 30;
1589 else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
1590 else bits = 18;
1591
Ben Skeggs186ecad2012-11-09 12:09:48 +10001592 link_data_rate = (pclk * bits / 8) / link_nr;
1593
1594 /* calculate ratio of packed data rate to link symbol rate */
1595 link_ratio = link_data_rate * symbol;
1596 r = do_div(link_ratio, link_bw);
1597
1598 for (TU = 64; TU >= 32; TU--) {
1599 /* calculate average number of valid symbols in each TU */
1600 u32 tu_valid = link_ratio * TU;
1601 u32 calc, diff;
1602
1603 /* find a hw representation for the fraction.. */
1604 VTUi = tu_valid / symbol;
1605 calc = VTUi * symbol;
1606 diff = tu_valid - calc;
1607 if (diff) {
1608 if (diff >= (symbol / 2)) {
1609 VTUf = symbol / (symbol - diff);
1610 if (symbol - (VTUf * diff))
1611 VTUf++;
1612
1613 if (VTUf <= 15) {
1614 VTUa = 1;
1615 calc += symbol - (symbol / VTUf);
1616 } else {
1617 VTUa = 0;
1618 VTUf = 1;
1619 calc += symbol;
1620 }
1621 } else {
1622 VTUa = 0;
1623 VTUf = min((int)(symbol / diff), 15);
1624 calc += symbol / VTUf;
1625 }
1626
1627 diff = calc - tu_valid;
1628 } else {
1629 /* no remainder, but the hw doesn't like the fractional
1630 * part to be zero. decrement the integer part and
1631 * have the fraction add a whole symbol back
1632 */
1633 VTUa = 0;
1634 VTUf = 1;
1635 VTUi--;
1636 }
1637
1638 if (diff < best_diff) {
1639 best_diff = diff;
1640 bestTU = TU;
1641 bestVTUa = VTUa;
1642 bestVTUf = VTUf;
1643 bestVTUi = VTUi;
1644 if (diff == 0)
1645 break;
1646 }
1647 }
1648
1649 if (!bestTU) {
1650 nv_error(priv, "unable to find suitable dp config\n");
1651 return;
1652 }
1653
1654 /* XXX close to vbios numbers, but not right */
1655 unk = (symbol - link_ratio) * bestTU;
1656 unk *= link_ratio;
1657 r = do_div(unk, symbol);
1658 r = do_div(unk, symbol);
1659 unk += 6;
1660
1661 nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
1662 nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
1663 bestVTUf << 16 |
1664 bestVTUi << 8 | unk);
1665}
1666
1667static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001668nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001669{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001670 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001671 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1672 u32 hval, hreg = 0x614200 + (head * 0x800);
1673 u32 oval, oreg;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001674 u32 mask, conf;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001675
Ben Skeggs415f12e2014-05-21 11:24:43 +10001676 outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
1677 if (!outp)
1678 return;
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001679
Ben Skeggs55f083c2014-05-20 10:18:03 +10001680 /* we allow both encoder attach and detach operations to occur
1681 * within a single supervisor (ie. modeset) sequence. the
1682 * encoder detach scripts quite often switch off power to the
1683 * lanes, which requires the link to be re-trained.
1684 *
1685 * this is not generally an issue as the sink "must" (heh)
1686 * signal an irq when it's lost sync so the driver can
1687 * re-train.
1688 *
1689 * however, on some boards, if one does not configure at least
1690 * the gpu side of the link *before* attaching, then various
1691 * things can go horribly wrong (PDISP disappearing from mmio,
1692 * third supervisor never happens, etc).
1693 *
1694 * the solution is simply to retrain here, if necessary. last
1695 * i checked, the binary driver userspace does not appear to
1696 * trigger this situation (it forces an UPDATE between steps).
1697 */
Ben Skeggsb17932c2014-05-27 15:00:36 +10001698 if (outp->info.type == DCB_OUTPUT_DP) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001699 u32 soff = (ffs(outp->info.or) - 1) * 0x08;
Ben Skeggsb17932c2014-05-27 15:00:36 +10001700 u32 ctrl, datarate;
1701
1702 if (outp->info.location == 0) {
1703 ctrl = nv_rd32(priv, 0x610794 + soff);
1704 soff = 1;
1705 } else {
1706 ctrl = nv_rd32(priv, 0x610b80 + soff);
1707 soff = 2;
1708 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001709
1710 switch ((ctrl & 0x000f0000) >> 16) {
Ben Skeggs0713b452014-07-01 10:54:52 +10001711 case 6: datarate = pclk * 30; break;
1712 case 5: datarate = pclk * 24; break;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001713 case 2:
1714 default:
Ben Skeggs0713b452014-07-01 10:54:52 +10001715 datarate = pclk * 18;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001716 break;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001717 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001718
Ben Skeggs55f083c2014-05-20 10:18:03 +10001719 if (nvkm_output_dp_train(outp, datarate / soff, true))
1720 ERR("link not trained before attach\n");
Ben Skeggs16d4c032013-02-20 18:56:33 +10001721 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001722
1723 exec_clkcmp(priv, head, 0, pclk, &conf);
1724
1725 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
1726 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
1727 oval = 0x00000000;
1728 hval = 0x00000000;
1729 mask = 0xffffffff;
1730 } else
1731 if (!outp->info.location) {
1732 if (outp->info.type == DCB_OUTPUT_DP)
1733 nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
1734 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
1735 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1736 hval = 0x00000000;
1737 mask = 0x00000707;
1738 } else {
1739 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
1740 oval = 0x00000001;
1741 hval = 0x00000001;
1742 mask = 0x00000707;
1743 }
1744
1745 nv_mask(priv, hreg, 0x0000000f, hval);
1746 nv_mask(priv, oreg, mask, oval);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001747}
1748
1749/* If programming a TMDS output on a SOR that can also be configured for
1750 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
1751 *
1752 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
1753 * the VBIOS scripts on at least one board I have only switch it off on
1754 * link 0, causing a blank display if the output has previously been
1755 * programmed for DisplayPort.
1756 */
1757static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001758nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001759{
1760 struct nouveau_bios *bios = nouveau_bios(priv);
1761 const int link = !(outp->sorconf.link & 1);
1762 const int or = ffs(outp->or) - 1;
1763 const u32 loff = (or * 0x800) + (link * 0x80);
1764 const u16 mask = (outp->sorconf.link << 6) | outp->or;
1765 u8 ver, hdr;
1766
1767 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
1768 nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
1769}
1770
1771static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001772nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001773{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001774 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001775 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001776 u32 conf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001777
Ben Skeggs415f12e2014-05-21 11:24:43 +10001778 outp = exec_clkcmp(priv, head, 1, pclk, &conf);
1779 if (!outp)
1780 return;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001781
Ben Skeggs415f12e2014-05-21 11:24:43 +10001782 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
1783 nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001784}
1785
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001786void
1787nv50_disp_intr_supervisor(struct work_struct *work)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001788{
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001789 struct nv50_disp_priv *priv =
1790 container_of(work, struct nv50_disp_priv, supervisor);
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001791 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001792 u32 super = nv_rd32(priv, 0x610030);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001793 int head;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001794
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001795 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001796
Ben Skeggs16d4c032013-02-20 18:56:33 +10001797 if (priv->super & 0x00000010) {
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001798 nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001799 for (head = 0; head < priv->head.nr; head++) {
1800 if (!(super & (0x00000020 << head)))
1801 continue;
1802 if (!(super & (0x00000080 << head)))
1803 continue;
1804 nv50_disp_intr_unk10_0(priv, head);
1805 }
1806 } else
1807 if (priv->super & 0x00000020) {
1808 for (head = 0; head < priv->head.nr; head++) {
1809 if (!(super & (0x00000080 << head)))
1810 continue;
1811 nv50_disp_intr_unk20_0(priv, head);
1812 }
1813 for (head = 0; head < priv->head.nr; head++) {
1814 if (!(super & (0x00000200 << head)))
1815 continue;
1816 nv50_disp_intr_unk20_1(priv, head);
1817 }
1818 for (head = 0; head < priv->head.nr; head++) {
1819 if (!(super & (0x00000080 << head)))
1820 continue;
1821 nv50_disp_intr_unk20_2(priv, head);
1822 }
1823 } else
1824 if (priv->super & 0x00000040) {
1825 for (head = 0; head < priv->head.nr; head++) {
1826 if (!(super & (0x00000080 << head)))
1827 continue;
1828 nv50_disp_intr_unk40_0(priv, head);
1829 }
1830 }
1831
1832 nv_wr32(priv, 0x610030, 0x80000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001833}
1834
Ben Skeggs70cabe42012-08-14 10:04:04 +10001835void
Ben Skeggsebb945a2012-07-20 08:17:34 +10001836nv50_disp_intr(struct nouveau_subdev *subdev)
1837{
1838 struct nv50_disp_priv *priv = (void *)subdev;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001839 u32 intr0 = nv_rd32(priv, 0x610020);
1840 u32 intr1 = nv_rd32(priv, 0x610024);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001841
Ben Skeggs117e16332014-02-21 11:06:40 +10001842 while (intr0 & 0x001f0000) {
1843 u32 chid = __ffs(intr0 & 0x001f0000) - 16;
1844 nv50_disp_intr_error(priv, chid);
1845 intr0 &= ~(0x00010000 << chid);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001846 }
1847
1848 if (intr1 & 0x00000004) {
Ben Skeggs79ca2772014-08-10 04:10:20 +10001849 nouveau_disp_vblank(&priv->base, 0);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001850 nv_wr32(priv, 0x610024, 0x00000004);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001851 intr1 &= ~0x00000004;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001852 }
1853
Ben Skeggs186ecad2012-11-09 12:09:48 +10001854 if (intr1 & 0x00000008) {
Ben Skeggs79ca2772014-08-10 04:10:20 +10001855 nouveau_disp_vblank(&priv->base, 1);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001856 nv_wr32(priv, 0x610024, 0x00000008);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001857 intr1 &= ~0x00000008;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001858 }
1859
Ben Skeggs186ecad2012-11-09 12:09:48 +10001860 if (intr1 & 0x00000070) {
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001861 priv->super = (intr1 & 0x00000070);
1862 schedule_work(&priv->supervisor);
1863 nv_wr32(priv, 0x610024, priv->super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001864 intr1 &= ~0x00000070;
1865 }
Ben Skeggsebb945a2012-07-20 08:17:34 +10001866}
1867
1868static int
1869nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
Ben Skeggs370c00f2012-08-14 14:11:49 +10001870 struct nouveau_oclass *oclass, void *data, u32 size,
1871 struct nouveau_object **pobject)
Ben Skeggsebb945a2012-07-20 08:17:34 +10001872{
1873 struct nv50_disp_priv *priv;
1874 int ret;
1875
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001876 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
Ben Skeggsebb945a2012-07-20 08:17:34 +10001877 "display", &priv);
1878 *pobject = nv_object(priv);
1879 if (ret)
1880 return ret;
1881
Ben Skeggs70cabe42012-08-14 10:04:04 +10001882 nv_engine(priv)->sclass = nv50_disp_base_oclass;
1883 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001884 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001885 INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001886 priv->sclass = nv50_disp_sclass;
1887 priv->head.nr = 2;
1888 priv->dac.nr = 3;
1889 priv->sor.nr = 2;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001890 priv->pior.nr = 3;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001891 priv->dac.power = nv50_dac_power;
Ben Skeggs7ebb38b2012-11-09 09:38:06 +10001892 priv->dac.sense = nv50_dac_sense;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001893 priv->sor.power = nv50_sor_power;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001894 priv->pior.power = nv50_pior_power;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001895 return 0;
1896}
1897
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001898struct nouveau_oclass *
Ben Skeggsb8407c92014-05-17 11:19:54 +10001899nv50_disp_outp_sclass[] = {
1900 &nv50_pior_dp_impl.base.base,
1901 NULL
1902};
1903
1904struct nouveau_oclass *
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001905nv50_disp_oclass = &(struct nv50_disp_impl) {
1906 .base.base.handle = NV_ENGINE(DISP, 0x50),
1907 .base.base.ofuncs = &(struct nouveau_ofuncs) {
Ben Skeggsebb945a2012-07-20 08:17:34 +10001908 .ctor = nv50_disp_ctor,
1909 .dtor = _nouveau_disp_dtor,
1910 .init = _nouveau_disp_init,
1911 .fini = _nouveau_disp_fini,
1912 },
Ben Skeggs79ca2772014-08-10 04:10:20 +10001913 .base.vblank = &nv50_disp_vblank_func,
Ben Skeggsb8407c92014-05-17 11:19:54 +10001914 .base.outp = nv50_disp_outp_sclass,
Ben Skeggsd67d92c2014-02-20 15:14:10 +10001915 .mthd.core = &nv50_disp_mast_mthd_chan,
1916 .mthd.base = &nv50_disp_sync_mthd_chan,
1917 .mthd.ovly = &nv50_disp_ovly_mthd_chan,
1918 .mthd.prev = 0x000004,
Ben Skeggs4952b4d2014-08-10 04:10:27 +10001919 .head.scanoutpos = nv50_disp_base_scanoutpos,
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001920}.base.base;