aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-02-06 22:29:23 -0500
committerBen Skeggs <bskeggs@redhat.com>2011-02-24 15:45:11 -0500
commitcdccc70eff1eaf3627a716374f9ebc115fc4621c (patch)
tree744a5a9e35c5749326d3bfb85336afceb24c2b4d
parent45c4e0aae96c6354bf5131a282a74fe38d032de3 (diff)
drm/nv50-nvc0: initialise display sync channels
Also imports a couple of helper functions that'll be used to implement page flipping in the following commits.. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c22
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c123
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h15
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.c88
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.h2
6 files changed, 246 insertions, 6 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index 6c9501b3226b..6f0f4bb93796 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -73,6 +73,8 @@ enum {
73 NvImageBlit = 0x8000000d, 73 NvImageBlit = 0x8000000d,
74 NvSw = 0x8000000e, 74 NvSw = 0x8000000e,
75 NvSema = 0x8000000f, 75 NvSema = 0x8000000f,
76 NvEvoSema0 = 0x80000010,
77 NvEvoSema1 = 0x80000011,
76 78
77 /* G80+ display objects */ 79 /* G80+ display objects */
78 NvEvoVRAM = 0x01000000, 80 NvEvoVRAM = 0x01000000,
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 710a7053dc99..4f00c87ed86e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -36,6 +36,7 @@
36#include "nouveau_drm.h" 36#include "nouveau_drm.h"
37#include "nouveau_ramht.h" 37#include "nouveau_ramht.h"
38#include "nouveau_vm.h" 38#include "nouveau_vm.h"
39#include "nv50_display.h"
39 40
40struct nouveau_gpuobj_method { 41struct nouveau_gpuobj_method {
41 struct list_head head; 42 struct list_head head;
@@ -782,7 +783,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
782 struct drm_device *dev = chan->dev; 783 struct drm_device *dev = chan->dev;
783 struct drm_nouveau_private *dev_priv = dev->dev_private; 784 struct drm_nouveau_private *dev_priv = dev->dev_private;
784 struct nouveau_gpuobj *vram = NULL, *tt = NULL; 785 struct nouveau_gpuobj *vram = NULL, *tt = NULL;
785 int ret; 786 int ret, i;
786 787
787 NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); 788 NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
788 789
@@ -847,6 +848,25 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
847 nouveau_gpuobj_ref(NULL, &ramht); 848 nouveau_gpuobj_ref(NULL, &ramht);
848 if (ret) 849 if (ret)
849 return ret; 850 return ret;
851
852 /* dma objects for display sync channel semaphore blocks */
853 for (i = 0; i < 2; i++) {
854 struct nouveau_gpuobj *sem = NULL;
855 struct nv50_display_crtc *dispc =
856 &nv50_display(dev)->crtc[i];
857 u64 offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT;
858
859 ret = nouveau_gpuobj_dma_new(chan, 0x3d, offset, 0xfff,
860 NV_MEM_ACCESS_RW,
861 NV_MEM_TARGET_VRAM, &sem);
862 if (ret)
863 return ret;
864
865 ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, sem);
866 nouveau_gpuobj_ref(NULL, &sem);
867 if (ret)
868 return ret;
869 }
850 } 870 }
851 871
852 /* VRAM ctxdma */ 872 /* VRAM ctxdma */
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 09d7994ea099..75a376cc342a 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -178,7 +178,7 @@ nv50_display_init(struct drm_device *dev)
178 178
179 nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); 179 nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
180 180
181 ret = RING_SPACE(evo, 11); 181 ret = RING_SPACE(evo, 15);
182 if (ret) 182 if (ret)
183 return ret; 183 return ret;
184 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); 184 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2);
@@ -192,6 +192,11 @@ nv50_display_init(struct drm_device *dev)
192 OUT_RING(evo, 0); 192 OUT_RING(evo, 0);
193 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); 193 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1);
194 OUT_RING(evo, 0); 194 OUT_RING(evo, 0);
195 /* required to make display sync channels not hate life */
196 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK900), 1);
197 OUT_RING (evo, 0x00000311);
198 BEGIN_RING(evo, 0, NV50_EVO_CRTC(1, UNK900), 1);
199 OUT_RING (evo, 0x00000311);
195 FIRE_RING(evo); 200 FIRE_RING(evo);
196 if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) 201 if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
197 NV_ERROR(dev, "evo pushbuf stalled\n"); 202 NV_ERROR(dev, "evo pushbuf stalled\n");
@@ -366,6 +371,122 @@ nv50_display_destroy(struct drm_device *dev)
366 kfree(disp); 371 kfree(disp);
367} 372}
368 373
374void
375nv50_display_flip_stop(struct drm_crtc *crtc)
376{
377 struct nv50_display *disp = nv50_display(crtc->dev);
378 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
379 struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index];
380 struct nouveau_channel *evo = dispc->sync;
381 int ret;
382
383 ret = RING_SPACE(evo, 8);
384 if (ret) {
385 WARN_ON(1);
386 return;
387 }
388
389 BEGIN_RING(evo, 0, 0x0084, 1);
390 OUT_RING (evo, 0x00000000);
391 BEGIN_RING(evo, 0, 0x0094, 1);
392 OUT_RING (evo, 0x00000000);
393 BEGIN_RING(evo, 0, 0x00c0, 1);
394 OUT_RING (evo, 0x00000000);
395 BEGIN_RING(evo, 0, 0x0080, 1);
396 OUT_RING (evo, 0x00000000);
397 FIRE_RING (evo);
398}
399
400int
401nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
402 struct nouveau_channel *chan)
403{
404 struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
405 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
406 struct nv50_display *disp = nv50_display(crtc->dev);
407 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
408 struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index];
409 struct nouveau_channel *evo = dispc->sync;
410 int ret;
411
412 ret = RING_SPACE(evo, 24);
413 if (unlikely(ret))
414 return ret;
415
416 /* synchronise with the rendering channel, if necessary */
417 if (likely(chan)) {
418 u64 offset = dispc->sem.bo->vma.offset + dispc->sem.offset;
419
420 ret = RING_SPACE(chan, 10);
421 if (ret) {
422 WIND_RING(evo);
423 return ret;
424 }
425
426 if (dev_priv->chipset < 0xc0) {
427 BEGIN_RING(chan, NvSubSw, 0x0060, 2);
428 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
429 OUT_RING (chan, dispc->sem.offset);
430 BEGIN_RING(chan, NvSubSw, 0x006c, 1);
431 OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
432 BEGIN_RING(chan, NvSubSw, 0x0064, 2);
433 OUT_RING (chan, dispc->sem.offset ^ 0x10);
434 OUT_RING (chan, 0x74b1e000);
435 BEGIN_RING(chan, NvSubSw, 0x0060, 1);
436 if (dev_priv->chipset < 0x84)
437 OUT_RING (chan, NvSema);
438 else
439 OUT_RING (chan, chan->vram_handle);
440 } else {
441 BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
442 OUT_RING (chan, upper_32_bits(offset));
443 OUT_RING (chan, lower_32_bits(offset));
444 OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
445 OUT_RING (chan, 0x1002);
446 BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
447 OUT_RING (chan, upper_32_bits(offset));
448 OUT_RING (chan, lower_32_bits(offset ^ 0x10));
449 OUT_RING (chan, 0x74b1e000);
450 OUT_RING (chan, 0x1001);
451 }
452 FIRE_RING (chan);
453 } else {
454 nouveau_bo_wr32(dispc->sem.bo, dispc->sem.offset / 4,
455 0xf00d0000 | dispc->sem.value);
456 }
457
458 /* queue the flip on the crtc's "display sync" channel */
459 BEGIN_RING(evo, 0, 0x0100, 1);
460 OUT_RING (evo, 0xfffe0000);
461 BEGIN_RING(evo, 0, 0x0084, 5);
462 OUT_RING (evo, chan ? 0x00000100 : 0x00000010);
463 OUT_RING (evo, dispc->sem.offset);
464 OUT_RING (evo, 0xf00d0000 | dispc->sem.value);
465 OUT_RING (evo, 0x74b1e000);
466 OUT_RING (evo, NvEvoSync);
467 BEGIN_RING(evo, 0, 0x00a0, 2);
468 OUT_RING (evo, 0x00000000);
469 OUT_RING (evo, 0x00000000);
470 BEGIN_RING(evo, 0, 0x00c0, 1);
471 OUT_RING (evo, nv_fb->r_dma);
472 BEGIN_RING(evo, 0, 0x0110, 2);
473 OUT_RING (evo, 0x00000000);
474 OUT_RING (evo, 0x00000000);
475 BEGIN_RING(evo, 0, 0x0800, 5);
476 OUT_RING (evo, (nv_fb->nvbo->bo.mem.start << PAGE_SHIFT) >> 8);
477 OUT_RING (evo, 0);
478 OUT_RING (evo, (fb->height << 16) | fb->width);
479 OUT_RING (evo, nv_fb->r_pitch);
480 OUT_RING (evo, nv_fb->r_format);
481 BEGIN_RING(evo, 0, 0x0080, 1);
482 OUT_RING (evo, 0x00000000);
483 FIRE_RING (evo);
484
485 dispc->sem.offset ^= 0x10;
486 dispc->sem.value++;
487 return 0;
488}
489
369static u16 490static u16
370nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb, 491nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
371 u32 mc, int pxclk) 492 u32 mc, int pxclk)
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 3f5a3d543598..c2da503a22aa 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -35,10 +35,21 @@
35#include "nouveau_crtc.h" 35#include "nouveau_crtc.h"
36#include "nv50_evo.h" 36#include "nv50_evo.h"
37 37
38struct nv50_display_crtc {
39 struct nouveau_channel *sync;
40 struct {
41 struct nouveau_bo *bo;
42 u32 offset;
43 u16 value;
44 } sem;
45};
46
38struct nv50_display { 47struct nv50_display {
39 struct nouveau_channel *master; 48 struct nouveau_channel *master;
40 struct nouveau_gpuobj *ntfy; 49 struct nouveau_gpuobj *ntfy;
41 50
51 struct nv50_display_crtc crtc[2];
52
42 struct tasklet_struct tasklet; 53 struct tasklet_struct tasklet;
43 struct { 54 struct {
44 struct dcb_entry *dcb; 55 struct dcb_entry *dcb;
@@ -62,6 +73,10 @@ void nv50_display_destroy(struct drm_device *dev);
62int nv50_crtc_blank(struct nouveau_crtc *, bool blank); 73int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
63int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); 74int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
64 75
76int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
77 struct nouveau_channel *chan);
78void nv50_display_flip_stop(struct drm_crtc *);
79
65int nv50_evo_init(struct drm_device *dev); 80int nv50_evo_init(struct drm_device *dev);
66void nv50_evo_fini(struct drm_device *dev); 81void nv50_evo_fini(struct drm_device *dev);
67void nv50_evo_dmaobj_init(struct nouveau_gpuobj *, u32 memtype, u64 base, 82void nv50_evo_dmaobj_init(struct nouveau_gpuobj *, u32 memtype, u64 base,
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c
index b70208e981fb..18fbf27376c1 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.c
+++ b/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -220,7 +220,15 @@ static void
220nv50_evo_destroy(struct drm_device *dev) 220nv50_evo_destroy(struct drm_device *dev)
221{ 221{
222 struct nv50_display *disp = nv50_display(dev); 222 struct nv50_display *disp = nv50_display(dev);
223 223 int i;
224
225 for (i = 0; i < 2; i++) {
226 if (disp->crtc[i].sem.bo) {
227 nouveau_bo_unmap(disp->crtc[i].sem.bo);
228 nouveau_bo_ref(NULL, &disp->crtc[i].sem.bo);
229 }
230 nv50_evo_channel_del(&disp->crtc[i].sync);
231 }
224 nouveau_gpuobj_ref(NULL, &disp->ntfy); 232 nouveau_gpuobj_ref(NULL, &disp->ntfy);
225 nv50_evo_channel_del(&disp->master); 233 nv50_evo_channel_del(&disp->master);
226} 234}
@@ -232,7 +240,7 @@ nv50_evo_create(struct drm_device *dev)
232 struct nv50_display *disp = nv50_display(dev); 240 struct nv50_display *disp = nv50_display(dev);
233 struct nouveau_gpuobj *ramht = NULL; 241 struct nouveau_gpuobj *ramht = NULL;
234 struct nouveau_channel *evo; 242 struct nouveau_channel *evo;
235 int ret; 243 int ret, i, j;
236 244
237 /* create primary evo channel, the one we use for modesetting 245 /* create primary evo channel, the one we use for modesetting
238 * purporses 246 * purporses
@@ -311,6 +319,61 @@ nv50_evo_create(struct drm_device *dev)
311 if (ret) 319 if (ret)
312 goto err; 320 goto err;
313 321
322 /* create "display sync" channels and other structures we need
323 * to implement page flipping
324 */
325 for (i = 0; i < 2; i++) {
326 struct nv50_display_crtc *dispc = &disp->crtc[i];
327 u64 offset;
328
329 ret = nv50_evo_channel_new(dev, 1 + i, &dispc->sync);
330 if (ret)
331 goto err;
332
333 ret = nouveau_bo_new(dev, NULL, 4096, 0x1000, TTM_PL_FLAG_VRAM,
334 0, 0x0000, false, true, &dispc->sem.bo);
335 if (!ret) {
336 offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT;
337
338 ret = nouveau_bo_pin(dispc->sem.bo, TTM_PL_FLAG_VRAM);
339 if (!ret)
340 ret = nouveau_bo_map(dispc->sem.bo);
341 if (ret)
342 nouveau_bo_ref(NULL, &dispc->sem.bo);
343 }
344
345 if (ret)
346 goto err;
347
348 ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoSync, 0x0000,
349 offset, 4096, NULL);
350 if (ret)
351 goto err;
352
353 ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoVRAM_LP, 0x80000000,
354 0, dev_priv->vram_size, NULL);
355 if (ret)
356 goto err;
357
358 ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB32, 0x80000000 |
359 (dev_priv->chipset < 0xc0 ?
360 0x7a00 : 0xfe00),
361 0, dev_priv->vram_size, NULL);
362 if (ret)
363 goto err;
364
365 ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB16, 0x80000000 |
366 (dev_priv->chipset < 0xc0 ?
367 0x7000 : 0xfe00),
368 0, dev_priv->vram_size, NULL);
369 if (ret)
370 goto err;
371
372 for (j = 0; j < 4096; j += 4)
373 nouveau_bo_wr32(dispc->sem.bo, j / 4, 0x74b1e000);
374 dispc->sem.offset = 0;
375 }
376
314 return 0; 377 return 0;
315 378
316err: 379err:
@@ -322,7 +385,7 @@ int
322nv50_evo_init(struct drm_device *dev) 385nv50_evo_init(struct drm_device *dev)
323{ 386{
324 struct nv50_display *disp = nv50_display(dev); 387 struct nv50_display *disp = nv50_display(dev);
325 int ret; 388 int ret, i;
326 389
327 if (!disp->master) { 390 if (!disp->master) {
328 ret = nv50_evo_create(dev); 391 ret = nv50_evo_create(dev);
@@ -330,15 +393,32 @@ nv50_evo_init(struct drm_device *dev)
330 return ret; 393 return ret;
331 } 394 }
332 395
333 return nv50_evo_channel_init(disp->master); 396 ret = nv50_evo_channel_init(disp->master);
397 if (ret)
398 return ret;
399
400 for (i = 0; i < 2; i++) {
401 ret = nv50_evo_channel_init(disp->crtc[i].sync);
402 if (ret)
403 return ret;
404 }
405
406 return 0;
334} 407}
335 408
336void 409void
337nv50_evo_fini(struct drm_device *dev) 410nv50_evo_fini(struct drm_device *dev)
338{ 411{
339 struct nv50_display *disp = nv50_display(dev); 412 struct nv50_display *disp = nv50_display(dev);
413 int i;
414
415 for (i = 0; i < 2; i++) {
416 if (disp->crtc[i].sync)
417 nv50_evo_channel_fini(disp->crtc[i].sync);
418 }
340 419
341 if (disp->master) 420 if (disp->master)
342 nv50_evo_channel_fini(disp->master); 421 nv50_evo_channel_fini(disp->master);
422
343 nv50_evo_destroy(dev); 423 nv50_evo_destroy(dev);
344} 424}
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.h b/drivers/gpu/drm/nouveau/nv50_evo.h
index e6b069fec0bc..3860ca62cb19 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.h
+++ b/drivers/gpu/drm/nouveau/nv50_evo.h
@@ -113,5 +113,7 @@
113/* Both of these are needed, otherwise nothing happens. */ 113/* Both of these are needed, otherwise nothing happens. */
114#define NV50_EVO_CRTC_SCALE_RES1 0x000008d8 114#define NV50_EVO_CRTC_SCALE_RES1 0x000008d8
115#define NV50_EVO_CRTC_SCALE_RES2 0x000008dc 115#define NV50_EVO_CRTC_SCALE_RES2 0x000008dc
116#define NV50_EVO_CRTC_UNK900 0x00000900
117#define NV50_EVO_CRTC_UNK904 0x00000904
116 118
117#endif 119#endif