blob: b3ad1d09ede87ed65f8a2c24cfe2a002b8b1aee4 [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{
252 struct nv50_disp_base *base = (void *)object;
253 int ret;
254
255 ret = nouveau_parent_init(&base->base);
256 if (ret)
257 return ret;
258
259 /* caps */
260 /* intr 100 */
261 /* 6194e8 shit */
262 /* intr */
263 /* set 610010 from engctx */
264 /* acquire mast? */
265 return 0;
266}
267
268static int
269nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
270{
271 struct nv50_disp_base *base = (void *)object;
272 return nouveau_parent_fini(&base->base, suspend);
273}
274
275struct nouveau_ofuncs
276nv50_disp_base_ofuncs = {
277 .ctor = nv50_disp_base_ctor,
278 .dtor = nv50_disp_base_dtor,
279 .init = nv50_disp_base_init,
280 .fini = nv50_disp_base_fini,
281};
282
283static struct nouveau_oclass
284nv50_disp_base_oclass[] = {
285 { 0x5070, &nv50_disp_base_ofuncs },
Ben Skeggsebb945a2012-07-20 08:17:34 +1000286};
287
288static struct nouveau_oclass
289nv50_disp_sclass[] = {
Ben Skeggs70cabe42012-08-14 10:04:04 +1000290 { 0x507d, &nv50_disp_mast_ofuncs }, /* master */
291 { 0x507c, &nv50_disp_dmac_ofuncs }, /* sync */
292 { 0x507e, &nv50_disp_dmac_ofuncs }, /* overlay */
293 { 0x507b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */
294 { 0x507a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */
295 {}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000296};
297
Ben Skeggs70cabe42012-08-14 10:04:04 +1000298/*******************************************************************************
299 * Display context, tracks instmem allocation and prevents more than one
300 * client using the display hardware at any time.
301 ******************************************************************************/
302
303static int
304nv50_disp_data_ctor(struct nouveau_object *parent,
305 struct nouveau_object *engine,
306 struct nouveau_oclass *oclass, void *data, u32 size,
307 struct nouveau_object **pobject)
308{
309 struct nouveau_engctx *ectx;
310 int ret;
311
312 ret = nouveau_engctx_create(parent, engine, oclass, NULL, 0x10000,
313 0x10000, NVOBJ_FLAG_ZERO_ALLOC, &ectx);
314 *pobject = nv_object(ectx);
315 if (ret)
316 return ret;
317
318 return 0;
319}
320
321struct nouveau_oclass
322nv50_disp_cclass = {
323 .handle = NV_ENGCTX(DISP, 0x50),
324 .ofuncs = &(struct nouveau_ofuncs) {
325 .ctor = nv50_disp_data_ctor,
326 .dtor = _nouveau_engctx_dtor,
327 .init = _nouveau_engctx_init,
328 .fini = _nouveau_engctx_fini,
329 .rd32 = _nouveau_engctx_rd32,
330 .wr32 = _nouveau_engctx_wr32,
331 },
332};
333
334/*******************************************************************************
335 * Display engine implementation
336 ******************************************************************************/
337
Ben Skeggsebb945a2012-07-20 08:17:34 +1000338static void
339nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
340{
341 struct nouveau_disp *disp = &priv->base;
342 struct nouveau_software_chan *chan, *temp;
343 unsigned long flags;
344
345 spin_lock_irqsave(&disp->vblank.lock, flags);
346 list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
347 if (chan->vblank.crtc != crtc)
348 continue;
349
350 nv_wr32(priv, 0x001704, chan->vblank.channel);
351 nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
352
353 if (nv_device(priv)->chipset == 0x50) {
354 nv_wr32(priv, 0x001570, chan->vblank.offset);
355 nv_wr32(priv, 0x001574, chan->vblank.value);
356 } else {
357 if (nv_device(priv)->chipset >= 0xc0) {
358 nv_wr32(priv, 0x06000c,
359 upper_32_bits(chan->vblank.offset));
360 }
361 nv_wr32(priv, 0x060010, chan->vblank.offset);
362 nv_wr32(priv, 0x060014, chan->vblank.value);
363 }
364
365 list_del(&chan->vblank.head);
366 if (disp->vblank.put)
367 disp->vblank.put(disp->vblank.data, crtc);
368 }
369 spin_unlock_irqrestore(&disp->vblank.lock, flags);
370
371 if (disp->vblank.notify)
372 disp->vblank.notify(disp->vblank.data, crtc);
373}
374
Ben Skeggs70cabe42012-08-14 10:04:04 +1000375void
Ben Skeggsebb945a2012-07-20 08:17:34 +1000376nv50_disp_intr(struct nouveau_subdev *subdev)
377{
378 struct nv50_disp_priv *priv = (void *)subdev;
379 u32 stat1 = nv_rd32(priv, 0x610024);
380
381 if (stat1 & 0x00000004) {
382 nv50_disp_intr_vblank(priv, 0);
383 nv_wr32(priv, 0x610024, 0x00000004);
384 stat1 &= ~0x00000004;
385 }
386
387 if (stat1 & 0x00000008) {
388 nv50_disp_intr_vblank(priv, 1);
389 nv_wr32(priv, 0x610024, 0x00000008);
390 stat1 &= ~0x00000008;
391 }
392
393}
394
395static int
396nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
397 struct nouveau_oclass *oclass, void *data, u32 size,
398 struct nouveau_object **pobject)
399{
400 struct nv50_disp_priv *priv;
401 int ret;
402
403 ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
404 "display", &priv);
405 *pobject = nv_object(priv);
406 if (ret)
407 return ret;
408
Ben Skeggs70cabe42012-08-14 10:04:04 +1000409 nv_engine(priv)->sclass = nv50_disp_base_oclass;
410 nv_engine(priv)->cclass = &nv50_disp_cclass;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000411 nv_subdev(priv)->intr = nv50_disp_intr;
Ben Skeggs70cabe42012-08-14 10:04:04 +1000412 priv->sclass = nv50_disp_sclass;
413 priv->head.nr = 2;
414 priv->dac.nr = 3;
415 priv->sor.nr = 2;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000416
417 INIT_LIST_HEAD(&priv->base.vblank.list);
418 spin_lock_init(&priv->base.vblank.lock);
419 return 0;
420}
421
422struct nouveau_oclass
423nv50_disp_oclass = {
424 .handle = NV_ENGINE(DISP, 0x50),
425 .ofuncs = &(struct nouveau_ofuncs) {
426 .ctor = nv50_disp_ctor,
427 .dtor = _nouveau_disp_dtor,
428 .init = _nouveau_disp_init,
429 .fini = _nouveau_disp_fini,
430 },
431};