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