blob: 7e60c11d7d36add1d8524a32860cfcb04f44e643 [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 <core/class.h>
31#include <nvif/unpack.h>
32#include <nvif/class.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100033
Ben Skeggs186ecad2012-11-09 12:09:48 +100034#include <subdev/bios.h>
35#include <subdev/bios/dcb.h>
36#include <subdev/bios/disp.h>
37#include <subdev/bios/init.h>
38#include <subdev/bios/pll.h>
Ben Skeggs88524bc2013-03-05 10:53:54 +100039#include <subdev/devinit.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100040#include <subdev/timer.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100041#include <subdev/fb.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100042
Ben Skeggs70cabe42012-08-14 10:04:04 +100043#include "nv50.h"
44
45/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +100046 * EVO channel base class
Ben Skeggs70cabe42012-08-14 10:04:04 +100047 ******************************************************************************/
48
Ben Skeggs2c04ae02014-08-10 04:10:25 +100049static int
Ben Skeggs370c00f2012-08-14 14:11:49 +100050nv50_disp_chan_create_(struct nouveau_object *parent,
51 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +100052 struct nouveau_oclass *oclass, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +100053 int length, void **pobject)
54{
Ben Skeggs2c04ae02014-08-10 04:10:25 +100055 const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
Ben Skeggs370c00f2012-08-14 14:11:49 +100056 struct nv50_disp_base *base = (void *)parent;
57 struct nv50_disp_chan *chan;
Ben Skeggs2c04ae02014-08-10 04:10:25 +100058 int chid = impl->chid + head;
Ben Skeggs370c00f2012-08-14 14:11:49 +100059 int ret;
60
61 if (base->chan & (1 << chid))
62 return -EBUSY;
63 base->chan |= (1 << chid);
64
65 ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
66 (1ULL << NVDEV_ENGINE_DMAOBJ),
67 length, pobject);
68 chan = *pobject;
69 if (ret)
70 return ret;
Ben Skeggs370c00f2012-08-14 14:11:49 +100071 chan->chid = chid;
Ben Skeggs2c04ae02014-08-10 04:10:25 +100072
73 nv_parent(chan)->object_attach = impl->attach;
74 nv_parent(chan)->object_detach = impl->detach;
Ben Skeggs370c00f2012-08-14 14:11:49 +100075 return 0;
76}
77
Ben Skeggs2c04ae02014-08-10 04:10:25 +100078static void
Ben Skeggs370c00f2012-08-14 14:11:49 +100079nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
80{
81 struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
82 base->chan &= ~(1 << chan->chid);
83 nouveau_namedb_destroy(&chan->base);
84}
85
86u32
Ben Skeggs70cabe42012-08-14 10:04:04 +100087nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
88{
Ben Skeggs370c00f2012-08-14 14:11:49 +100089 struct nv50_disp_priv *priv = (void *)object->engine;
90 struct nv50_disp_chan *chan = (void *)object;
91 return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
92}
93
94void
95nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
96{
97 struct nv50_disp_priv *priv = (void *)object->engine;
98 struct nv50_disp_chan *chan = (void *)object;
99 nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
100}
101
102/*******************************************************************************
103 * EVO DMA channel base class
104 ******************************************************************************/
105
106static int
107nv50_disp_dmac_object_attach(struct nouveau_object *parent,
108 struct nouveau_object *object, u32 name)
109{
110 struct nv50_disp_base *base = (void *)parent->parent;
111 struct nv50_disp_chan *chan = (void *)parent;
112 u32 addr = nv_gpuobj(object)->node->offset;
113 u32 chid = chan->chid;
114 u32 data = (chid << 28) | (addr << 10) | chid;
115 return nouveau_ramht_insert(base->ramht, chid, name, data);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000116}
117
118static void
Ben Skeggs370c00f2012-08-14 14:11:49 +1000119nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
Ben Skeggs70cabe42012-08-14 10:04:04 +1000120{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000121 struct nv50_disp_base *base = (void *)parent->parent;
122 nouveau_ramht_remove(base->ramht, cookie);
123}
124
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000125static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000126nv50_disp_dmac_create_(struct nouveau_object *parent,
127 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000128 struct nouveau_oclass *oclass, u32 pushbuf, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000129 int length, void **pobject)
130{
131 struct nv50_disp_dmac *dmac;
132 int ret;
133
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000134 ret = nv50_disp_chan_create_(parent, engine, oclass, head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000135 length, pobject);
136 dmac = *pobject;
137 if (ret)
138 return ret;
139
140 dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
141 if (!dmac->pushdma)
142 return -ENOENT;
143
144 switch (nv_mclass(dmac->pushdma)) {
145 case 0x0002:
146 case 0x003d:
147 if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
148 return -EINVAL;
149
150 switch (dmac->pushdma->target) {
151 case NV_MEM_TARGET_VRAM:
152 dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
153 break;
Ben Skeggs944234d2012-10-30 10:03:38 +1000154 case NV_MEM_TARGET_PCI_NOSNOOP:
155 dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
156 break;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000157 default:
158 return -EINVAL;
159 }
160 break;
161 default:
162 return -EINVAL;
163 }
164
165 return 0;
166}
167
168void
169nv50_disp_dmac_dtor(struct nouveau_object *object)
170{
171 struct nv50_disp_dmac *dmac = (void *)object;
172 nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
173 nv50_disp_chan_destroy(&dmac->base);
174}
175
176static int
177nv50_disp_dmac_init(struct nouveau_object *object)
178{
179 struct nv50_disp_priv *priv = (void *)object->engine;
180 struct nv50_disp_dmac *dmac = (void *)object;
181 int chid = dmac->base.chid;
182 int ret;
183
184 ret = nv50_disp_chan_init(&dmac->base);
185 if (ret)
186 return ret;
187
188 /* enable error reporting */
189 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
190
191 /* initialise channel for dma command submission */
192 nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
193 nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
194 nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
195 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
196 nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
197 nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
198
199 /* wait for it to go inactive */
200 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
201 nv_error(dmac, "init timeout, 0x%08x\n",
202 nv_rd32(priv, 0x610200 + (chid * 0x10)));
203 return -EBUSY;
204 }
205
206 return 0;
207}
208
209static int
210nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
211{
212 struct nv50_disp_priv *priv = (void *)object->engine;
213 struct nv50_disp_dmac *dmac = (void *)object;
214 int chid = dmac->base.chid;
215
216 /* deactivate channel */
217 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
218 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
219 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
220 nv_error(dmac, "fini timeout, 0x%08x\n",
221 nv_rd32(priv, 0x610200 + (chid * 0x10)));
222 if (suspend)
223 return -EBUSY;
224 }
225
226 /* disable error reporting */
227 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
228
229 return nv50_disp_chan_fini(&dmac->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000230}
231
232/*******************************************************************************
233 * EVO master channel object
234 ******************************************************************************/
235
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000236static void
237nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
238 const struct nv50_disp_mthd_list *list, int inst)
239{
240 struct nouveau_object *disp = nv_object(priv);
241 int i;
242
243 for (i = 0; list->data[i].mthd; i++) {
244 if (list->data[i].addr) {
245 u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
246 u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
247 u32 mthd = list->data[i].mthd + (list->mthd * inst);
248 const char *name = list->data[i].name;
249 char mods[16];
250
251 if (prev != next)
252 snprintf(mods, sizeof(mods), "-> 0x%08x", next);
253 else
254 snprintf(mods, sizeof(mods), "%13c", ' ');
255
256 nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
257 mthd, prev, mods, name ? " // " : "",
258 name ? name : "");
259 }
260 }
261}
262
263void
264nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
265 const struct nv50_disp_mthd_chan *chan)
266{
267 struct nouveau_object *disp = nv_object(priv);
268 const struct nv50_disp_impl *impl = (void *)disp->oclass;
269 const struct nv50_disp_mthd_list *list;
270 int i, j;
271
272 if (debug > nv_subdev(priv)->debug)
273 return;
274
275 for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
276 u32 base = head * chan->addr;
277 for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
278 const char *cname = chan->name;
279 const char *sname = "";
280 char cname_[16], sname_[16];
281
282 if (chan->addr) {
283 snprintf(cname_, sizeof(cname_), "%s %d",
284 chan->name, head);
285 cname = cname_;
286 }
287
288 if (chan->data[i].nr > 1) {
289 snprintf(sname_, sizeof(sname_), " - %s %d",
290 chan->data[i].name, j);
291 sname = sname_;
292 }
293
294 nv_printk_(disp, debug, "%s%s:\n", cname, sname);
295 nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
296 list, j);
297 }
298 }
299}
300
301const struct nv50_disp_mthd_list
302nv50_disp_mast_mthd_base = {
303 .mthd = 0x0000,
304 .addr = 0x000000,
305 .data = {
306 { 0x0080, 0x000000 },
307 { 0x0084, 0x610bb8 },
308 { 0x0088, 0x610b9c },
309 { 0x008c, 0x000000 },
310 {}
311 }
312};
313
314static const struct nv50_disp_mthd_list
315nv50_disp_mast_mthd_dac = {
316 .mthd = 0x0080,
317 .addr = 0x000008,
318 .data = {
319 { 0x0400, 0x610b58 },
320 { 0x0404, 0x610bdc },
321 { 0x0420, 0x610828 },
322 {}
323 }
324};
325
326const struct nv50_disp_mthd_list
327nv50_disp_mast_mthd_sor = {
328 .mthd = 0x0040,
329 .addr = 0x000008,
330 .data = {
331 { 0x0600, 0x610b70 },
332 {}
333 }
334};
335
336const struct nv50_disp_mthd_list
337nv50_disp_mast_mthd_pior = {
338 .mthd = 0x0040,
339 .addr = 0x000008,
340 .data = {
341 { 0x0700, 0x610b80 },
342 {}
343 }
344};
345
346static const struct nv50_disp_mthd_list
347nv50_disp_mast_mthd_head = {
348 .mthd = 0x0400,
349 .addr = 0x000540,
350 .data = {
351 { 0x0800, 0x610ad8 },
352 { 0x0804, 0x610ad0 },
353 { 0x0808, 0x610a48 },
354 { 0x080c, 0x610a78 },
355 { 0x0810, 0x610ac0 },
356 { 0x0814, 0x610af8 },
357 { 0x0818, 0x610b00 },
358 { 0x081c, 0x610ae8 },
359 { 0x0820, 0x610af0 },
360 { 0x0824, 0x610b08 },
361 { 0x0828, 0x610b10 },
362 { 0x082c, 0x610a68 },
363 { 0x0830, 0x610a60 },
364 { 0x0834, 0x000000 },
365 { 0x0838, 0x610a40 },
366 { 0x0840, 0x610a24 },
367 { 0x0844, 0x610a2c },
368 { 0x0848, 0x610aa8 },
369 { 0x084c, 0x610ab0 },
370 { 0x0860, 0x610a84 },
371 { 0x0864, 0x610a90 },
372 { 0x0868, 0x610b18 },
373 { 0x086c, 0x610b20 },
374 { 0x0870, 0x610ac8 },
375 { 0x0874, 0x610a38 },
376 { 0x0880, 0x610a58 },
377 { 0x0884, 0x610a9c },
378 { 0x08a0, 0x610a70 },
379 { 0x08a4, 0x610a50 },
380 { 0x08a8, 0x610ae0 },
381 { 0x08c0, 0x610b28 },
382 { 0x08c4, 0x610b30 },
383 { 0x08c8, 0x610b40 },
384 { 0x08d4, 0x610b38 },
385 { 0x08d8, 0x610b48 },
386 { 0x08dc, 0x610b50 },
387 { 0x0900, 0x610a18 },
388 { 0x0904, 0x610ab8 },
389 {}
390 }
391};
392
393static const struct nv50_disp_mthd_chan
394nv50_disp_mast_mthd_chan = {
395 .name = "Core",
396 .addr = 0x000000,
397 .data = {
398 { "Global", 1, &nv50_disp_mast_mthd_base },
399 { "DAC", 3, &nv50_disp_mast_mthd_dac },
400 { "SOR", 2, &nv50_disp_mast_mthd_sor },
401 { "PIOR", 3, &nv50_disp_mast_mthd_pior },
402 { "HEAD", 2, &nv50_disp_mast_mthd_head },
403 {}
404 }
405};
406
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000407int
Ben Skeggs70cabe42012-08-14 10:04:04 +1000408nv50_disp_mast_ctor(struct nouveau_object *parent,
409 struct nouveau_object *engine,
410 struct nouveau_oclass *oclass, void *data, u32 size,
411 struct nouveau_object **pobject)
412{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000413 struct nv50_display_mast_class *args = data;
414 struct nv50_disp_dmac *mast;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000415 int ret;
416
Ben Skeggs370c00f2012-08-14 14:11:49 +1000417 if (size < sizeof(*args))
418 return -EINVAL;
419
420 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
421 0, sizeof(*mast), (void **)&mast);
422 *pobject = nv_object(mast);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000423 if (ret)
424 return ret;
425
426 return 0;
427}
428
Ben Skeggs70cabe42012-08-14 10:04:04 +1000429static int
430nv50_disp_mast_init(struct nouveau_object *object)
431{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000432 struct nv50_disp_priv *priv = (void *)object->engine;
433 struct nv50_disp_dmac *mast = (void *)object;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000434 int ret;
435
Ben Skeggs370c00f2012-08-14 14:11:49 +1000436 ret = nv50_disp_chan_init(&mast->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000437 if (ret)
438 return ret;
439
Ben Skeggs370c00f2012-08-14 14:11:49 +1000440 /* enable error reporting */
441 nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
442
443 /* attempt to unstick channel from some unknown state */
444 if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
445 nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
446 if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
447 nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
448
449 /* initialise channel for dma command submission */
450 nv_wr32(priv, 0x610204, mast->push);
451 nv_wr32(priv, 0x610208, 0x00010000);
452 nv_wr32(priv, 0x61020c, 0x00000000);
453 nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
454 nv_wr32(priv, 0x640000, 0x00000000);
455 nv_wr32(priv, 0x610200, 0x01000013);
456
457 /* wait for it to go inactive */
458 if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
459 nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
460 return -EBUSY;
461 }
462
Ben Skeggs70cabe42012-08-14 10:04:04 +1000463 return 0;
464}
465
466static int
467nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
468{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000469 struct nv50_disp_priv *priv = (void *)object->engine;
470 struct nv50_disp_dmac *mast = (void *)object;
471
472 /* deactivate channel */
473 nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
474 nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
475 if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
476 nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
477 if (suspend)
478 return -EBUSY;
479 }
480
481 /* disable error reporting */
482 nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
483
484 return nv50_disp_chan_fini(&mast->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000485}
486
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000487struct nv50_disp_chan_impl
Ben Skeggs70cabe42012-08-14 10:04:04 +1000488nv50_disp_mast_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000489 .base.ctor = nv50_disp_mast_ctor,
490 .base.dtor = nv50_disp_dmac_dtor,
491 .base.init = nv50_disp_mast_init,
492 .base.fini = nv50_disp_mast_fini,
493 .base.rd32 = nv50_disp_chan_rd32,
494 .base.wr32 = nv50_disp_chan_wr32,
495 .chid = 0,
496 .attach = nv50_disp_dmac_object_attach,
497 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000498};
499
500/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000501 * EVO sync channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000502 ******************************************************************************/
503
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000504static const struct nv50_disp_mthd_list
505nv50_disp_sync_mthd_base = {
506 .mthd = 0x0000,
507 .addr = 0x000000,
508 .data = {
509 { 0x0080, 0x000000 },
510 { 0x0084, 0x0008c4 },
511 { 0x0088, 0x0008d0 },
512 { 0x008c, 0x0008dc },
513 { 0x0090, 0x0008e4 },
514 { 0x0094, 0x610884 },
515 { 0x00a0, 0x6108a0 },
516 { 0x00a4, 0x610878 },
517 { 0x00c0, 0x61086c },
518 { 0x00e0, 0x610858 },
519 { 0x00e4, 0x610860 },
520 { 0x00e8, 0x6108ac },
521 { 0x00ec, 0x6108b4 },
522 { 0x0100, 0x610894 },
523 { 0x0110, 0x6108bc },
524 { 0x0114, 0x61088c },
525 {}
526 }
527};
528
529const struct nv50_disp_mthd_list
530nv50_disp_sync_mthd_image = {
531 .mthd = 0x0400,
532 .addr = 0x000000,
533 .data = {
534 { 0x0800, 0x6108f0 },
535 { 0x0804, 0x6108fc },
536 { 0x0808, 0x61090c },
537 { 0x080c, 0x610914 },
538 { 0x0810, 0x610904 },
539 {}
540 }
541};
542
543static const struct nv50_disp_mthd_chan
544nv50_disp_sync_mthd_chan = {
545 .name = "Base",
546 .addr = 0x000540,
547 .data = {
548 { "Global", 1, &nv50_disp_sync_mthd_base },
549 { "Image", 2, &nv50_disp_sync_mthd_image },
550 {}
551 }
552};
553
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000554int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000555nv50_disp_sync_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000556 struct nouveau_object *engine,
557 struct nouveau_oclass *oclass, void *data, u32 size,
558 struct nouveau_object **pobject)
559{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000560 struct nv50_display_sync_class *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000561 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000562 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000563 int ret;
564
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000565 if (size < sizeof(*args) || args->head >= priv->head.nr)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000566 return -EINVAL;
567
568 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000569 args->head, sizeof(*dmac), (void **)&dmac);
Ben Skeggs370c00f2012-08-14 14:11:49 +1000570 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000571 if (ret)
572 return ret;
573
574 return 0;
575}
576
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000577struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000578nv50_disp_sync_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000579 .base.ctor = nv50_disp_sync_ctor,
580 .base.dtor = nv50_disp_dmac_dtor,
581 .base.init = nv50_disp_dmac_init,
582 .base.fini = nv50_disp_dmac_fini,
583 .base.rd32 = nv50_disp_chan_rd32,
584 .base.wr32 = nv50_disp_chan_wr32,
585 .chid = 1,
586 .attach = nv50_disp_dmac_object_attach,
587 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000588};
589
590/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000591 * EVO overlay channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000592 ******************************************************************************/
593
Ben Skeggsd67d92c2014-02-20 15:14:10 +1000594const struct nv50_disp_mthd_list
595nv50_disp_ovly_mthd_base = {
596 .mthd = 0x0000,
597 .addr = 0x000000,
598 .data = {
599 { 0x0080, 0x000000 },
600 { 0x0084, 0x0009a0 },
601 { 0x0088, 0x0009c0 },
602 { 0x008c, 0x0009c8 },
603 { 0x0090, 0x6109b4 },
604 { 0x0094, 0x610970 },
605 { 0x00a0, 0x610998 },
606 { 0x00a4, 0x610964 },
607 { 0x00c0, 0x610958 },
608 { 0x00e0, 0x6109a8 },
609 { 0x00e4, 0x6109d0 },
610 { 0x00e8, 0x6109d8 },
611 { 0x0100, 0x61094c },
612 { 0x0104, 0x610984 },
613 { 0x0108, 0x61098c },
614 { 0x0800, 0x6109f8 },
615 { 0x0808, 0x610a08 },
616 { 0x080c, 0x610a10 },
617 { 0x0810, 0x610a00 },
618 {}
619 }
620};
621
622static const struct nv50_disp_mthd_chan
623nv50_disp_ovly_mthd_chan = {
624 .name = "Overlay",
625 .addr = 0x000540,
626 .data = {
627 { "Global", 1, &nv50_disp_ovly_mthd_base },
628 {}
629 }
630};
631
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000632int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000633nv50_disp_ovly_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000634 struct nouveau_object *engine,
635 struct nouveau_oclass *oclass, void *data, u32 size,
636 struct nouveau_object **pobject)
637{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000638 struct nv50_display_ovly_class *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000639 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000640 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000641 int ret;
642
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000643 if (size < sizeof(*args) || args->head >= priv->head.nr)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000644 return -EINVAL;
645
646 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000647 args->head, sizeof(*dmac), (void **)&dmac);
Ben Skeggs370c00f2012-08-14 14:11:49 +1000648 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000649 if (ret)
650 return ret;
651
652 return 0;
653}
654
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000655struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000656nv50_disp_ovly_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000657 .base.ctor = nv50_disp_ovly_ctor,
658 .base.dtor = nv50_disp_dmac_dtor,
659 .base.init = nv50_disp_dmac_init,
660 .base.fini = nv50_disp_dmac_fini,
661 .base.rd32 = nv50_disp_chan_rd32,
662 .base.wr32 = nv50_disp_chan_wr32,
663 .chid = 3,
664 .attach = nv50_disp_dmac_object_attach,
665 .detach = nv50_disp_dmac_object_detach,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000666};
667
668/*******************************************************************************
669 * EVO PIO channel base class
670 ******************************************************************************/
671
672static int
673nv50_disp_pioc_create_(struct nouveau_object *parent,
674 struct nouveau_object *engine,
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000675 struct nouveau_oclass *oclass, int head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000676 int length, void **pobject)
677{
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000678 return nv50_disp_chan_create_(parent, engine, oclass, head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000679 length, pobject);
680}
681
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000682void
Ben Skeggs70cabe42012-08-14 10:04:04 +1000683nv50_disp_pioc_dtor(struct nouveau_object *object)
684{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000685 struct nv50_disp_pioc *pioc = (void *)object;
686 nv50_disp_chan_destroy(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000687}
688
689static int
690nv50_disp_pioc_init(struct nouveau_object *object)
691{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000692 struct nv50_disp_priv *priv = (void *)object->engine;
693 struct nv50_disp_pioc *pioc = (void *)object;
694 int chid = pioc->base.chid;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000695 int ret;
696
Ben Skeggs370c00f2012-08-14 14:11:49 +1000697 ret = nv50_disp_chan_init(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000698 if (ret)
699 return ret;
700
Ben Skeggs370c00f2012-08-14 14:11:49 +1000701 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
702 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
703 nv_error(pioc, "timeout0: 0x%08x\n",
704 nv_rd32(priv, 0x610200 + (chid * 0x10)));
705 return -EBUSY;
706 }
707
708 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
709 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
710 nv_error(pioc, "timeout1: 0x%08x\n",
711 nv_rd32(priv, 0x610200 + (chid * 0x10)));
712 return -EBUSY;
713 }
714
Ben Skeggs70cabe42012-08-14 10:04:04 +1000715 return 0;
716}
717
718static int
719nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
720{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000721 struct nv50_disp_priv *priv = (void *)object->engine;
722 struct nv50_disp_pioc *pioc = (void *)object;
723 int chid = pioc->base.chid;
724
725 nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
726 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
727 nv_error(pioc, "timeout: 0x%08x\n",
728 nv_rd32(priv, 0x610200 + (chid * 0x10)));
729 if (suspend)
730 return -EBUSY;
731 }
732
733 return nv50_disp_chan_fini(&pioc->base, suspend);
734}
735
736/*******************************************************************************
737 * EVO immediate overlay channel objects
738 ******************************************************************************/
739
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000740int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000741nv50_disp_oimm_ctor(struct nouveau_object *parent,
742 struct nouveau_object *engine,
743 struct nouveau_oclass *oclass, void *data, u32 size,
744 struct nouveau_object **pobject)
745{
746 struct nv50_display_oimm_class *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000747 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000748 struct nv50_disp_pioc *pioc;
749 int ret;
750
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000751 if (size < sizeof(*args) || args->head >= priv->head.nr)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000752 return -EINVAL;
753
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000754 ret = nv50_disp_pioc_create_(parent, engine, oclass, args->head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000755 sizeof(*pioc), (void **)&pioc);
756 *pobject = nv_object(pioc);
757 if (ret)
758 return ret;
759
760 return 0;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000761}
762
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000763struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000764nv50_disp_oimm_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000765 .base.ctor = nv50_disp_oimm_ctor,
766 .base.dtor = nv50_disp_pioc_dtor,
767 .base.init = nv50_disp_pioc_init,
768 .base.fini = nv50_disp_pioc_fini,
769 .base.rd32 = nv50_disp_chan_rd32,
770 .base.wr32 = nv50_disp_chan_wr32,
771 .chid = 5,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000772};
773
774/*******************************************************************************
775 * EVO cursor channel objects
776 ******************************************************************************/
777
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000778int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000779nv50_disp_curs_ctor(struct nouveau_object *parent,
780 struct nouveau_object *engine,
781 struct nouveau_oclass *oclass, void *data, u32 size,
782 struct nouveau_object **pobject)
783{
784 struct nv50_display_curs_class *args = data;
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000785 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000786 struct nv50_disp_pioc *pioc;
787 int ret;
788
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000789 if (size < sizeof(*args) || args->head >= priv->head.nr)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000790 return -EINVAL;
791
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000792 ret = nv50_disp_pioc_create_(parent, engine, oclass, args->head,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000793 sizeof(*pioc), (void **)&pioc);
794 *pobject = nv_object(pioc);
795 if (ret)
796 return ret;
797
798 return 0;
799}
800
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000801struct nv50_disp_chan_impl
Ben Skeggs370c00f2012-08-14 14:11:49 +1000802nv50_disp_curs_ofuncs = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +1000803 .base.ctor = nv50_disp_curs_ctor,
804 .base.dtor = nv50_disp_pioc_dtor,
805 .base.init = nv50_disp_pioc_init,
806 .base.fini = nv50_disp_pioc_fini,
807 .base.rd32 = nv50_disp_chan_rd32,
808 .base.wr32 = nv50_disp_chan_wr32,
809 .chid = 7,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000810};
811
812/*******************************************************************************
813 * Base display object
814 ******************************************************************************/
815
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000816int
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000817nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000818{
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000819 const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
820 const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
821 const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
822 union {
823 struct nv04_disp_scanoutpos_v0 v0;
824 } *args = data;
825 int ret;
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000826
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000827 nv_ioctl(object, "disp scanoutpos size %d\n", size);
828 if (nvif_unpack(args->v0, 0, 0, false)) {
829 nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
830 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
831 args->v0.hblanke = (blanke & 0x0000ffff);
832 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
833 args->v0.hblanks = (blanks & 0x0000ffff);
834 args->v0.vtotal = ( total & 0xffff0000) >> 16;
835 args->v0.htotal = ( total & 0x0000ffff);
836 args->v0.time[0] = ktime_to_ns(ktime_get());
837 args->v0.vline = /* vline read locks hline */
838 nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
839 args->v0.time[1] = ktime_to_ns(ktime_get());
840 args->v0.hline =
841 nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
842 } else
843 return ret;
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000844
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000845 return 0;
846}
847
Ben Skeggs79ca2772014-08-10 04:10:20 +1000848int
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000849nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
850 void *data, u32 size)
851{
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000852 const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000853 union {
854 struct nv50_disp_mthd_v0 v0;
855 struct nv50_disp_mthd_v1 v1;
856 } *args = data;
857 struct nv50_disp_priv *priv = (void *)object->engine;
858 struct nvkm_output *outp = NULL;
859 struct nvkm_output *temp;
860 u16 type, mask = 0;
861 int head, ret;
862
863 if (mthd != NV50_DISP_MTHD)
864 return -EINVAL;
865
866 nv_ioctl(object, "disp mthd size %d\n", size);
867 if (nvif_unpack(args->v0, 0, 0, true)) {
868 nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
869 args->v0.version, args->v0.method, args->v0.head);
870 mthd = args->v0.method;
871 head = args->v0.head;
872 } else
873 if (nvif_unpack(args->v1, 1, 1, true)) {
874 nv_ioctl(object, "disp mthd vers %d mthd %02x "
875 "type %04x mask %04x\n",
876 args->v1.version, args->v1.method,
877 args->v1.hasht, args->v1.hashm);
878 mthd = args->v1.method;
879 type = args->v1.hasht;
880 mask = args->v1.hashm;
881 head = ffs((mask >> 8) & 0x0f) - 1;
882 } else
883 return ret;
884
885 if (head < 0 || head >= priv->head.nr)
886 return -ENXIO;
887
888 if (mask) {
889 list_for_each_entry(temp, &priv->base.outp, head) {
890 if ((temp->info.hasht == type) &&
891 (temp->info.hashm & mask) == mask) {
892 outp = temp;
893 break;
894 }
895 }
896 if (outp == NULL)
897 return -ENXIO;
898 }
899
900 switch (mthd) {
Ben Skeggs4952b4d2014-08-10 04:10:27 +1000901 case NV50_DISP_SCANOUTPOS:
902 return impl->head.scanoutpos(object, priv, data, size, head);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000903 default:
904 break;
905 }
906
907 switch (mthd * !!outp) {
908 case NV50_DISP_MTHD_V1_DAC_PWR:
909 return priv->dac.power(object, priv, data, size, head, outp);
Ben Skeggsc4abd312014-08-10 04:10:26 +1000910 case NV50_DISP_MTHD_V1_DAC_LOAD:
911 return priv->dac.sense(object, priv, data, size, head, outp);
Ben Skeggsd55b4af2014-08-10 04:10:26 +1000912 case NV50_DISP_MTHD_V1_SOR_PWR:
913 return priv->sor.power(object, priv, data, size, head, outp);
Ben Skeggs120b0c32014-08-10 04:10:26 +1000914 case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
915 if (!priv->sor.hda_eld)
916 return -ENODEV;
917 return priv->sor.hda_eld(object, priv, data, size, head, outp);
Ben Skeggse00f2232014-08-10 04:10:26 +1000918 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
919 if (!priv->sor.hdmi)
920 return -ENODEV;
921 return priv->sor.hdmi(object, priv, data, size, head, outp);
Ben Skeggsa3761fa2014-08-10 04:10:27 +1000922 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
923 union {
924 struct nv50_disp_sor_lvds_script_v0 v0;
925 } *args = data;
926 nv_ioctl(object, "disp sor lvds script size %d\n", size);
927 if (nvif_unpack(args->v0, 0, 0, false)) {
928 nv_ioctl(object, "disp sor lvds script "
929 "vers %d name %04x\n",
930 args->v0.version, args->v0.script);
931 priv->sor.lvdsconf = args->v0.script;
932 return 0;
933 } else
934 return ret;
935 }
936 break;
Ben Skeggsc02ed2b2014-08-10 04:10:27 +1000937 case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
938 struct nvkm_output_dp *outpdp = (void *)outp;
939 union {
940 struct nv50_disp_sor_dp_pwr_v0 v0;
941 } *args = data;
942 nv_ioctl(object, "disp sor dp pwr size %d\n", size);
943 if (nvif_unpack(args->v0, 0, 0, false)) {
944 nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
945 args->v0.version, args->v0.state);
946 if (args->v0.state == 0) {
947 nvkm_notify_put(&outpdp->irq);
948 ((struct nvkm_output_dp_impl *)nv_oclass(outp))
949 ->lnk_pwr(outpdp, 0);
950 atomic_set(&outpdp->lt.done, 0);
951 return 0;
952 } else
953 if (args->v0.state != 0) {
954 nvkm_output_dp_train(&outpdp->base, 0, true);
955 return 0;
956 }
957 } else
958 return ret;
959 }
960 break;
Ben Skeggs67cb49c2014-08-10 04:10:27 +1000961 case NV50_DISP_MTHD_V1_PIOR_PWR:
962 if (!priv->pior.power)
963 return -ENODEV;
964 return priv->pior.power(object, priv, data, size, head, outp);
Ben Skeggsbf0eb892014-08-10 04:10:26 +1000965 default:
966 break;
967 }
968
969 return -EINVAL;
970}
971
972int
Ben Skeggs70cabe42012-08-14 10:04:04 +1000973nv50_disp_base_ctor(struct nouveau_object *parent,
974 struct nouveau_object *engine,
975 struct nouveau_oclass *oclass, void *data, u32 size,
976 struct nouveau_object **pobject)
977{
978 struct nv50_disp_priv *priv = (void *)engine;
979 struct nv50_disp_base *base;
980 int ret;
981
982 ret = nouveau_parent_create(parent, engine, oclass, 0,
983 priv->sclass, 0, &base);
984 *pobject = nv_object(base);
985 if (ret)
986 return ret;
987
Ben Skeggs2ecda482013-04-24 18:04:22 +1000988 return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
989 &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000990}
991
Ben Skeggs79ca2772014-08-10 04:10:20 +1000992void
Ben Skeggs70cabe42012-08-14 10:04:04 +1000993nv50_disp_base_dtor(struct nouveau_object *object)
994{
995 struct nv50_disp_base *base = (void *)object;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000996 nouveau_ramht_ref(NULL, &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000997 nouveau_parent_destroy(&base->base);
998}
999
1000static int
1001nv50_disp_base_init(struct nouveau_object *object)
1002{
Ben Skeggsab772142012-08-14 11:29:57 +10001003 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001004 struct nv50_disp_base *base = (void *)object;
Ben Skeggsab772142012-08-14 11:29:57 +10001005 int ret, i;
1006 u32 tmp;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001007
1008 ret = nouveau_parent_init(&base->base);
1009 if (ret)
1010 return ret;
1011
Ben Skeggsab772142012-08-14 11:29:57 +10001012 /* The below segments of code copying values from one register to
1013 * another appear to inform EVO of the display capabilities or
1014 * something similar. NFI what the 0x614004 caps are for..
1015 */
1016 tmp = nv_rd32(priv, 0x614004);
1017 nv_wr32(priv, 0x610184, tmp);
1018
1019 /* ... CRTC caps */
1020 for (i = 0; i < priv->head.nr; i++) {
1021 tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
1022 nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
1023 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
1024 nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
1025 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
1026 nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
1027 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
1028 nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
1029 }
1030
1031 /* ... DAC caps */
1032 for (i = 0; i < priv->dac.nr; i++) {
1033 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
1034 nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
1035 }
1036
1037 /* ... SOR caps */
1038 for (i = 0; i < priv->sor.nr; i++) {
1039 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
1040 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
1041 }
1042
Ben Skeggs476e84e2013-02-11 09:24:23 +10001043 /* ... PIOR caps */
Emil Velikovb969fa52013-07-30 01:01:10 +01001044 for (i = 0; i < priv->pior.nr; i++) {
Ben Skeggsab772142012-08-14 11:29:57 +10001045 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
1046 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
1047 }
1048
Ben Skeggs446b05a2012-08-14 12:50:14 +10001049 /* steal display away from vbios, or something like that */
1050 if (nv_rd32(priv, 0x610024) & 0x00000100) {
1051 nv_wr32(priv, 0x610024, 0x00000100);
1052 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
1053 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
1054 nv_error(priv, "timeout acquiring display\n");
1055 return -EBUSY;
1056 }
1057 }
1058
1059 /* point at display engine memory area (hash table, objects) */
Ben Skeggs370c00f2012-08-14 14:11:49 +10001060 nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
Ben Skeggs446b05a2012-08-14 12:50:14 +10001061
1062 /* enable supervisor interrupts, disable everything else */
Ben Skeggs370c00f2012-08-14 14:11:49 +10001063 nv_wr32(priv, 0x61002c, 0x00000370);
1064 nv_wr32(priv, 0x610028, 0x00000000);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001065 return 0;
1066}
1067
1068static int
1069nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
1070{
Ben Skeggs446b05a2012-08-14 12:50:14 +10001071 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001072 struct nv50_disp_base *base = (void *)object;
Ben Skeggs446b05a2012-08-14 12:50:14 +10001073
1074 /* disable all interrupts */
1075 nv_wr32(priv, 0x610024, 0x00000000);
1076 nv_wr32(priv, 0x610020, 0x00000000);
1077
Ben Skeggs70cabe42012-08-14 10:04:04 +10001078 return nouveau_parent_fini(&base->base, suspend);
1079}
1080
1081struct nouveau_ofuncs
1082nv50_disp_base_ofuncs = {
1083 .ctor = nv50_disp_base_ctor,
1084 .dtor = nv50_disp_base_dtor,
1085 .init = nv50_disp_base_init,
1086 .fini = nv50_disp_base_fini,
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001087 .mthd = nv50_disp_base_mthd,
Ben Skeggs70cabe42012-08-14 10:04:04 +10001088};
1089
1090static struct nouveau_oclass
1091nv50_disp_base_oclass[] = {
Ben Skeggs4952b4d2014-08-10 04:10:27 +10001092 { NV50_DISP_CLASS, &nv50_disp_base_ofuncs },
Ben Skeggs370c00f2012-08-14 14:11:49 +10001093 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +10001094};
1095
1096static struct nouveau_oclass
1097nv50_disp_sclass[] = {
Ben Skeggs2c04ae02014-08-10 04:10:25 +10001098 { NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs.base },
1099 { NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs.base },
1100 { NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs.base },
1101 { NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs.base },
1102 { NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs.base },
Ben Skeggs70cabe42012-08-14 10:04:04 +10001103 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +10001104};
1105
Ben Skeggs70cabe42012-08-14 10:04:04 +10001106/*******************************************************************************
1107 * Display context, tracks instmem allocation and prevents more than one
1108 * client using the display hardware at any time.
1109 ******************************************************************************/
1110
1111static int
1112nv50_disp_data_ctor(struct nouveau_object *parent,
1113 struct nouveau_object *engine,
1114 struct nouveau_oclass *oclass, void *data, u32 size,
1115 struct nouveau_object **pobject)
1116{
Ben Skeggs370c00f2012-08-14 14:11:49 +10001117 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001118 struct nouveau_engctx *ectx;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001119 int ret = -EBUSY;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001120
Ben Skeggs370c00f2012-08-14 14:11:49 +10001121 /* no context needed for channel objects... */
Ben Skeggs586491e2014-08-10 04:10:24 +10001122 if (nv_mclass(parent) != NV_DEVICE) {
Ben Skeggs370c00f2012-08-14 14:11:49 +10001123 atomic_inc(&parent->refcount);
1124 *pobject = parent;
Ben Skeggs43e6e512013-04-26 00:12:59 +10001125 return 1;
Ben Skeggs370c00f2012-08-14 14:11:49 +10001126 }
Ben Skeggs70cabe42012-08-14 10:04:04 +10001127
Ben Skeggs370c00f2012-08-14 14:11:49 +10001128 /* allocate display hardware to client */
1129 mutex_lock(&nv_subdev(priv)->mutex);
1130 if (list_empty(&nv_engine(priv)->contexts)) {
1131 ret = nouveau_engctx_create(parent, engine, oclass, NULL,
1132 0x10000, 0x10000,
1133 NVOBJ_FLAG_HEAP, &ectx);
1134 *pobject = nv_object(ectx);
1135 }
1136 mutex_unlock(&nv_subdev(priv)->mutex);
1137 return ret;
Ben Skeggs70cabe42012-08-14 10:04:04 +10001138}
1139
1140struct nouveau_oclass
1141nv50_disp_cclass = {
1142 .handle = NV_ENGCTX(DISP, 0x50),
1143 .ofuncs = &(struct nouveau_ofuncs) {
1144 .ctor = nv50_disp_data_ctor,
1145 .dtor = _nouveau_engctx_dtor,
1146 .init = _nouveau_engctx_init,
1147 .fini = _nouveau_engctx_fini,
1148 .rd32 = _nouveau_engctx_rd32,
1149 .wr32 = _nouveau_engctx_wr32,
1150 },
1151};
1152
1153/*******************************************************************************
1154 * Display engine implementation
1155 ******************************************************************************/
1156
Ben Skeggs79ca2772014-08-10 04:10:20 +10001157static void
1158nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
1159{
1160 struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
1161 nv_mask(disp, 0x61002c, (4 << head), 0);
1162}
1163
1164static void
1165nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
1166{
1167 struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
1168 nv_mask(disp, 0x61002c, (4 << head), (4 << head));
1169}
1170
1171const struct nvkm_event_func
1172nv50_disp_vblank_func = {
1173 .ctor = nouveau_disp_vblank_ctor,
1174 .init = nv50_disp_vblank_init,
1175 .fini = nv50_disp_vblank_fini,
1176};
1177
Ben Skeggs117e16332014-02-21 11:06:40 +10001178static const struct nouveau_enum
1179nv50_disp_intr_error_type[] = {
1180 { 3, "ILLEGAL_MTHD" },
1181 { 4, "INVALID_VALUE" },
1182 { 5, "INVALID_STATE" },
1183 { 7, "INVALID_HANDLE" },
1184 {}
1185};
1186
1187static const struct nouveau_enum
1188nv50_disp_intr_error_code[] = {
1189 { 0x00, "" },
1190 {}
1191};
1192
Ben Skeggsebb945a2012-07-20 08:17:34 +10001193static void
Ben Skeggs117e16332014-02-21 11:06:40 +10001194nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001195{
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001196 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs117e16332014-02-21 11:06:40 +10001197 u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
1198 u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
1199 u32 code = (addr & 0x00ff0000) >> 16;
1200 u32 type = (addr & 0x00007000) >> 12;
1201 u32 mthd = (addr & 0x00000ffc);
1202 const struct nouveau_enum *ec, *et;
1203 char ecunk[6], etunk[6];
Ben Skeggs186ecad2012-11-09 12:09:48 +10001204
Ben Skeggs117e16332014-02-21 11:06:40 +10001205 et = nouveau_enum_find(nv50_disp_intr_error_type, type);
1206 if (!et)
1207 snprintf(etunk, sizeof(etunk), "UNK%02X", type);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001208
Ben Skeggs117e16332014-02-21 11:06:40 +10001209 ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
1210 if (!ec)
1211 snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001212
Ben Skeggs117e16332014-02-21 11:06:40 +10001213 nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
1214 et ? et->name : etunk, ec ? ec->name : ecunk,
1215 chid, mthd, data);
1216
Ben Skeggs9cf6ba22014-02-20 23:26:18 +10001217 if (chid == 0) {
1218 switch (mthd) {
1219 case 0x0080:
1220 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
1221 impl->mthd.core);
1222 break;
1223 default:
1224 break;
1225 }
1226 } else
1227 if (chid <= 2) {
1228 switch (mthd) {
1229 case 0x0080:
1230 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
1231 impl->mthd.base);
1232 break;
1233 default:
1234 break;
1235 }
1236 } else
1237 if (chid <= 4) {
1238 switch (mthd) {
1239 case 0x0080:
1240 nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
1241 impl->mthd.ovly);
1242 break;
1243 default:
1244 break;
1245 }
1246 }
1247
Ben Skeggs117e16332014-02-21 11:06:40 +10001248 nv_wr32(priv, 0x610020, 0x00010000 << chid);
1249 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001250}
1251
Ben Skeggs415f12e2014-05-21 11:24:43 +10001252static struct nvkm_output *
1253exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
1254 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001255 struct nvbios_outp *info)
1256{
1257 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001258 struct nvkm_output *outp;
1259 u16 mask, type;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001260
Ben Skeggs415f12e2014-05-21 11:24:43 +10001261 if (or < 4) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001262 type = DCB_OUTPUT_ANALOG;
1263 mask = 0;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001264 } else
Ben Skeggs415f12e2014-05-21 11:24:43 +10001265 if (or < 8) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001266 switch (ctrl & 0x00000f00) {
1267 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
1268 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
1269 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
1270 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
1271 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
1272 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
1273 default:
1274 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001275 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001276 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001277 or -= 4;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001278 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001279 or = or - 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001280 type = 0x0010;
1281 mask = 0;
1282 switch (ctrl & 0x00000f00) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001283 case 0x00000000: type |= priv->pior.type[or]; break;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001284 default:
1285 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001286 return NULL;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001287 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001288 }
1289
1290 mask = 0x00c0 & (mask << 6);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001291 mask |= 0x0001 << or;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001292 mask |= 0x0100 << head;
1293
Ben Skeggs415f12e2014-05-21 11:24:43 +10001294 list_for_each_entry(outp, &priv->base.outp, head) {
1295 if ((outp->info.hasht & 0xff) == type &&
1296 (outp->info.hashm & mask) == mask) {
1297 *data = nvbios_outp_match(bios, outp->info.hasht,
1298 outp->info.hashm,
1299 ver, hdr, cnt, len, info);
1300 if (!*data)
1301 return NULL;
1302 return outp;
1303 }
1304 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001305
Ben Skeggs415f12e2014-05-21 11:24:43 +10001306 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001307}
1308
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001309static struct nvkm_output *
Ben Skeggs186ecad2012-11-09 12:09:48 +10001310exec_script(struct nv50_disp_priv *priv, int head, int id)
1311{
1312 struct nouveau_bios *bios = nouveau_bios(priv);
Ben Skeggs415f12e2014-05-21 11:24:43 +10001313 struct nvkm_output *outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001314 struct nvbios_outp info;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001315 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001316 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001317 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001318 int i;
1319
Ben Skeggs476e84e2013-02-11 09:24:23 +10001320 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001321 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001322 ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
1323
Ben Skeggs476e84e2013-02-11 09:24:23 +10001324 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001325 if (!(ctrl & (1 << head))) {
1326 if (nv_device(priv)->chipset < 0x90 ||
1327 nv_device(priv)->chipset == 0x92 ||
1328 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001329 reg = 0x610b74;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001330 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001331 reg = 0x610798;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001332 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001333 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1334 ctrl = nv_rd32(priv, reg + (i * 8));
1335 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001336 }
1337
Ben Skeggs476e84e2013-02-11 09:24:23 +10001338 /* PIOR */
1339 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001340 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001341 ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
1342 i += 8;
1343 }
1344
Ben Skeggs186ecad2012-11-09 12:09:48 +10001345 if (!(ctrl & (1 << head)))
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001346 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001347 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001348
Ben Skeggs415f12e2014-05-21 11:24:43 +10001349 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
1350 if (outp) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001351 struct nvbios_init init = {
1352 .subdev = nv_subdev(priv),
1353 .bios = bios,
1354 .offset = info.script[id],
Ben Skeggs415f12e2014-05-21 11:24:43 +10001355 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001356 .crtc = head,
1357 .execute = 1,
1358 };
1359
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001360 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001361 }
1362
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001363 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001364}
1365
Ben Skeggs415f12e2014-05-21 11:24:43 +10001366static struct nvkm_output *
1367exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001368{
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 info1;
1372 struct nvbios_ocfg info2;
1373 u8 ver, hdr, cnt, len;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001374 u32 data, ctrl = 0;
Emil Velikovb969fa52013-07-30 01:01:10 +01001375 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001376 int i;
1377
Ben Skeggs476e84e2013-02-11 09:24:23 +10001378 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +01001379 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001380 ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
1381
Ben Skeggs476e84e2013-02-11 09:24:23 +10001382 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001383 if (!(ctrl & (1 << head))) {
1384 if (nv_device(priv)->chipset < 0x90 ||
1385 nv_device(priv)->chipset == 0x92 ||
1386 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001387 reg = 0x610b70;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001388 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +01001389 reg = 0x610794;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001390 }
Emil Velikovb969fa52013-07-30 01:01:10 +01001391 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
1392 ctrl = nv_rd32(priv, reg + (i * 8));
1393 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001394 }
1395
Ben Skeggs476e84e2013-02-11 09:24:23 +10001396 /* PIOR */
1397 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +01001398 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +10001399 ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
1400 i += 8;
1401 }
1402
Ben Skeggs186ecad2012-11-09 12:09:48 +10001403 if (!(ctrl & (1 << head)))
Ben Skeggs415f12e2014-05-21 11:24:43 +10001404 return NULL;
Marcin Slusarzc684cef2013-01-03 19:38:45 +01001405 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001406
Ben Skeggs415f12e2014-05-21 11:24:43 +10001407 outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
Ben Skeggsba5e01b2014-06-17 09:39:18 +10001408 if (!outp)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001409 return NULL;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001410
Ben Skeggs415f12e2014-05-21 11:24:43 +10001411 if (outp->info.location == 0) {
1412 switch (outp->info.type) {
Ben Skeggs476e84e2013-02-11 09:24:23 +10001413 case DCB_OUTPUT_TMDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001414 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001415 if (pclk >= 165000)
Ben Skeggs415f12e2014-05-21 11:24:43 +10001416 *conf |= 0x0100;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001417 break;
1418 case DCB_OUTPUT_LVDS:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001419 *conf = priv->sor.lvdsconf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001420 break;
1421 case DCB_OUTPUT_DP:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001422 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001423 break;
1424 case DCB_OUTPUT_ANALOG:
1425 default:
Ben Skeggs415f12e2014-05-21 11:24:43 +10001426 *conf = 0x00ff;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001427 break;
1428 }
1429 } else {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001430 *conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001431 pclk = pclk / 2;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001432 }
1433
Ben Skeggs415f12e2014-05-21 11:24:43 +10001434 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001435 if (data && id < 0xff) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001436 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1437 if (data) {
1438 struct nvbios_init init = {
1439 .subdev = nv_subdev(priv),
1440 .bios = bios,
1441 .offset = data,
Ben Skeggs415f12e2014-05-21 11:24:43 +10001442 .outp = &outp->info,
Ben Skeggs186ecad2012-11-09 12:09:48 +10001443 .crtc = head,
1444 .execute = 1,
1445 };
1446
Ben Skeggs46c13c12013-02-16 13:49:21 +10001447 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001448 }
1449 }
1450
Ben Skeggs415f12e2014-05-21 11:24:43 +10001451 return outp;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001452}
1453
1454static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001455nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001456{
Ben Skeggs16d4c032013-02-20 18:56:33 +10001457 exec_script(priv, head, 1);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001458}
1459
1460static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001461nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
1462{
Ben Skeggs1ae5a622014-06-11 13:06:48 +10001463 struct nvkm_output *outp = exec_script(priv, head, 2);
1464
1465 /* the binary driver does this outside of the supervisor handling
1466 * (after the third supervisor from a detach). we (currently?)
1467 * allow both detach/attach to happen in the same set of
1468 * supervisor interrupts, so it would make sense to execute this
1469 * (full power down?) script after all the detach phases of the
1470 * supervisor handling. like with training if needed from the
1471 * second supervisor, nvidia doesn't do this, so who knows if it's
1472 * entirely safe, but it does appear to work..
1473 *
1474 * without this script being run, on some configurations i've
1475 * seen, switching from DP to TMDS on a DP connector may result
1476 * in a blank screen (SOR_PWR off/on can restore it)
1477 */
1478 if (outp && outp->info.type == DCB_OUTPUT_DP) {
1479 struct nvkm_output_dp *outpdp = (void *)outp;
1480 struct nvbios_init init = {
1481 .subdev = nv_subdev(priv),
1482 .bios = nouveau_bios(priv),
1483 .outp = &outp->info,
1484 .crtc = head,
1485 .offset = outpdp->info.script[4],
1486 .execute = 1,
1487 };
1488
1489 nvbios_exec(&init);
1490 atomic_set(&outpdp->lt.done, 0);
1491 }
Ben Skeggs16d4c032013-02-20 18:56:33 +10001492}
1493
1494static void
1495nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
1496{
Ben Skeggs88524bc2013-03-05 10:53:54 +10001497 struct nouveau_devinit *devinit = nouveau_devinit(priv);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001498 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1499 if (pclk)
Ben Skeggs88524bc2013-03-05 10:53:54 +10001500 devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001501}
1502
1503static void
1504nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
1505 struct dcb_output *outp, u32 pclk)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001506{
1507 const int link = !(outp->sorconf.link & 1);
1508 const int or = ffs(outp->or) - 1;
1509 const u32 soff = ( or * 0x800);
1510 const u32 loff = (link * 0x080) + soff;
1511 const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
Ben Skeggs186ecad2012-11-09 12:09:48 +10001512 const u32 symbol = 100000;
1513 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
1514 u32 clksor = nv_rd32(priv, 0x614300 + soff);
1515 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
1516 int TU, VTUi, VTUf, VTUa;
1517 u64 link_data_rate, link_ratio, unk;
1518 u32 best_diff = 64 * symbol;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001519 u32 link_nr, link_bw, bits, r;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001520
1521 /* calculate packed data rate for each lane */
1522 if (dpctrl > 0x00030000) link_nr = 4;
1523 else if (dpctrl > 0x00010000) link_nr = 2;
1524 else link_nr = 1;
1525
1526 if (clksor & 0x000c0000)
1527 link_bw = 270000;
1528 else
1529 link_bw = 162000;
1530
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001531 if ((ctrl & 0xf0000) == 0x60000) bits = 30;
1532 else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
1533 else bits = 18;
1534
Ben Skeggs186ecad2012-11-09 12:09:48 +10001535 link_data_rate = (pclk * bits / 8) / link_nr;
1536
1537 /* calculate ratio of packed data rate to link symbol rate */
1538 link_ratio = link_data_rate * symbol;
1539 r = do_div(link_ratio, link_bw);
1540
1541 for (TU = 64; TU >= 32; TU--) {
1542 /* calculate average number of valid symbols in each TU */
1543 u32 tu_valid = link_ratio * TU;
1544 u32 calc, diff;
1545
1546 /* find a hw representation for the fraction.. */
1547 VTUi = tu_valid / symbol;
1548 calc = VTUi * symbol;
1549 diff = tu_valid - calc;
1550 if (diff) {
1551 if (diff >= (symbol / 2)) {
1552 VTUf = symbol / (symbol - diff);
1553 if (symbol - (VTUf * diff))
1554 VTUf++;
1555
1556 if (VTUf <= 15) {
1557 VTUa = 1;
1558 calc += symbol - (symbol / VTUf);
1559 } else {
1560 VTUa = 0;
1561 VTUf = 1;
1562 calc += symbol;
1563 }
1564 } else {
1565 VTUa = 0;
1566 VTUf = min((int)(symbol / diff), 15);
1567 calc += symbol / VTUf;
1568 }
1569
1570 diff = calc - tu_valid;
1571 } else {
1572 /* no remainder, but the hw doesn't like the fractional
1573 * part to be zero. decrement the integer part and
1574 * have the fraction add a whole symbol back
1575 */
1576 VTUa = 0;
1577 VTUf = 1;
1578 VTUi--;
1579 }
1580
1581 if (diff < best_diff) {
1582 best_diff = diff;
1583 bestTU = TU;
1584 bestVTUa = VTUa;
1585 bestVTUf = VTUf;
1586 bestVTUi = VTUi;
1587 if (diff == 0)
1588 break;
1589 }
1590 }
1591
1592 if (!bestTU) {
1593 nv_error(priv, "unable to find suitable dp config\n");
1594 return;
1595 }
1596
1597 /* XXX close to vbios numbers, but not right */
1598 unk = (symbol - link_ratio) * bestTU;
1599 unk *= link_ratio;
1600 r = do_div(unk, symbol);
1601 r = do_div(unk, symbol);
1602 unk += 6;
1603
1604 nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
1605 nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
1606 bestVTUf << 16 |
1607 bestVTUi << 8 | unk);
1608}
1609
1610static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001611nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001612{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001613 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001614 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1615 u32 hval, hreg = 0x614200 + (head * 0x800);
1616 u32 oval, oreg;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001617 u32 mask, conf;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001618
Ben Skeggs415f12e2014-05-21 11:24:43 +10001619 outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
1620 if (!outp)
1621 return;
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001622
Ben Skeggs55f083c2014-05-20 10:18:03 +10001623 /* we allow both encoder attach and detach operations to occur
1624 * within a single supervisor (ie. modeset) sequence. the
1625 * encoder detach scripts quite often switch off power to the
1626 * lanes, which requires the link to be re-trained.
1627 *
1628 * this is not generally an issue as the sink "must" (heh)
1629 * signal an irq when it's lost sync so the driver can
1630 * re-train.
1631 *
1632 * however, on some boards, if one does not configure at least
1633 * the gpu side of the link *before* attaching, then various
1634 * things can go horribly wrong (PDISP disappearing from mmio,
1635 * third supervisor never happens, etc).
1636 *
1637 * the solution is simply to retrain here, if necessary. last
1638 * i checked, the binary driver userspace does not appear to
1639 * trigger this situation (it forces an UPDATE between steps).
1640 */
Ben Skeggsb17932c2014-05-27 15:00:36 +10001641 if (outp->info.type == DCB_OUTPUT_DP) {
Ben Skeggs415f12e2014-05-21 11:24:43 +10001642 u32 soff = (ffs(outp->info.or) - 1) * 0x08;
Ben Skeggsb17932c2014-05-27 15:00:36 +10001643 u32 ctrl, datarate;
1644
1645 if (outp->info.location == 0) {
1646 ctrl = nv_rd32(priv, 0x610794 + soff);
1647 soff = 1;
1648 } else {
1649 ctrl = nv_rd32(priv, 0x610b80 + soff);
1650 soff = 2;
1651 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001652
1653 switch ((ctrl & 0x000f0000) >> 16) {
Ben Skeggs0713b452014-07-01 10:54:52 +10001654 case 6: datarate = pclk * 30; break;
1655 case 5: datarate = pclk * 24; break;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001656 case 2:
1657 default:
Ben Skeggs0713b452014-07-01 10:54:52 +10001658 datarate = pclk * 18;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001659 break;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001660 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001661
Ben Skeggs55f083c2014-05-20 10:18:03 +10001662 if (nvkm_output_dp_train(outp, datarate / soff, true))
1663 ERR("link not trained before attach\n");
Ben Skeggs16d4c032013-02-20 18:56:33 +10001664 }
Ben Skeggs415f12e2014-05-21 11:24:43 +10001665
1666 exec_clkcmp(priv, head, 0, pclk, &conf);
1667
1668 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
1669 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
1670 oval = 0x00000000;
1671 hval = 0x00000000;
1672 mask = 0xffffffff;
1673 } else
1674 if (!outp->info.location) {
1675 if (outp->info.type == DCB_OUTPUT_DP)
1676 nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
1677 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
1678 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1679 hval = 0x00000000;
1680 mask = 0x00000707;
1681 } else {
1682 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
1683 oval = 0x00000001;
1684 hval = 0x00000001;
1685 mask = 0x00000707;
1686 }
1687
1688 nv_mask(priv, hreg, 0x0000000f, hval);
1689 nv_mask(priv, oreg, mask, oval);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001690}
1691
1692/* If programming a TMDS output on a SOR that can also be configured for
1693 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
1694 *
1695 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
1696 * the VBIOS scripts on at least one board I have only switch it off on
1697 * link 0, causing a blank display if the output has previously been
1698 * programmed for DisplayPort.
1699 */
1700static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001701nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001702{
1703 struct nouveau_bios *bios = nouveau_bios(priv);
1704 const int link = !(outp->sorconf.link & 1);
1705 const int or = ffs(outp->or) - 1;
1706 const u32 loff = (or * 0x800) + (link * 0x80);
1707 const u16 mask = (outp->sorconf.link << 6) | outp->or;
1708 u8 ver, hdr;
1709
1710 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
1711 nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
1712}
1713
1714static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001715nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001716{
Ben Skeggs415f12e2014-05-21 11:24:43 +10001717 struct nvkm_output *outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001718 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
Ben Skeggs415f12e2014-05-21 11:24:43 +10001719 u32 conf;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001720
Ben Skeggs415f12e2014-05-21 11:24:43 +10001721 outp = exec_clkcmp(priv, head, 1, pclk, &conf);
1722 if (!outp)
1723 return;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001724
Ben Skeggs415f12e2014-05-21 11:24:43 +10001725 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
1726 nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001727}
1728
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001729void
1730nv50_disp_intr_supervisor(struct work_struct *work)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001731{
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001732 struct nv50_disp_priv *priv =
1733 container_of(work, struct nv50_disp_priv, supervisor);
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001734 struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001735 u32 super = nv_rd32(priv, 0x610030);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001736 int head;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001737
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001738 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001739
Ben Skeggs16d4c032013-02-20 18:56:33 +10001740 if (priv->super & 0x00000010) {
Ben Skeggsb62b9ec2014-02-20 23:19:58 +10001741 nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001742 for (head = 0; head < priv->head.nr; head++) {
1743 if (!(super & (0x00000020 << head)))
1744 continue;
1745 if (!(super & (0x00000080 << head)))
1746 continue;
1747 nv50_disp_intr_unk10_0(priv, head);
1748 }
1749 } else
1750 if (priv->super & 0x00000020) {
1751 for (head = 0; head < priv->head.nr; head++) {
1752 if (!(super & (0x00000080 << head)))
1753 continue;
1754 nv50_disp_intr_unk20_0(priv, head);
1755 }
1756 for (head = 0; head < priv->head.nr; head++) {
1757 if (!(super & (0x00000200 << head)))
1758 continue;
1759 nv50_disp_intr_unk20_1(priv, head);
1760 }
1761 for (head = 0; head < priv->head.nr; head++) {
1762 if (!(super & (0x00000080 << head)))
1763 continue;
1764 nv50_disp_intr_unk20_2(priv, head);
1765 }
1766 } else
1767 if (priv->super & 0x00000040) {
1768 for (head = 0; head < priv->head.nr; head++) {
1769 if (!(super & (0x00000080 << head)))
1770 continue;
1771 nv50_disp_intr_unk40_0(priv, head);
1772 }
1773 }
1774
1775 nv_wr32(priv, 0x610030, 0x80000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001776}
1777
Ben Skeggs70cabe42012-08-14 10:04:04 +10001778void
Ben Skeggsebb945a2012-07-20 08:17:34 +10001779nv50_disp_intr(struct nouveau_subdev *subdev)
1780{
1781 struct nv50_disp_priv *priv = (void *)subdev;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001782 u32 intr0 = nv_rd32(priv, 0x610020);
1783 u32 intr1 = nv_rd32(priv, 0x610024);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001784
Ben Skeggs117e16332014-02-21 11:06:40 +10001785 while (intr0 & 0x001f0000) {
1786 u32 chid = __ffs(intr0 & 0x001f0000) - 16;
1787 nv50_disp_intr_error(priv, chid);
1788 intr0 &= ~(0x00010000 << chid);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001789 }
1790
1791 if (intr1 & 0x00000004) {
Ben Skeggs79ca2772014-08-10 04:10:20 +10001792 nouveau_disp_vblank(&priv->base, 0);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001793 nv_wr32(priv, 0x610024, 0x00000004);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001794 intr1 &= ~0x00000004;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001795 }
1796
Ben Skeggs186ecad2012-11-09 12:09:48 +10001797 if (intr1 & 0x00000008) {
Ben Skeggs79ca2772014-08-10 04:10:20 +10001798 nouveau_disp_vblank(&priv->base, 1);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001799 nv_wr32(priv, 0x610024, 0x00000008);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001800 intr1 &= ~0x00000008;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001801 }
1802
Ben Skeggs186ecad2012-11-09 12:09:48 +10001803 if (intr1 & 0x00000070) {
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001804 priv->super = (intr1 & 0x00000070);
1805 schedule_work(&priv->supervisor);
1806 nv_wr32(priv, 0x610024, priv->super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001807 intr1 &= ~0x00000070;
1808 }
Ben Skeggsebb945a2012-07-20 08:17:34 +10001809}
1810
1811static int
1812nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
Ben Skeggs370c00f2012-08-14 14:11:49 +10001813 struct nouveau_oclass *oclass, void *data, u32 size,
1814 struct nouveau_object **pobject)
Ben Skeggsebb945a2012-07-20 08:17:34 +10001815{
1816 struct nv50_disp_priv *priv;
1817 int ret;
1818
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001819 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
Ben Skeggsebb945a2012-07-20 08:17:34 +10001820 "display", &priv);
1821 *pobject = nv_object(priv);
1822 if (ret)
1823 return ret;
1824
Ben Skeggs70cabe42012-08-14 10:04:04 +10001825 nv_engine(priv)->sclass = nv50_disp_base_oclass;
1826 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001827 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001828 INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001829 priv->sclass = nv50_disp_sclass;
1830 priv->head.nr = 2;
1831 priv->dac.nr = 3;
1832 priv->sor.nr = 2;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001833 priv->pior.nr = 3;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001834 priv->dac.power = nv50_dac_power;
Ben Skeggs7ebb38b2012-11-09 09:38:06 +10001835 priv->dac.sense = nv50_dac_sense;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001836 priv->sor.power = nv50_sor_power;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001837 priv->pior.power = nv50_pior_power;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001838 return 0;
1839}
1840
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001841struct nouveau_oclass *
Ben Skeggsb8407c92014-05-17 11:19:54 +10001842nv50_disp_outp_sclass[] = {
1843 &nv50_pior_dp_impl.base.base,
1844 NULL
1845};
1846
1847struct nouveau_oclass *
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001848nv50_disp_oclass = &(struct nv50_disp_impl) {
1849 .base.base.handle = NV_ENGINE(DISP, 0x50),
1850 .base.base.ofuncs = &(struct nouveau_ofuncs) {
Ben Skeggsebb945a2012-07-20 08:17:34 +10001851 .ctor = nv50_disp_ctor,
1852 .dtor = _nouveau_disp_dtor,
1853 .init = _nouveau_disp_init,
1854 .fini = _nouveau_disp_fini,
1855 },
Ben Skeggs79ca2772014-08-10 04:10:20 +10001856 .base.vblank = &nv50_disp_vblank_func,
Ben Skeggsb8407c92014-05-17 11:19:54 +10001857 .base.outp = nv50_disp_outp_sclass,
Ben Skeggsd67d92c2014-02-20 15:14:10 +10001858 .mthd.core = &nv50_disp_mast_mthd_chan,
1859 .mthd.base = &nv50_disp_sync_mthd_chan,
1860 .mthd.ovly = &nv50_disp_ovly_mthd_chan,
1861 .mthd.prev = 0x000004,
Ben Skeggs4952b4d2014-08-10 04:10:27 +10001862 .head.scanoutpos = nv50_disp_base_scanoutpos,
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001863}.base.base;