blob: 867852bd036f505c03d461ec6593294d185cb2de [file] [log] [blame]
Ben Skeggsebb945a2012-07-20 08:17:34 +10001/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
Ben Skeggs370c00f2012-08-14 14:11:49 +100025#include <core/object.h>
26#include <core/parent.h>
27#include <core/handle.h>
28#include <core/class.h>
Ben Skeggs117e16332014-02-21 11:06:40 +100029#include <core/enum.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100030
Ben Skeggs186ecad2012-11-09 12:09:48 +100031#include <subdev/bios.h>
32#include <subdev/bios/dcb.h>
33#include <subdev/bios/disp.h>
34#include <subdev/bios/init.h>
35#include <subdev/bios/pll.h>
Ben Skeggs88524bc2013-03-05 10:53:54 +100036#include <subdev/devinit.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100037#include <subdev/timer.h>
Ben Skeggs370c00f2012-08-14 14:11:49 +100038#include <subdev/fb.h>
Ben Skeggs446b05a2012-08-14 12:50:14 +100039
Ben Skeggs70cabe42012-08-14 10:04:04 +100040#include "nv50.h"
41
42/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +100043 * EVO channel base class
Ben Skeggs70cabe42012-08-14 10:04:04 +100044 ******************************************************************************/
45
Ben Skeggs370c00f2012-08-14 14:11:49 +100046int
47nv50_disp_chan_create_(struct nouveau_object *parent,
48 struct nouveau_object *engine,
49 struct nouveau_oclass *oclass, int chid,
50 int length, void **pobject)
51{
52 struct nv50_disp_base *base = (void *)parent;
53 struct nv50_disp_chan *chan;
54 int ret;
55
56 if (base->chan & (1 << chid))
57 return -EBUSY;
58 base->chan |= (1 << chid);
59
60 ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
61 (1ULL << NVDEV_ENGINE_DMAOBJ),
62 length, pobject);
63 chan = *pobject;
64 if (ret)
65 return ret;
66
67 chan->chid = chid;
68 return 0;
69}
70
71void
72nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
73{
74 struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
75 base->chan &= ~(1 << chan->chid);
76 nouveau_namedb_destroy(&chan->base);
77}
78
79u32
Ben Skeggs70cabe42012-08-14 10:04:04 +100080nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
81{
Ben Skeggs370c00f2012-08-14 14:11:49 +100082 struct nv50_disp_priv *priv = (void *)object->engine;
83 struct nv50_disp_chan *chan = (void *)object;
84 return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
85}
86
87void
88nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
89{
90 struct nv50_disp_priv *priv = (void *)object->engine;
91 struct nv50_disp_chan *chan = (void *)object;
92 nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
93}
94
95/*******************************************************************************
96 * EVO DMA channel base class
97 ******************************************************************************/
98
99static int
100nv50_disp_dmac_object_attach(struct nouveau_object *parent,
101 struct nouveau_object *object, u32 name)
102{
103 struct nv50_disp_base *base = (void *)parent->parent;
104 struct nv50_disp_chan *chan = (void *)parent;
105 u32 addr = nv_gpuobj(object)->node->offset;
106 u32 chid = chan->chid;
107 u32 data = (chid << 28) | (addr << 10) | chid;
108 return nouveau_ramht_insert(base->ramht, chid, name, data);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000109}
110
111static void
Ben Skeggs370c00f2012-08-14 14:11:49 +1000112nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
Ben Skeggs70cabe42012-08-14 10:04:04 +1000113{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000114 struct nv50_disp_base *base = (void *)parent->parent;
115 nouveau_ramht_remove(base->ramht, cookie);
116}
117
118int
119nv50_disp_dmac_create_(struct nouveau_object *parent,
120 struct nouveau_object *engine,
121 struct nouveau_oclass *oclass, u32 pushbuf, int chid,
122 int length, void **pobject)
123{
124 struct nv50_disp_dmac *dmac;
125 int ret;
126
127 ret = nv50_disp_chan_create_(parent, engine, oclass, chid,
128 length, pobject);
129 dmac = *pobject;
130 if (ret)
131 return ret;
132
133 dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
134 if (!dmac->pushdma)
135 return -ENOENT;
136
137 switch (nv_mclass(dmac->pushdma)) {
138 case 0x0002:
139 case 0x003d:
140 if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
141 return -EINVAL;
142
143 switch (dmac->pushdma->target) {
144 case NV_MEM_TARGET_VRAM:
145 dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
146 break;
Ben Skeggs944234d2012-10-30 10:03:38 +1000147 case NV_MEM_TARGET_PCI_NOSNOOP:
148 dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
149 break;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000150 default:
151 return -EINVAL;
152 }
153 break;
154 default:
155 return -EINVAL;
156 }
157
158 return 0;
159}
160
161void
162nv50_disp_dmac_dtor(struct nouveau_object *object)
163{
164 struct nv50_disp_dmac *dmac = (void *)object;
165 nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
166 nv50_disp_chan_destroy(&dmac->base);
167}
168
169static int
170nv50_disp_dmac_init(struct nouveau_object *object)
171{
172 struct nv50_disp_priv *priv = (void *)object->engine;
173 struct nv50_disp_dmac *dmac = (void *)object;
174 int chid = dmac->base.chid;
175 int ret;
176
177 ret = nv50_disp_chan_init(&dmac->base);
178 if (ret)
179 return ret;
180
181 /* enable error reporting */
182 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
183
184 /* initialise channel for dma command submission */
185 nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
186 nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
187 nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
188 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
189 nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
190 nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
191
192 /* wait for it to go inactive */
193 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
194 nv_error(dmac, "init timeout, 0x%08x\n",
195 nv_rd32(priv, 0x610200 + (chid * 0x10)));
196 return -EBUSY;
197 }
198
199 return 0;
200}
201
202static int
203nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
204{
205 struct nv50_disp_priv *priv = (void *)object->engine;
206 struct nv50_disp_dmac *dmac = (void *)object;
207 int chid = dmac->base.chid;
208
209 /* deactivate channel */
210 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
211 nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
212 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
213 nv_error(dmac, "fini timeout, 0x%08x\n",
214 nv_rd32(priv, 0x610200 + (chid * 0x10)));
215 if (suspend)
216 return -EBUSY;
217 }
218
219 /* disable error reporting */
220 nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
221
222 return nv50_disp_chan_fini(&dmac->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000223}
224
225/*******************************************************************************
226 * EVO master channel object
227 ******************************************************************************/
228
229static int
230nv50_disp_mast_ctor(struct nouveau_object *parent,
231 struct nouveau_object *engine,
232 struct nouveau_oclass *oclass, void *data, u32 size,
233 struct nouveau_object **pobject)
234{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000235 struct nv50_display_mast_class *args = data;
236 struct nv50_disp_dmac *mast;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000237 int ret;
238
Ben Skeggs370c00f2012-08-14 14:11:49 +1000239 if (size < sizeof(*args))
240 return -EINVAL;
241
242 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
243 0, sizeof(*mast), (void **)&mast);
244 *pobject = nv_object(mast);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000245 if (ret)
246 return ret;
247
Ben Skeggs370c00f2012-08-14 14:11:49 +1000248 nv_parent(mast)->object_attach = nv50_disp_dmac_object_attach;
249 nv_parent(mast)->object_detach = nv50_disp_dmac_object_detach;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000250 return 0;
251}
252
Ben Skeggs70cabe42012-08-14 10:04:04 +1000253static int
254nv50_disp_mast_init(struct nouveau_object *object)
255{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000256 struct nv50_disp_priv *priv = (void *)object->engine;
257 struct nv50_disp_dmac *mast = (void *)object;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000258 int ret;
259
Ben Skeggs370c00f2012-08-14 14:11:49 +1000260 ret = nv50_disp_chan_init(&mast->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000261 if (ret)
262 return ret;
263
Ben Skeggs370c00f2012-08-14 14:11:49 +1000264 /* enable error reporting */
265 nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
266
267 /* attempt to unstick channel from some unknown state */
268 if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
269 nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
270 if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
271 nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
272
273 /* initialise channel for dma command submission */
274 nv_wr32(priv, 0x610204, mast->push);
275 nv_wr32(priv, 0x610208, 0x00010000);
276 nv_wr32(priv, 0x61020c, 0x00000000);
277 nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
278 nv_wr32(priv, 0x640000, 0x00000000);
279 nv_wr32(priv, 0x610200, 0x01000013);
280
281 /* wait for it to go inactive */
282 if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
283 nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
284 return -EBUSY;
285 }
286
Ben Skeggs70cabe42012-08-14 10:04:04 +1000287 return 0;
288}
289
290static int
291nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
292{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000293 struct nv50_disp_priv *priv = (void *)object->engine;
294 struct nv50_disp_dmac *mast = (void *)object;
295
296 /* deactivate channel */
297 nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
298 nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
299 if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
300 nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
301 if (suspend)
302 return -EBUSY;
303 }
304
305 /* disable error reporting */
306 nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
307
308 return nv50_disp_chan_fini(&mast->base, suspend);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000309}
310
311struct nouveau_ofuncs
312nv50_disp_mast_ofuncs = {
313 .ctor = nv50_disp_mast_ctor,
Ben Skeggs370c00f2012-08-14 14:11:49 +1000314 .dtor = nv50_disp_dmac_dtor,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000315 .init = nv50_disp_mast_init,
316 .fini = nv50_disp_mast_fini,
317 .rd32 = nv50_disp_chan_rd32,
318 .wr32 = nv50_disp_chan_wr32,
319};
320
321/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000322 * EVO sync channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000323 ******************************************************************************/
324
325static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000326nv50_disp_sync_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000327 struct nouveau_object *engine,
328 struct nouveau_oclass *oclass, void *data, u32 size,
329 struct nouveau_object **pobject)
330{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000331 struct nv50_display_sync_class *args = data;
332 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000333 int ret;
334
Dan Carpenteraf1ac182013-01-23 11:27:56 +0300335 if (size < sizeof(*args) || args->head > 1)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000336 return -EINVAL;
337
338 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
339 1 + args->head, sizeof(*dmac),
340 (void **)&dmac);
341 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000342 if (ret)
343 return ret;
344
Ben Skeggs370c00f2012-08-14 14:11:49 +1000345 nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
346 nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000347 return 0;
348}
349
Ben Skeggs70cabe42012-08-14 10:04:04 +1000350struct nouveau_ofuncs
Ben Skeggs370c00f2012-08-14 14:11:49 +1000351nv50_disp_sync_ofuncs = {
352 .ctor = nv50_disp_sync_ctor,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000353 .dtor = nv50_disp_dmac_dtor,
354 .init = nv50_disp_dmac_init,
355 .fini = nv50_disp_dmac_fini,
356 .rd32 = nv50_disp_chan_rd32,
357 .wr32 = nv50_disp_chan_wr32,
358};
359
360/*******************************************************************************
Ben Skeggs370c00f2012-08-14 14:11:49 +1000361 * EVO overlay channel objects
Ben Skeggs70cabe42012-08-14 10:04:04 +1000362 ******************************************************************************/
363
364static int
Ben Skeggs370c00f2012-08-14 14:11:49 +1000365nv50_disp_ovly_ctor(struct nouveau_object *parent,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000366 struct nouveau_object *engine,
367 struct nouveau_oclass *oclass, void *data, u32 size,
368 struct nouveau_object **pobject)
369{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000370 struct nv50_display_ovly_class *args = data;
371 struct nv50_disp_dmac *dmac;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000372 int ret;
373
Dan Carpenteraf1ac182013-01-23 11:27:56 +0300374 if (size < sizeof(*args) || args->head > 1)
Ben Skeggs370c00f2012-08-14 14:11:49 +1000375 return -EINVAL;
376
377 ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
378 3 + args->head, sizeof(*dmac),
379 (void **)&dmac);
380 *pobject = nv_object(dmac);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000381 if (ret)
382 return ret;
383
Ben Skeggs370c00f2012-08-14 14:11:49 +1000384 nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
385 nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000386 return 0;
387}
388
Ben Skeggs370c00f2012-08-14 14:11:49 +1000389struct nouveau_ofuncs
390nv50_disp_ovly_ofuncs = {
391 .ctor = nv50_disp_ovly_ctor,
392 .dtor = nv50_disp_dmac_dtor,
393 .init = nv50_disp_dmac_init,
394 .fini = nv50_disp_dmac_fini,
395 .rd32 = nv50_disp_chan_rd32,
396 .wr32 = nv50_disp_chan_wr32,
397};
398
399/*******************************************************************************
400 * EVO PIO channel base class
401 ******************************************************************************/
402
403static int
404nv50_disp_pioc_create_(struct nouveau_object *parent,
405 struct nouveau_object *engine,
406 struct nouveau_oclass *oclass, int chid,
407 int length, void **pobject)
408{
409 return nv50_disp_chan_create_(parent, engine, oclass, chid,
410 length, pobject);
411}
412
Ben Skeggs70cabe42012-08-14 10:04:04 +1000413static void
414nv50_disp_pioc_dtor(struct nouveau_object *object)
415{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000416 struct nv50_disp_pioc *pioc = (void *)object;
417 nv50_disp_chan_destroy(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000418}
419
420static int
421nv50_disp_pioc_init(struct nouveau_object *object)
422{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000423 struct nv50_disp_priv *priv = (void *)object->engine;
424 struct nv50_disp_pioc *pioc = (void *)object;
425 int chid = pioc->base.chid;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000426 int ret;
427
Ben Skeggs370c00f2012-08-14 14:11:49 +1000428 ret = nv50_disp_chan_init(&pioc->base);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000429 if (ret)
430 return ret;
431
Ben Skeggs370c00f2012-08-14 14:11:49 +1000432 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
433 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
434 nv_error(pioc, "timeout0: 0x%08x\n",
435 nv_rd32(priv, 0x610200 + (chid * 0x10)));
436 return -EBUSY;
437 }
438
439 nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
440 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
441 nv_error(pioc, "timeout1: 0x%08x\n",
442 nv_rd32(priv, 0x610200 + (chid * 0x10)));
443 return -EBUSY;
444 }
445
Ben Skeggs70cabe42012-08-14 10:04:04 +1000446 return 0;
447}
448
449static int
450nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
451{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000452 struct nv50_disp_priv *priv = (void *)object->engine;
453 struct nv50_disp_pioc *pioc = (void *)object;
454 int chid = pioc->base.chid;
455
456 nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
457 if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
458 nv_error(pioc, "timeout: 0x%08x\n",
459 nv_rd32(priv, 0x610200 + (chid * 0x10)));
460 if (suspend)
461 return -EBUSY;
462 }
463
464 return nv50_disp_chan_fini(&pioc->base, suspend);
465}
466
467/*******************************************************************************
468 * EVO immediate overlay channel objects
469 ******************************************************************************/
470
471static int
472nv50_disp_oimm_ctor(struct nouveau_object *parent,
473 struct nouveau_object *engine,
474 struct nouveau_oclass *oclass, void *data, u32 size,
475 struct nouveau_object **pobject)
476{
477 struct nv50_display_oimm_class *args = data;
478 struct nv50_disp_pioc *pioc;
479 int ret;
480
481 if (size < sizeof(*args) || args->head > 1)
482 return -EINVAL;
483
484 ret = nv50_disp_pioc_create_(parent, engine, oclass, 5 + args->head,
485 sizeof(*pioc), (void **)&pioc);
486 *pobject = nv_object(pioc);
487 if (ret)
488 return ret;
489
490 return 0;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000491}
492
493struct nouveau_ofuncs
Ben Skeggs370c00f2012-08-14 14:11:49 +1000494nv50_disp_oimm_ofuncs = {
495 .ctor = nv50_disp_oimm_ctor,
496 .dtor = nv50_disp_pioc_dtor,
497 .init = nv50_disp_pioc_init,
498 .fini = nv50_disp_pioc_fini,
499 .rd32 = nv50_disp_chan_rd32,
500 .wr32 = nv50_disp_chan_wr32,
501};
502
503/*******************************************************************************
504 * EVO cursor channel objects
505 ******************************************************************************/
506
507static int
508nv50_disp_curs_ctor(struct nouveau_object *parent,
509 struct nouveau_object *engine,
510 struct nouveau_oclass *oclass, void *data, u32 size,
511 struct nouveau_object **pobject)
512{
513 struct nv50_display_curs_class *args = data;
514 struct nv50_disp_pioc *pioc;
515 int ret;
516
517 if (size < sizeof(*args) || args->head > 1)
518 return -EINVAL;
519
520 ret = nv50_disp_pioc_create_(parent, engine, oclass, 7 + args->head,
521 sizeof(*pioc), (void **)&pioc);
522 *pobject = nv_object(pioc);
523 if (ret)
524 return ret;
525
526 return 0;
527}
528
529struct nouveau_ofuncs
530nv50_disp_curs_ofuncs = {
531 .ctor = nv50_disp_curs_ctor,
Ben Skeggs70cabe42012-08-14 10:04:04 +1000532 .dtor = nv50_disp_pioc_dtor,
533 .init = nv50_disp_pioc_init,
534 .fini = nv50_disp_pioc_fini,
535 .rd32 = nv50_disp_chan_rd32,
536 .wr32 = nv50_disp_chan_wr32,
537};
538
539/*******************************************************************************
540 * Base display object
541 ******************************************************************************/
542
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000543int
544nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
545 void *data, u32 size)
546{
547 struct nv50_disp_priv *priv = (void *)object->engine;
548 struct nv04_display_scanoutpos *args = data;
549 const int head = (mthd & NV50_DISP_MTHD_HEAD);
550 u32 blanke, blanks, total;
551
552 if (size < sizeof(*args) || head >= priv->head.nr)
553 return -EINVAL;
554 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
555 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
556 total = nv_rd32(priv, 0x610afc + (head * 0x540));
557
558 args->vblanke = (blanke & 0xffff0000) >> 16;
559 args->hblanke = (blanke & 0x0000ffff);
560 args->vblanks = (blanks & 0xffff0000) >> 16;
561 args->hblanks = (blanks & 0x0000ffff);
562 args->vtotal = ( total & 0xffff0000) >> 16;
563 args->htotal = ( total & 0x0000ffff);
564
565 args->time[0] = ktime_to_ns(ktime_get());
566 args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
567 args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
568 args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
569 return 0;
570}
571
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000572static void
573nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
574{
Maarten Lankhorstc8f28f82013-03-05 14:59:26 +0100575 nv_mask(event->priv, 0x61002c, (4 << head), (4 << head));
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000576}
577
578static void
579nv50_disp_base_vblank_disable(struct nouveau_event *event, int head)
580{
Maarten Lankhorstc8f28f82013-03-05 14:59:26 +0100581 nv_mask(event->priv, 0x61002c, (4 << head), 0);
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000582}
583
Ben Skeggs70cabe42012-08-14 10:04:04 +1000584static int
585nv50_disp_base_ctor(struct nouveau_object *parent,
586 struct nouveau_object *engine,
587 struct nouveau_oclass *oclass, void *data, u32 size,
588 struct nouveau_object **pobject)
589{
590 struct nv50_disp_priv *priv = (void *)engine;
591 struct nv50_disp_base *base;
592 int ret;
593
594 ret = nouveau_parent_create(parent, engine, oclass, 0,
595 priv->sclass, 0, &base);
596 *pobject = nv_object(base);
597 if (ret)
598 return ret;
599
Ben Skeggs1d7c71a2013-01-31 09:23:34 +1000600 priv->base.vblank->priv = priv;
601 priv->base.vblank->enable = nv50_disp_base_vblank_enable;
602 priv->base.vblank->disable = nv50_disp_base_vblank_disable;
Ben Skeggs2ecda482013-04-24 18:04:22 +1000603 return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
604 &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000605}
606
607static void
608nv50_disp_base_dtor(struct nouveau_object *object)
609{
610 struct nv50_disp_base *base = (void *)object;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000611 nouveau_ramht_ref(NULL, &base->ramht);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000612 nouveau_parent_destroy(&base->base);
613}
614
615static int
616nv50_disp_base_init(struct nouveau_object *object)
617{
Ben Skeggsab772142012-08-14 11:29:57 +1000618 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000619 struct nv50_disp_base *base = (void *)object;
Ben Skeggsab772142012-08-14 11:29:57 +1000620 int ret, i;
621 u32 tmp;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000622
623 ret = nouveau_parent_init(&base->base);
624 if (ret)
625 return ret;
626
Ben Skeggsab772142012-08-14 11:29:57 +1000627 /* The below segments of code copying values from one register to
628 * another appear to inform EVO of the display capabilities or
629 * something similar. NFI what the 0x614004 caps are for..
630 */
631 tmp = nv_rd32(priv, 0x614004);
632 nv_wr32(priv, 0x610184, tmp);
633
634 /* ... CRTC caps */
635 for (i = 0; i < priv->head.nr; i++) {
636 tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
637 nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
638 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
639 nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
640 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
641 nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
642 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
643 nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
644 }
645
646 /* ... DAC caps */
647 for (i = 0; i < priv->dac.nr; i++) {
648 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
649 nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
650 }
651
652 /* ... SOR caps */
653 for (i = 0; i < priv->sor.nr; i++) {
654 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
655 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
656 }
657
Ben Skeggs476e84e2013-02-11 09:24:23 +1000658 /* ... PIOR caps */
Emil Velikovb969fa52013-07-30 01:01:10 +0100659 for (i = 0; i < priv->pior.nr; i++) {
Ben Skeggsab772142012-08-14 11:29:57 +1000660 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
661 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
662 }
663
Ben Skeggs446b05a2012-08-14 12:50:14 +1000664 /* steal display away from vbios, or something like that */
665 if (nv_rd32(priv, 0x610024) & 0x00000100) {
666 nv_wr32(priv, 0x610024, 0x00000100);
667 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
668 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
669 nv_error(priv, "timeout acquiring display\n");
670 return -EBUSY;
671 }
672 }
673
674 /* point at display engine memory area (hash table, objects) */
Ben Skeggs370c00f2012-08-14 14:11:49 +1000675 nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
Ben Skeggs446b05a2012-08-14 12:50:14 +1000676
677 /* enable supervisor interrupts, disable everything else */
Ben Skeggs370c00f2012-08-14 14:11:49 +1000678 nv_wr32(priv, 0x61002c, 0x00000370);
679 nv_wr32(priv, 0x610028, 0x00000000);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000680 return 0;
681}
682
683static int
684nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
685{
Ben Skeggs446b05a2012-08-14 12:50:14 +1000686 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000687 struct nv50_disp_base *base = (void *)object;
Ben Skeggs446b05a2012-08-14 12:50:14 +1000688
689 /* disable all interrupts */
690 nv_wr32(priv, 0x610024, 0x00000000);
691 nv_wr32(priv, 0x610020, 0x00000000);
692
Ben Skeggs70cabe42012-08-14 10:04:04 +1000693 return nouveau_parent_fini(&base->base, suspend);
694}
695
696struct nouveau_ofuncs
697nv50_disp_base_ofuncs = {
698 .ctor = nv50_disp_base_ctor,
699 .dtor = nv50_disp_base_dtor,
700 .init = nv50_disp_base_init,
701 .fini = nv50_disp_base_fini,
702};
703
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000704static struct nouveau_omthds
705nv50_disp_base_omthds[] = {
Ben Skeggsd2fa7d32013-11-14 13:37:48 +1000706 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000707 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
Ben Skeggs4a230fa2012-11-09 11:25:37 +1000708 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000709 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
710 { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
Ben Skeggsa2bc2832013-02-11 09:11:08 +1000711 { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
712 { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
713 { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000714 {},
715};
716
Ben Skeggs70cabe42012-08-14 10:04:04 +1000717static struct nouveau_oclass
718nv50_disp_base_oclass[] = {
Ben Skeggsef22c8b2012-11-09 09:32:56 +1000719 { NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds },
Ben Skeggs370c00f2012-08-14 14:11:49 +1000720 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000721};
722
723static struct nouveau_oclass
724nv50_disp_sclass[] = {
Ben Skeggs370c00f2012-08-14 14:11:49 +1000725 { NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
726 { NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
727 { NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
728 { NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
729 { NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
Ben Skeggs70cabe42012-08-14 10:04:04 +1000730 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000731};
732
Ben Skeggs70cabe42012-08-14 10:04:04 +1000733/*******************************************************************************
734 * Display context, tracks instmem allocation and prevents more than one
735 * client using the display hardware at any time.
736 ******************************************************************************/
737
738static int
739nv50_disp_data_ctor(struct nouveau_object *parent,
740 struct nouveau_object *engine,
741 struct nouveau_oclass *oclass, void *data, u32 size,
742 struct nouveau_object **pobject)
743{
Ben Skeggs370c00f2012-08-14 14:11:49 +1000744 struct nv50_disp_priv *priv = (void *)engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000745 struct nouveau_engctx *ectx;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000746 int ret = -EBUSY;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000747
Ben Skeggs370c00f2012-08-14 14:11:49 +1000748 /* no context needed for channel objects... */
749 if (nv_mclass(parent) != NV_DEVICE_CLASS) {
750 atomic_inc(&parent->refcount);
751 *pobject = parent;
Ben Skeggs43e6e512013-04-26 00:12:59 +1000752 return 1;
Ben Skeggs370c00f2012-08-14 14:11:49 +1000753 }
Ben Skeggs70cabe42012-08-14 10:04:04 +1000754
Ben Skeggs370c00f2012-08-14 14:11:49 +1000755 /* allocate display hardware to client */
756 mutex_lock(&nv_subdev(priv)->mutex);
757 if (list_empty(&nv_engine(priv)->contexts)) {
758 ret = nouveau_engctx_create(parent, engine, oclass, NULL,
759 0x10000, 0x10000,
760 NVOBJ_FLAG_HEAP, &ectx);
761 *pobject = nv_object(ectx);
762 }
763 mutex_unlock(&nv_subdev(priv)->mutex);
764 return ret;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000765}
766
767struct nouveau_oclass
768nv50_disp_cclass = {
769 .handle = NV_ENGCTX(DISP, 0x50),
770 .ofuncs = &(struct nouveau_ofuncs) {
771 .ctor = nv50_disp_data_ctor,
772 .dtor = _nouveau_engctx_dtor,
773 .init = _nouveau_engctx_init,
774 .fini = _nouveau_engctx_fini,
775 .rd32 = _nouveau_engctx_rd32,
776 .wr32 = _nouveau_engctx_wr32,
777 },
778};
779
780/*******************************************************************************
781 * Display engine implementation
782 ******************************************************************************/
783
Ben Skeggs117e16332014-02-21 11:06:40 +1000784static const struct nouveau_enum
785nv50_disp_intr_error_type[] = {
786 { 3, "ILLEGAL_MTHD" },
787 { 4, "INVALID_VALUE" },
788 { 5, "INVALID_STATE" },
789 { 7, "INVALID_HANDLE" },
790 {}
791};
792
793static const struct nouveau_enum
794nv50_disp_intr_error_code[] = {
795 { 0x00, "" },
796 {}
797};
798
Ben Skeggsebb945a2012-07-20 08:17:34 +1000799static void
Ben Skeggs117e16332014-02-21 11:06:40 +1000800nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
Ben Skeggs186ecad2012-11-09 12:09:48 +1000801{
Ben Skeggs117e16332014-02-21 11:06:40 +1000802 u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
803 u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
804 u32 code = (addr & 0x00ff0000) >> 16;
805 u32 type = (addr & 0x00007000) >> 12;
806 u32 mthd = (addr & 0x00000ffc);
807 const struct nouveau_enum *ec, *et;
808 char ecunk[6], etunk[6];
Ben Skeggs186ecad2012-11-09 12:09:48 +1000809
Ben Skeggs117e16332014-02-21 11:06:40 +1000810 et = nouveau_enum_find(nv50_disp_intr_error_type, type);
811 if (!et)
812 snprintf(etunk, sizeof(etunk), "UNK%02X", type);
Ben Skeggs186ecad2012-11-09 12:09:48 +1000813
Ben Skeggs117e16332014-02-21 11:06:40 +1000814 ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
815 if (!ec)
816 snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
Ben Skeggs186ecad2012-11-09 12:09:48 +1000817
Ben Skeggs117e16332014-02-21 11:06:40 +1000818 nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
819 et ? et->name : etunk, ec ? ec->name : ecunk,
820 chid, mthd, data);
821
822 nv_wr32(priv, 0x610020, 0x00010000 << chid);
823 nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +1000824}
825
Ben Skeggs186ecad2012-11-09 12:09:48 +1000826static u16
827exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
828 struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
829 struct nvbios_outp *info)
830{
831 struct nouveau_bios *bios = nouveau_bios(priv);
832 u16 mask, type, data;
833
834 if (outp < 4) {
835 type = DCB_OUTPUT_ANALOG;
836 mask = 0;
Ben Skeggs476e84e2013-02-11 09:24:23 +1000837 } else
838 if (outp < 8) {
Ben Skeggs186ecad2012-11-09 12:09:48 +1000839 switch (ctrl & 0x00000f00) {
840 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
841 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
842 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
843 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
844 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
845 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
846 default:
847 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
848 return 0x0000;
849 }
Ben Skeggs476e84e2013-02-11 09:24:23 +1000850 outp -= 4;
851 } else {
852 outp = outp - 8;
853 type = 0x0010;
854 mask = 0;
855 switch (ctrl & 0x00000f00) {
856 case 0x00000000: type |= priv->pior.type[outp]; break;
857 default:
858 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
859 return 0x0000;
860 }
Ben Skeggs186ecad2012-11-09 12:09:48 +1000861 }
862
863 mask = 0x00c0 & (mask << 6);
864 mask |= 0x0001 << outp;
865 mask |= 0x0100 << head;
866
867 data = dcb_outp_match(bios, type, mask, ver, hdr, dcb);
868 if (!data)
869 return 0x0000;
870
Ben Skeggs476e84e2013-02-11 09:24:23 +1000871 /* off-chip encoders require matching the exact encoder type */
872 if (dcb->location != 0)
873 type |= dcb->extdev << 8;
874
Ben Skeggs186ecad2012-11-09 12:09:48 +1000875 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
876}
877
878static bool
879exec_script(struct nv50_disp_priv *priv, int head, int id)
880{
881 struct nouveau_bios *bios = nouveau_bios(priv);
882 struct nvbios_outp info;
883 struct dcb_output dcb;
884 u8 ver, hdr, cnt, len;
885 u16 data;
886 u32 ctrl = 0x00000000;
Emil Velikovb969fa52013-07-30 01:01:10 +0100887 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000888 int i;
889
Ben Skeggs476e84e2013-02-11 09:24:23 +1000890 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +0100891 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +1000892 ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
893
Ben Skeggs476e84e2013-02-11 09:24:23 +1000894 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100895 if (!(ctrl & (1 << head))) {
896 if (nv_device(priv)->chipset < 0x90 ||
897 nv_device(priv)->chipset == 0x92 ||
898 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +0100899 reg = 0x610b74;
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100900 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +0100901 reg = 0x610798;
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100902 }
Emil Velikovb969fa52013-07-30 01:01:10 +0100903 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
904 ctrl = nv_rd32(priv, reg + (i * 8));
905 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000906 }
907
Ben Skeggs476e84e2013-02-11 09:24:23 +1000908 /* PIOR */
909 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +0100910 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +1000911 ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
912 i += 8;
913 }
914
Ben Skeggs186ecad2012-11-09 12:09:48 +1000915 if (!(ctrl & (1 << head)))
916 return false;
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100917 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000918
919 data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
920 if (data) {
921 struct nvbios_init init = {
922 .subdev = nv_subdev(priv),
923 .bios = bios,
924 .offset = info.script[id],
925 .outp = &dcb,
926 .crtc = head,
927 .execute = 1,
928 };
929
930 return nvbios_exec(&init) == 0;
931 }
932
933 return false;
934}
935
936static u32
937exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
938 struct dcb_output *outp)
939{
940 struct nouveau_bios *bios = nouveau_bios(priv);
941 struct nvbios_outp info1;
942 struct nvbios_ocfg info2;
943 u8 ver, hdr, cnt, len;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000944 u32 ctrl = 0x00000000;
Ben Skeggs46c13c12013-02-16 13:49:21 +1000945 u32 data, conf = ~0;
Emil Velikovb969fa52013-07-30 01:01:10 +0100946 u32 reg;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000947 int i;
948
Ben Skeggs476e84e2013-02-11 09:24:23 +1000949 /* DAC */
Emil Velikovb969fa52013-07-30 01:01:10 +0100950 for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
Ben Skeggs186ecad2012-11-09 12:09:48 +1000951 ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
952
Ben Skeggs476e84e2013-02-11 09:24:23 +1000953 /* SOR */
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100954 if (!(ctrl & (1 << head))) {
955 if (nv_device(priv)->chipset < 0x90 ||
956 nv_device(priv)->chipset == 0x92 ||
957 nv_device(priv)->chipset == 0xa0) {
Emil Velikovb969fa52013-07-30 01:01:10 +0100958 reg = 0x610b70;
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100959 } else {
Emil Velikovb969fa52013-07-30 01:01:10 +0100960 reg = 0x610794;
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100961 }
Emil Velikovb969fa52013-07-30 01:01:10 +0100962 for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
963 ctrl = nv_rd32(priv, reg + (i * 8));
964 i += 4;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000965 }
966
Ben Skeggs476e84e2013-02-11 09:24:23 +1000967 /* PIOR */
968 if (!(ctrl & (1 << head))) {
Emil Velikovb969fa52013-07-30 01:01:10 +0100969 for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
Ben Skeggs476e84e2013-02-11 09:24:23 +1000970 ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
971 i += 8;
972 }
973
Ben Skeggs186ecad2012-11-09 12:09:48 +1000974 if (!(ctrl & (1 << head)))
Ben Skeggs46c13c12013-02-16 13:49:21 +1000975 return conf;
Marcin Slusarzc684cef2013-01-03 19:38:45 +0100976 i--;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000977
978 data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
979 if (!data)
Ben Skeggs46c13c12013-02-16 13:49:21 +1000980 return conf;
Ben Skeggs186ecad2012-11-09 12:09:48 +1000981
Ben Skeggs476e84e2013-02-11 09:24:23 +1000982 if (outp->location == 0) {
983 switch (outp->type) {
984 case DCB_OUTPUT_TMDS:
985 conf = (ctrl & 0x00000f00) >> 8;
986 if (pclk >= 165000)
987 conf |= 0x0100;
988 break;
989 case DCB_OUTPUT_LVDS:
990 conf = priv->sor.lvdsconf;
991 break;
992 case DCB_OUTPUT_DP:
993 conf = (ctrl & 0x00000f00) >> 8;
994 break;
995 case DCB_OUTPUT_ANALOG:
996 default:
997 conf = 0x00ff;
998 break;
999 }
1000 } else {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001001 conf = (ctrl & 0x00000f00) >> 8;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001002 pclk = pclk / 2;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001003 }
1004
1005 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001006 if (data && id < 0xff) {
Ben Skeggs186ecad2012-11-09 12:09:48 +10001007 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
1008 if (data) {
1009 struct nvbios_init init = {
1010 .subdev = nv_subdev(priv),
1011 .bios = bios,
1012 .offset = data,
1013 .outp = outp,
1014 .crtc = head,
1015 .execute = 1,
1016 };
1017
Ben Skeggs46c13c12013-02-16 13:49:21 +10001018 nvbios_exec(&init);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001019 }
1020 }
1021
Ben Skeggs46c13c12013-02-16 13:49:21 +10001022 return conf;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001023}
1024
1025static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001026nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001027{
Ben Skeggs16d4c032013-02-20 18:56:33 +10001028 exec_script(priv, head, 1);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001029}
1030
1031static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001032nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
1033{
1034 exec_script(priv, head, 2);
1035}
1036
1037static void
1038nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
1039{
Ben Skeggs88524bc2013-03-05 10:53:54 +10001040 struct nouveau_devinit *devinit = nouveau_devinit(priv);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001041 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1042 if (pclk)
Ben Skeggs88524bc2013-03-05 10:53:54 +10001043 devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001044}
1045
1046static void
1047nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
1048 struct dcb_output *outp, u32 pclk)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001049{
1050 const int link = !(outp->sorconf.link & 1);
1051 const int or = ffs(outp->or) - 1;
1052 const u32 soff = ( or * 0x800);
1053 const u32 loff = (link * 0x080) + soff;
1054 const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
Ben Skeggs186ecad2012-11-09 12:09:48 +10001055 const u32 symbol = 100000;
1056 u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
1057 u32 clksor = nv_rd32(priv, 0x614300 + soff);
1058 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
1059 int TU, VTUi, VTUf, VTUa;
1060 u64 link_data_rate, link_ratio, unk;
1061 u32 best_diff = 64 * symbol;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001062 u32 link_nr, link_bw, bits, r;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001063
1064 /* calculate packed data rate for each lane */
1065 if (dpctrl > 0x00030000) link_nr = 4;
1066 else if (dpctrl > 0x00010000) link_nr = 2;
1067 else link_nr = 1;
1068
1069 if (clksor & 0x000c0000)
1070 link_bw = 270000;
1071 else
1072 link_bw = 162000;
1073
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001074 if ((ctrl & 0xf0000) == 0x60000) bits = 30;
1075 else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
1076 else bits = 18;
1077
Ben Skeggs186ecad2012-11-09 12:09:48 +10001078 link_data_rate = (pclk * bits / 8) / link_nr;
1079
1080 /* calculate ratio of packed data rate to link symbol rate */
1081 link_ratio = link_data_rate * symbol;
1082 r = do_div(link_ratio, link_bw);
1083
1084 for (TU = 64; TU >= 32; TU--) {
1085 /* calculate average number of valid symbols in each TU */
1086 u32 tu_valid = link_ratio * TU;
1087 u32 calc, diff;
1088
1089 /* find a hw representation for the fraction.. */
1090 VTUi = tu_valid / symbol;
1091 calc = VTUi * symbol;
1092 diff = tu_valid - calc;
1093 if (diff) {
1094 if (diff >= (symbol / 2)) {
1095 VTUf = symbol / (symbol - diff);
1096 if (symbol - (VTUf * diff))
1097 VTUf++;
1098
1099 if (VTUf <= 15) {
1100 VTUa = 1;
1101 calc += symbol - (symbol / VTUf);
1102 } else {
1103 VTUa = 0;
1104 VTUf = 1;
1105 calc += symbol;
1106 }
1107 } else {
1108 VTUa = 0;
1109 VTUf = min((int)(symbol / diff), 15);
1110 calc += symbol / VTUf;
1111 }
1112
1113 diff = calc - tu_valid;
1114 } else {
1115 /* no remainder, but the hw doesn't like the fractional
1116 * part to be zero. decrement the integer part and
1117 * have the fraction add a whole symbol back
1118 */
1119 VTUa = 0;
1120 VTUf = 1;
1121 VTUi--;
1122 }
1123
1124 if (diff < best_diff) {
1125 best_diff = diff;
1126 bestTU = TU;
1127 bestVTUa = VTUa;
1128 bestVTUf = VTUf;
1129 bestVTUi = VTUi;
1130 if (diff == 0)
1131 break;
1132 }
1133 }
1134
1135 if (!bestTU) {
1136 nv_error(priv, "unable to find suitable dp config\n");
1137 return;
1138 }
1139
1140 /* XXX close to vbios numbers, but not right */
1141 unk = (symbol - link_ratio) * bestTU;
1142 unk *= link_ratio;
1143 r = do_div(unk, symbol);
1144 r = do_div(unk, symbol);
1145 unk += 6;
1146
1147 nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
1148 nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
1149 bestVTUf << 16 |
1150 bestVTUi << 8 | unk);
1151}
1152
1153static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001154nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001155{
1156 struct dcb_output outp;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001157 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1158 u32 hval, hreg = 0x614200 + (head * 0x800);
1159 u32 oval, oreg;
Emil Velikov378f2bc2013-07-02 14:44:12 +01001160 u32 mask;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001161 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
1162 if (conf != ~0) {
1163 if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
1164 u32 soff = (ffs(outp.or) - 1) * 0x08;
Ilia Mirkina7f1c1e2014-02-13 21:57:15 -05001165 u32 ctrl = nv_rd32(priv, 0x610794 + soff);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001166 u32 datarate;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001167
Ben Skeggs16d4c032013-02-20 18:56:33 +10001168 switch ((ctrl & 0x000f0000) >> 16) {
1169 case 6: datarate = pclk * 30 / 8; break;
1170 case 5: datarate = pclk * 24 / 8; break;
1171 case 2:
1172 default:
1173 datarate = pclk * 18 / 8;
1174 break;
Ben Skeggs0a0afd22013-02-18 23:17:53 -05001175 }
1176
Ben Skeggs16d4c032013-02-20 18:56:33 +10001177 nouveau_dp_train(&priv->base, priv->sor.dp,
1178 &outp, head, datarate);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001179 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001180
Ben Skeggs16d4c032013-02-20 18:56:33 +10001181 exec_clkcmp(priv, head, 0, pclk, &outp);
1182
1183 if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) {
1184 oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
1185 oval = 0x00000000;
1186 hval = 0x00000000;
Emil Velikov378f2bc2013-07-02 14:44:12 +01001187 mask = 0xffffffff;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001188 } else
1189 if (!outp.location) {
1190 if (outp.type == DCB_OUTPUT_DP)
1191 nv50_disp_intr_unk20_2_dp(priv, &outp, pclk);
1192 oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
1193 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1194 hval = 0x00000000;
Emil Velikov378f2bc2013-07-02 14:44:12 +01001195 mask = 0x00000707;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001196 } else {
1197 oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
1198 oval = 0x00000001;
1199 hval = 0x00000001;
Emil Velikov378f2bc2013-07-02 14:44:12 +01001200 mask = 0x00000707;
Ben Skeggs16d4c032013-02-20 18:56:33 +10001201 }
1202
1203 nv_mask(priv, hreg, 0x0000000f, hval);
Emil Velikov378f2bc2013-07-02 14:44:12 +01001204 nv_mask(priv, oreg, mask, oval);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001205 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001206}
1207
1208/* If programming a TMDS output on a SOR that can also be configured for
1209 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
1210 *
1211 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
1212 * the VBIOS scripts on at least one board I have only switch it off on
1213 * link 0, causing a blank display if the output has previously been
1214 * programmed for DisplayPort.
1215 */
1216static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001217nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001218{
1219 struct nouveau_bios *bios = nouveau_bios(priv);
1220 const int link = !(outp->sorconf.link & 1);
1221 const int or = ffs(outp->or) - 1;
1222 const u32 loff = (or * 0x800) + (link * 0x80);
1223 const u16 mask = (outp->sorconf.link << 6) | outp->or;
1224 u8 ver, hdr;
1225
1226 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
1227 nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
1228}
1229
1230static void
Ben Skeggs16d4c032013-02-20 18:56:33 +10001231nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001232{
Ben Skeggs16d4c032013-02-20 18:56:33 +10001233 struct dcb_output outp;
1234 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1235 if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) {
1236 if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS)
1237 nv50_disp_intr_unk40_0_tmds(priv, &outp);
1238 else
1239 if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) {
1240 u32 soff = (ffs(outp.or) - 1) * 0x08;
1241 u32 ctrl = nv_rd32(priv, 0x610b84 + soff);
1242 u32 datarate;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001243
Ben Skeggs16d4c032013-02-20 18:56:33 +10001244 switch ((ctrl & 0x000f0000) >> 16) {
1245 case 6: datarate = pclk * 30 / 8; break;
1246 case 5: datarate = pclk * 24 / 8; break;
1247 case 2:
1248 default:
1249 datarate = pclk * 18 / 8;
1250 break;
Ben Skeggs476e84e2013-02-11 09:24:23 +10001251 }
Ben Skeggs16d4c032013-02-20 18:56:33 +10001252
1253 nouveau_dp_train(&priv->base, priv->pior.dp,
1254 &outp, head, datarate);
Ben Skeggs476e84e2013-02-11 09:24:23 +10001255 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001256 }
Ben Skeggs186ecad2012-11-09 12:09:48 +10001257}
1258
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001259void
1260nv50_disp_intr_supervisor(struct work_struct *work)
Ben Skeggs186ecad2012-11-09 12:09:48 +10001261{
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001262 struct nv50_disp_priv *priv =
1263 container_of(work, struct nv50_disp_priv, supervisor);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001264 u32 super = nv_rd32(priv, 0x610030);
Ben Skeggs16d4c032013-02-20 18:56:33 +10001265 int head;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001266
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001267 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001268
Ben Skeggs16d4c032013-02-20 18:56:33 +10001269 if (priv->super & 0x00000010) {
1270 for (head = 0; head < priv->head.nr; head++) {
1271 if (!(super & (0x00000020 << head)))
1272 continue;
1273 if (!(super & (0x00000080 << head)))
1274 continue;
1275 nv50_disp_intr_unk10_0(priv, head);
1276 }
1277 } else
1278 if (priv->super & 0x00000020) {
1279 for (head = 0; head < priv->head.nr; head++) {
1280 if (!(super & (0x00000080 << head)))
1281 continue;
1282 nv50_disp_intr_unk20_0(priv, head);
1283 }
1284 for (head = 0; head < priv->head.nr; head++) {
1285 if (!(super & (0x00000200 << head)))
1286 continue;
1287 nv50_disp_intr_unk20_1(priv, head);
1288 }
1289 for (head = 0; head < priv->head.nr; head++) {
1290 if (!(super & (0x00000080 << head)))
1291 continue;
1292 nv50_disp_intr_unk20_2(priv, head);
1293 }
1294 } else
1295 if (priv->super & 0x00000040) {
1296 for (head = 0; head < priv->head.nr; head++) {
1297 if (!(super & (0x00000080 << head)))
1298 continue;
1299 nv50_disp_intr_unk40_0(priv, head);
1300 }
1301 }
1302
1303 nv_wr32(priv, 0x610030, 0x80000000);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001304}
1305
Ben Skeggs70cabe42012-08-14 10:04:04 +10001306void
Ben Skeggsebb945a2012-07-20 08:17:34 +10001307nv50_disp_intr(struct nouveau_subdev *subdev)
1308{
1309 struct nv50_disp_priv *priv = (void *)subdev;
Ben Skeggs186ecad2012-11-09 12:09:48 +10001310 u32 intr0 = nv_rd32(priv, 0x610020);
1311 u32 intr1 = nv_rd32(priv, 0x610024);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001312
Ben Skeggs117e16332014-02-21 11:06:40 +10001313 while (intr0 & 0x001f0000) {
1314 u32 chid = __ffs(intr0 & 0x001f0000) - 16;
1315 nv50_disp_intr_error(priv, chid);
1316 intr0 &= ~(0x00010000 << chid);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001317 }
1318
1319 if (intr1 & 0x00000004) {
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001320 nouveau_event_trigger(priv->base.vblank, 0);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001321 nv_wr32(priv, 0x610024, 0x00000004);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001322 intr1 &= ~0x00000004;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001323 }
1324
Ben Skeggs186ecad2012-11-09 12:09:48 +10001325 if (intr1 & 0x00000008) {
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001326 nouveau_event_trigger(priv->base.vblank, 1);
Ben Skeggsebb945a2012-07-20 08:17:34 +10001327 nv_wr32(priv, 0x610024, 0x00000008);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001328 intr1 &= ~0x00000008;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001329 }
1330
Ben Skeggs186ecad2012-11-09 12:09:48 +10001331 if (intr1 & 0x00000070) {
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001332 priv->super = (intr1 & 0x00000070);
1333 schedule_work(&priv->supervisor);
1334 nv_wr32(priv, 0x610024, priv->super);
Ben Skeggs186ecad2012-11-09 12:09:48 +10001335 intr1 &= ~0x00000070;
1336 }
Ben Skeggsebb945a2012-07-20 08:17:34 +10001337}
1338
1339static int
1340nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
Ben Skeggs370c00f2012-08-14 14:11:49 +10001341 struct nouveau_oclass *oclass, void *data, u32 size,
1342 struct nouveau_object **pobject)
Ben Skeggsebb945a2012-07-20 08:17:34 +10001343{
1344 struct nv50_disp_priv *priv;
1345 int ret;
1346
Ben Skeggs1d7c71a2013-01-31 09:23:34 +10001347 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
Ben Skeggsebb945a2012-07-20 08:17:34 +10001348 "display", &priv);
1349 *pobject = nv_object(priv);
1350 if (ret)
1351 return ret;
1352
Ben Skeggs70cabe42012-08-14 10:04:04 +10001353 nv_engine(priv)->sclass = nv50_disp_base_oclass;
1354 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001355 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs5cc027f2013-02-18 17:50:51 -05001356 INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
Ben Skeggs70cabe42012-08-14 10:04:04 +10001357 priv->sclass = nv50_disp_sclass;
1358 priv->head.nr = 2;
1359 priv->dac.nr = 3;
1360 priv->sor.nr = 2;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001361 priv->pior.nr = 3;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001362 priv->dac.power = nv50_dac_power;
Ben Skeggs7ebb38b2012-11-09 09:38:06 +10001363 priv->dac.sense = nv50_dac_sense;
Ben Skeggsef22c8b2012-11-09 09:32:56 +10001364 priv->sor.power = nv50_sor_power;
Ben Skeggsa2bc2832013-02-11 09:11:08 +10001365 priv->pior.power = nv50_pior_power;
1366 priv->pior.dp = &nv50_pior_dp_func;
Ben Skeggsebb945a2012-07-20 08:17:34 +10001367 return 0;
1368}
1369
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001370struct nouveau_oclass *
1371nv50_disp_oclass = &(struct nv50_disp_impl) {
1372 .base.base.handle = NV_ENGINE(DISP, 0x50),
1373 .base.base.ofuncs = &(struct nouveau_ofuncs) {
Ben Skeggsebb945a2012-07-20 08:17:34 +10001374 .ctor = nv50_disp_ctor,
1375 .dtor = _nouveau_disp_dtor,
1376 .init = _nouveau_disp_init,
1377 .fini = _nouveau_disp_fini,
1378 },
Ben Skeggsa8f8b482014-02-20 21:33:34 +10001379}.base.base;