blob: 8d3b6a21d62ac7d1361c56fb985355e7a78e7af0 [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
25#include <engine/software.h>
26#include <engine/disp.h>
27
Ben Skeggs446b05a2012-08-14 12:50:14 +100028#include <subdev/timer.h>
29
Ben Skeggs70cabe42012-08-14 10:04:04 +100030#include "nv50.h"
31
32/*******************************************************************************
33 * EVO channel common helpers
34 ******************************************************************************/
35
36static u32
37nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
38{
39 return 0xdeadcafe;
40}
41
42static void
43nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
44{
45}
46
47/*******************************************************************************
48 * EVO master channel object
49 ******************************************************************************/
50
51static int
52nv50_disp_mast_ctor(struct nouveau_object *parent,
53 struct nouveau_object *engine,
54 struct nouveau_oclass *oclass, void *data, u32 size,
55 struct nouveau_object **pobject)
56{
57 struct nv50_disp_chan *chan;
58 int ret;
59
60 ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
61 *pobject = nv_object(chan);
62 if (ret)
63 return ret;
64
65 return 0;
66}
67
68static void
69nv50_disp_mast_dtor(struct nouveau_object *object)
70{
71 struct nv50_disp_chan *chan = (void *)object;
72 nouveau_object_destroy(&chan->base);
73}
74
75static int
76nv50_disp_mast_init(struct nouveau_object *object)
77{
78 struct nv50_disp_chan *chan = (void *)object;
79 int ret;
80
81 ret = nouveau_object_init(&chan->base);
82 if (ret)
83 return ret;
84
85 return 0;
86}
87
88static int
89nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
90{
91 struct nv50_disp_chan *chan = (void *)object;
92 return nouveau_object_fini(&chan->base, suspend);
93}
94
95struct nouveau_ofuncs
96nv50_disp_mast_ofuncs = {
97 .ctor = nv50_disp_mast_ctor,
98 .dtor = nv50_disp_mast_dtor,
99 .init = nv50_disp_mast_init,
100 .fini = nv50_disp_mast_fini,
101 .rd32 = nv50_disp_chan_rd32,
102 .wr32 = nv50_disp_chan_wr32,
103};
104
105/*******************************************************************************
106 * EVO DMA channel objects (sync, overlay)
107 ******************************************************************************/
108
109static int
110nv50_disp_dmac_ctor(struct nouveau_object *parent,
111 struct nouveau_object *engine,
112 struct nouveau_oclass *oclass, void *data, u32 size,
113 struct nouveau_object **pobject)
114{
115 struct nv50_disp_chan *chan;
116 int ret;
117
118 ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
119 *pobject = nv_object(chan);
120 if (ret)
121 return ret;
122
123 return 0;
124}
125
126static void
127nv50_disp_dmac_dtor(struct nouveau_object *object)
128{
129 struct nv50_disp_chan *chan = (void *)object;
130 nouveau_object_destroy(&chan->base);
131}
132
133static int
134nv50_disp_dmac_init(struct nouveau_object *object)
135{
136 struct nv50_disp_chan *chan = (void *)object;
137 int ret;
138
139 ret = nouveau_object_init(&chan->base);
140 if (ret)
141 return ret;
142
143 return 0;
144}
145
146static int
147nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
148{
149 struct nv50_disp_chan *chan = (void *)object;
150 return nouveau_object_fini(&chan->base, suspend);
151}
152
153struct nouveau_ofuncs
154nv50_disp_dmac_ofuncs = {
155 .ctor = nv50_disp_dmac_ctor,
156 .dtor = nv50_disp_dmac_dtor,
157 .init = nv50_disp_dmac_init,
158 .fini = nv50_disp_dmac_fini,
159 .rd32 = nv50_disp_chan_rd32,
160 .wr32 = nv50_disp_chan_wr32,
161};
162
163/*******************************************************************************
164 * EVO PIO channel objects (cursor, immediate overlay controls)
165 ******************************************************************************/
166
167static int
168nv50_disp_pioc_ctor(struct nouveau_object *parent,
169 struct nouveau_object *engine,
170 struct nouveau_oclass *oclass, void *data, u32 size,
171 struct nouveau_object **pobject)
172{
173 struct nv50_disp_chan *chan;
174 int ret;
175
176 ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
177 *pobject = nv_object(chan);
178 if (ret)
179 return ret;
180
181 return 0;
182}
183
184static void
185nv50_disp_pioc_dtor(struct nouveau_object *object)
186{
187 struct nv50_disp_chan *chan = (void *)object;
188 nouveau_object_destroy(&chan->base);
189}
190
191static int
192nv50_disp_pioc_init(struct nouveau_object *object)
193{
194 struct nv50_disp_chan *chan = (void *)object;
195 int ret;
196
197 ret = nouveau_object_init(&chan->base);
198 if (ret)
199 return ret;
200
201 return 0;
202}
203
204static int
205nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
206{
207 struct nv50_disp_chan *chan = (void *)object;
208 return nouveau_object_fini(&chan->base, suspend);
209}
210
211struct nouveau_ofuncs
212nv50_disp_pioc_ofuncs = {
213 .ctor = nv50_disp_pioc_ctor,
214 .dtor = nv50_disp_pioc_dtor,
215 .init = nv50_disp_pioc_init,
216 .fini = nv50_disp_pioc_fini,
217 .rd32 = nv50_disp_chan_rd32,
218 .wr32 = nv50_disp_chan_wr32,
219};
220
221/*******************************************************************************
222 * Base display object
223 ******************************************************************************/
224
225static int
226nv50_disp_base_ctor(struct nouveau_object *parent,
227 struct nouveau_object *engine,
228 struct nouveau_oclass *oclass, void *data, u32 size,
229 struct nouveau_object **pobject)
230{
231 struct nv50_disp_priv *priv = (void *)engine;
232 struct nv50_disp_base *base;
233 int ret;
234
235 ret = nouveau_parent_create(parent, engine, oclass, 0,
236 priv->sclass, 0, &base);
237 *pobject = nv_object(base);
238 if (ret)
239 return ret;
240
241 return 0;
242}
243
244static void
245nv50_disp_base_dtor(struct nouveau_object *object)
246{
247 struct nv50_disp_base *base = (void *)object;
248 nouveau_parent_destroy(&base->base);
249}
250
251static int
252nv50_disp_base_init(struct nouveau_object *object)
253{
Ben Skeggsab772142012-08-14 11:29:57 +1000254 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000255 struct nv50_disp_base *base = (void *)object;
Ben Skeggsab772142012-08-14 11:29:57 +1000256 int ret, i;
257 u32 tmp;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000258
259 ret = nouveau_parent_init(&base->base);
260 if (ret)
261 return ret;
262
Ben Skeggsab772142012-08-14 11:29:57 +1000263 /* The below segments of code copying values from one register to
264 * another appear to inform EVO of the display capabilities or
265 * something similar. NFI what the 0x614004 caps are for..
266 */
267 tmp = nv_rd32(priv, 0x614004);
268 nv_wr32(priv, 0x610184, tmp);
269
270 /* ... CRTC caps */
271 for (i = 0; i < priv->head.nr; i++) {
272 tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
273 nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
274 tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
275 nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
276 tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
277 nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
278 tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
279 nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
280 }
281
282 /* ... DAC caps */
283 for (i = 0; i < priv->dac.nr; i++) {
284 tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
285 nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
286 }
287
288 /* ... SOR caps */
289 for (i = 0; i < priv->sor.nr; i++) {
290 tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
291 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
292 }
293
294 /* ... EXT caps */
295 for (i = 0; i < 3; i++) {
296 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
297 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
298 }
299
Ben Skeggs446b05a2012-08-14 12:50:14 +1000300 /* steal display away from vbios, or something like that */
301 if (nv_rd32(priv, 0x610024) & 0x00000100) {
302 nv_wr32(priv, 0x610024, 0x00000100);
303 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
304 if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
305 nv_error(priv, "timeout acquiring display\n");
306 return -EBUSY;
307 }
308 }
309
310 /* point at display engine memory area (hash table, objects) */
311 nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
312
313 /* enable supervisor interrupts, disable everything else */
314 nv_wr32(priv, 0x610024, 0x00000370);
315 nv_wr32(priv, 0x610020, 0x00000000);
Ben Skeggs70cabe42012-08-14 10:04:04 +1000316 return 0;
317}
318
319static int
320nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
321{
Ben Skeggs446b05a2012-08-14 12:50:14 +1000322 struct nv50_disp_priv *priv = (void *)object->engine;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000323 struct nv50_disp_base *base = (void *)object;
Ben Skeggs446b05a2012-08-14 12:50:14 +1000324
325 /* disable all interrupts */
326 nv_wr32(priv, 0x610024, 0x00000000);
327 nv_wr32(priv, 0x610020, 0x00000000);
328
329 /* return control of display to vbios */
330 nv_mask(priv, 0x6194e8, 0x00000001, 0x00000001);
331 nv_wait(priv, 0x6194e8, 0x00000002, 0x00000002);
332
Ben Skeggs70cabe42012-08-14 10:04:04 +1000333 return nouveau_parent_fini(&base->base, suspend);
334}
335
336struct nouveau_ofuncs
337nv50_disp_base_ofuncs = {
338 .ctor = nv50_disp_base_ctor,
339 .dtor = nv50_disp_base_dtor,
340 .init = nv50_disp_base_init,
341 .fini = nv50_disp_base_fini,
342};
343
344static struct nouveau_oclass
345nv50_disp_base_oclass[] = {
346 { 0x5070, &nv50_disp_base_ofuncs },
Ben Skeggsebb945a2012-07-20 08:17:34 +1000347};
348
349static struct nouveau_oclass
350nv50_disp_sclass[] = {
Ben Skeggs70cabe42012-08-14 10:04:04 +1000351 { 0x507d, &nv50_disp_mast_ofuncs }, /* master */
352 { 0x507c, &nv50_disp_dmac_ofuncs }, /* sync */
353 { 0x507e, &nv50_disp_dmac_ofuncs }, /* overlay */
354 { 0x507b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */
355 { 0x507a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */
356 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000357};
358
Ben Skeggs70cabe42012-08-14 10:04:04 +1000359/*******************************************************************************
360 * Display context, tracks instmem allocation and prevents more than one
361 * client using the display hardware at any time.
362 ******************************************************************************/
363
364static int
365nv50_disp_data_ctor(struct nouveau_object *parent,
366 struct nouveau_object *engine,
367 struct nouveau_oclass *oclass, void *data, u32 size,
368 struct nouveau_object **pobject)
369{
370 struct nouveau_engctx *ectx;
371 int ret;
372
373 ret = nouveau_engctx_create(parent, engine, oclass, NULL, 0x10000,
374 0x10000, NVOBJ_FLAG_ZERO_ALLOC, &ectx);
375 *pobject = nv_object(ectx);
376 if (ret)
377 return ret;
378
379 return 0;
380}
381
382struct nouveau_oclass
383nv50_disp_cclass = {
384 .handle = NV_ENGCTX(DISP, 0x50),
385 .ofuncs = &(struct nouveau_ofuncs) {
386 .ctor = nv50_disp_data_ctor,
387 .dtor = _nouveau_engctx_dtor,
388 .init = _nouveau_engctx_init,
389 .fini = _nouveau_engctx_fini,
390 .rd32 = _nouveau_engctx_rd32,
391 .wr32 = _nouveau_engctx_wr32,
392 },
393};
394
395/*******************************************************************************
396 * Display engine implementation
397 ******************************************************************************/
398
Ben Skeggsebb945a2012-07-20 08:17:34 +1000399static void
400nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
401{
402 struct nouveau_disp *disp = &priv->base;
403 struct nouveau_software_chan *chan, *temp;
404 unsigned long flags;
405
406 spin_lock_irqsave(&disp->vblank.lock, flags);
407 list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
408 if (chan->vblank.crtc != crtc)
409 continue;
410
411 nv_wr32(priv, 0x001704, chan->vblank.channel);
412 nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
413
414 if (nv_device(priv)->chipset == 0x50) {
415 nv_wr32(priv, 0x001570, chan->vblank.offset);
416 nv_wr32(priv, 0x001574, chan->vblank.value);
417 } else {
418 if (nv_device(priv)->chipset >= 0xc0) {
419 nv_wr32(priv, 0x06000c,
420 upper_32_bits(chan->vblank.offset));
421 }
422 nv_wr32(priv, 0x060010, chan->vblank.offset);
423 nv_wr32(priv, 0x060014, chan->vblank.value);
424 }
425
426 list_del(&chan->vblank.head);
427 if (disp->vblank.put)
428 disp->vblank.put(disp->vblank.data, crtc);
429 }
430 spin_unlock_irqrestore(&disp->vblank.lock, flags);
431
432 if (disp->vblank.notify)
433 disp->vblank.notify(disp->vblank.data, crtc);
434}
435
Ben Skeggs70cabe42012-08-14 10:04:04 +1000436void
Ben Skeggsebb945a2012-07-20 08:17:34 +1000437nv50_disp_intr(struct nouveau_subdev *subdev)
438{
439 struct nv50_disp_priv *priv = (void *)subdev;
440 u32 stat1 = nv_rd32(priv, 0x610024);
441
442 if (stat1 & 0x00000004) {
443 nv50_disp_intr_vblank(priv, 0);
444 nv_wr32(priv, 0x610024, 0x00000004);
445 stat1 &= ~0x00000004;
446 }
447
448 if (stat1 & 0x00000008) {
449 nv50_disp_intr_vblank(priv, 1);
450 nv_wr32(priv, 0x610024, 0x00000008);
451 stat1 &= ~0x00000008;
452 }
453
454}
455
456static int
457nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
458 struct nouveau_oclass *oclass, void *data, u32 size,
459 struct nouveau_object **pobject)
460{
461 struct nv50_disp_priv *priv;
462 int ret;
463
464 ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
465 "display", &priv);
466 *pobject = nv_object(priv);
467 if (ret)
468 return ret;
469
Ben Skeggs70cabe42012-08-14 10:04:04 +1000470 nv_engine(priv)->sclass = nv50_disp_base_oclass;
471 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000472 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000473 priv->sclass = nv50_disp_sclass;
474 priv->head.nr = 2;
475 priv->dac.nr = 3;
476 priv->sor.nr = 2;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000477
478 INIT_LIST_HEAD(&priv->base.vblank.list);
479 spin_lock_init(&priv->base.vblank.lock);
480 return 0;
481}
482
483struct nouveau_oclass
484nv50_disp_oclass = {
485 .handle = NV_ENGINE(DISP, 0x50),
486 .ofuncs = &(struct nouveau_ofuncs) {
487 .ctor = nv50_disp_ctor,
488 .dtor = _nouveau_disp_dtor,
489 .init = _nouveau_disp_init,
490 .fini = _nouveau_disp_fini,
491 },
492};