Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+245 -5
+2
drivers/gpu/drm/nouveau/nouveau_dma.h
··· 73 73 NvImageBlit = 0x8000000d, 74 74 NvSw = 0x8000000e, 75 75 NvSema = 0x8000000f, 76 + NvEvoSema0 = 0x80000010, 77 + NvEvoSema1 = 0x80000011, 76 78 77 79 /* G80+ display objects */ 78 80 NvEvoVRAM = 0x01000000,
+21 -1
drivers/gpu/drm/nouveau/nouveau_object.c
··· 36 36 #include "nouveau_drm.h" 37 37 #include "nouveau_ramht.h" 38 38 #include "nouveau_vm.h" 39 + #include "nv50_display.h" 39 40 40 41 struct nouveau_gpuobj_method { 41 42 struct list_head head; ··· 783 782 struct drm_device *dev = chan->dev; 784 783 struct drm_nouveau_private *dev_priv = dev->dev_private; 785 784 struct nouveau_gpuobj *vram = NULL, *tt = NULL; 786 - int ret; 785 + int ret, i; 787 786 788 787 NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); 789 788 ··· 848 847 nouveau_gpuobj_ref(NULL, &ramht); 849 848 if (ret) 850 849 return ret; 850 + 851 + /* dma objects for display sync channel semaphore blocks */ 852 + for (i = 0; i < 2; i++) { 853 + struct nouveau_gpuobj *sem = NULL; 854 + struct nv50_display_crtc *dispc = 855 + &nv50_display(dev)->crtc[i]; 856 + u64 offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT; 857 + 858 + ret = nouveau_gpuobj_dma_new(chan, 0x3d, offset, 0xfff, 859 + NV_MEM_ACCESS_RW, 860 + NV_MEM_TARGET_VRAM, &sem); 861 + if (ret) 862 + return ret; 863 + 864 + ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, sem); 865 + nouveau_gpuobj_ref(NULL, &sem); 866 + if (ret) 867 + return ret; 868 + } 851 869 } 852 870 853 871 /* VRAM ctxdma */
+122 -1
drivers/gpu/drm/nouveau/nv50_display.c
··· 178 178 179 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 182 if (ret) 183 183 return ret; 184 184 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); ··· 192 192 OUT_RING(evo, 0); 193 193 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); 194 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 200 FIRE_RING(evo); 196 201 if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) 197 202 NV_ERROR(dev, "evo pushbuf stalled\n"); ··· 369 364 nv50_display_disable(dev); 370 365 nouveau_irq_unregister(dev, 26); 371 366 kfree(disp); 367 + } 368 + 369 + void 370 + nv50_display_flip_stop(struct drm_crtc *crtc) 371 + { 372 + struct nv50_display *disp = nv50_display(crtc->dev); 373 + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 374 + struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index]; 375 + struct nouveau_channel *evo = dispc->sync; 376 + int ret; 377 + 378 + ret = RING_SPACE(evo, 8); 379 + if (ret) { 380 + WARN_ON(1); 381 + return; 382 + } 383 + 384 + BEGIN_RING(evo, 0, 0x0084, 1); 385 + OUT_RING (evo, 0x00000000); 386 + BEGIN_RING(evo, 0, 0x0094, 1); 387 + OUT_RING (evo, 0x00000000); 388 + BEGIN_RING(evo, 0, 0x00c0, 1); 389 + OUT_RING (evo, 0x00000000); 390 + BEGIN_RING(evo, 0, 0x0080, 1); 391 + OUT_RING (evo, 0x00000000); 392 + FIRE_RING (evo); 393 + } 394 + 395 + int 396 + nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, 397 + struct nouveau_channel *chan) 398 + { 399 + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; 400 + struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); 401 + struct nv50_display *disp = nv50_display(crtc->dev); 402 + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 403 + struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index]; 404 + struct nouveau_channel *evo = dispc->sync; 405 + int ret; 406 + 407 + ret = RING_SPACE(evo, 24); 408 + if (unlikely(ret)) 409 + return ret; 410 + 411 + /* synchronise with the rendering channel, if necessary */ 412 + if (likely(chan)) { 413 + u64 offset = dispc->sem.bo->vma.offset + dispc->sem.offset; 414 + 415 + ret = RING_SPACE(chan, 10); 416 + if (ret) { 417 + WIND_RING(evo); 418 + return ret; 419 + } 420 + 421 + if (dev_priv->chipset < 0xc0) { 422 + BEGIN_RING(chan, NvSubSw, 0x0060, 2); 423 + OUT_RING (chan, NvEvoSema0 + nv_crtc->index); 424 + OUT_RING (chan, dispc->sem.offset); 425 + BEGIN_RING(chan, NvSubSw, 0x006c, 1); 426 + OUT_RING (chan, 0xf00d0000 | dispc->sem.value); 427 + BEGIN_RING(chan, NvSubSw, 0x0064, 2); 428 + OUT_RING (chan, dispc->sem.offset ^ 0x10); 429 + OUT_RING (chan, 0x74b1e000); 430 + BEGIN_RING(chan, NvSubSw, 0x0060, 1); 431 + if (dev_priv->chipset < 0x84) 432 + OUT_RING (chan, NvSema); 433 + else 434 + OUT_RING (chan, chan->vram_handle); 435 + } else { 436 + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); 437 + OUT_RING (chan, upper_32_bits(offset)); 438 + OUT_RING (chan, lower_32_bits(offset)); 439 + OUT_RING (chan, 0xf00d0000 | dispc->sem.value); 440 + OUT_RING (chan, 0x1002); 441 + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); 442 + OUT_RING (chan, upper_32_bits(offset)); 443 + OUT_RING (chan, lower_32_bits(offset ^ 0x10)); 444 + OUT_RING (chan, 0x74b1e000); 445 + OUT_RING (chan, 0x1001); 446 + } 447 + FIRE_RING (chan); 448 + } else { 449 + nouveau_bo_wr32(dispc->sem.bo, dispc->sem.offset / 4, 450 + 0xf00d0000 | dispc->sem.value); 451 + } 452 + 453 + /* queue the flip on the crtc's "display sync" channel */ 454 + BEGIN_RING(evo, 0, 0x0100, 1); 455 + OUT_RING (evo, 0xfffe0000); 456 + BEGIN_RING(evo, 0, 0x0084, 5); 457 + OUT_RING (evo, chan ? 0x00000100 : 0x00000010); 458 + OUT_RING (evo, dispc->sem.offset); 459 + OUT_RING (evo, 0xf00d0000 | dispc->sem.value); 460 + OUT_RING (evo, 0x74b1e000); 461 + OUT_RING (evo, NvEvoSync); 462 + BEGIN_RING(evo, 0, 0x00a0, 2); 463 + OUT_RING (evo, 0x00000000); 464 + OUT_RING (evo, 0x00000000); 465 + BEGIN_RING(evo, 0, 0x00c0, 1); 466 + OUT_RING (evo, nv_fb->r_dma); 467 + BEGIN_RING(evo, 0, 0x0110, 2); 468 + OUT_RING (evo, 0x00000000); 469 + OUT_RING (evo, 0x00000000); 470 + BEGIN_RING(evo, 0, 0x0800, 5); 471 + OUT_RING (evo, (nv_fb->nvbo->bo.mem.start << PAGE_SHIFT) >> 8); 472 + OUT_RING (evo, 0); 473 + OUT_RING (evo, (fb->height << 16) | fb->width); 474 + OUT_RING (evo, nv_fb->r_pitch); 475 + OUT_RING (evo, nv_fb->r_format); 476 + BEGIN_RING(evo, 0, 0x0080, 1); 477 + OUT_RING (evo, 0x00000000); 478 + FIRE_RING (evo); 479 + 480 + dispc->sem.offset ^= 0x10; 481 + dispc->sem.value++; 482 + return 0; 372 483 } 373 484 374 485 static u16
+15
drivers/gpu/drm/nouveau/nv50_display.h
··· 35 35 #include "nouveau_crtc.h" 36 36 #include "nv50_evo.h" 37 37 38 + struct 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 + 38 47 struct nv50_display { 39 48 struct nouveau_channel *master; 40 49 struct nouveau_gpuobj *ntfy; 50 + 51 + struct nv50_display_crtc crtc[2]; 41 52 42 53 struct tasklet_struct tasklet; 43 54 struct { ··· 72 61 void nv50_display_destroy(struct drm_device *dev); 73 62 int nv50_crtc_blank(struct nouveau_crtc *, bool blank); 74 63 int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); 64 + 65 + int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *, 66 + struct nouveau_channel *chan); 67 + void nv50_display_flip_stop(struct drm_crtc *); 75 68 76 69 int nv50_evo_init(struct drm_device *dev); 77 70 void nv50_evo_fini(struct drm_device *dev);
+83 -3
drivers/gpu/drm/nouveau/nv50_evo.c
··· 220 220 nv50_evo_destroy(struct drm_device *dev) 221 221 { 222 222 struct nv50_display *disp = nv50_display(dev); 223 + int i; 223 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 232 nouveau_gpuobj_ref(NULL, &disp->ntfy); 225 233 nv50_evo_channel_del(&disp->master); 226 234 } ··· 240 232 struct nv50_display *disp = nv50_display(dev); 241 233 struct nouveau_gpuobj *ramht = NULL; 242 234 struct nouveau_channel *evo; 243 - int ret; 235 + int ret, i, j; 244 236 245 237 /* create primary evo channel, the one we use for modesetting 246 238 * purporses ··· 319 311 if (ret) 320 312 goto err; 321 313 314 + /* create "display sync" channels and other structures we need 315 + * to implement page flipping 316 + */ 317 + for (i = 0; i < 2; i++) { 318 + struct nv50_display_crtc *dispc = &disp->crtc[i]; 319 + u64 offset; 320 + 321 + ret = nv50_evo_channel_new(dev, 1 + i, &dispc->sync); 322 + if (ret) 323 + goto err; 324 + 325 + ret = nouveau_bo_new(dev, NULL, 4096, 0x1000, TTM_PL_FLAG_VRAM, 326 + 0, 0x0000, false, true, &dispc->sem.bo); 327 + if (!ret) { 328 + offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT; 329 + 330 + ret = nouveau_bo_pin(dispc->sem.bo, TTM_PL_FLAG_VRAM); 331 + if (!ret) 332 + ret = nouveau_bo_map(dispc->sem.bo); 333 + if (ret) 334 + nouveau_bo_ref(NULL, &dispc->sem.bo); 335 + } 336 + 337 + if (ret) 338 + goto err; 339 + 340 + ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoSync, 0x0000, 341 + offset, 4096, NULL); 342 + if (ret) 343 + goto err; 344 + 345 + ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoVRAM_LP, 0x80000000, 346 + 0, dev_priv->vram_size, NULL); 347 + if (ret) 348 + goto err; 349 + 350 + ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB32, 0x80000000 | 351 + (dev_priv->chipset < 0xc0 ? 352 + 0x7a00 : 0xfe00), 353 + 0, dev_priv->vram_size, NULL); 354 + if (ret) 355 + goto err; 356 + 357 + ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB16, 0x80000000 | 358 + (dev_priv->chipset < 0xc0 ? 359 + 0x7000 : 0xfe00), 360 + 0, dev_priv->vram_size, NULL); 361 + if (ret) 362 + goto err; 363 + 364 + for (j = 0; j < 4096; j += 4) 365 + nouveau_bo_wr32(dispc->sem.bo, j / 4, 0x74b1e000); 366 + dispc->sem.offset = 0; 367 + } 368 + 322 369 return 0; 323 370 324 371 err: ··· 385 322 nv50_evo_init(struct drm_device *dev) 386 323 { 387 324 struct nv50_display *disp = nv50_display(dev); 388 - int ret; 325 + int ret, i; 389 326 390 327 if (!disp->master) { 391 328 ret = nv50_evo_create(dev); ··· 393 330 return ret; 394 331 } 395 332 396 - return nv50_evo_channel_init(disp->master); 333 + ret = nv50_evo_channel_init(disp->master); 334 + if (ret) 335 + return ret; 336 + 337 + for (i = 0; i < 2; i++) { 338 + ret = nv50_evo_channel_init(disp->crtc[i].sync); 339 + if (ret) 340 + return ret; 341 + } 342 + 343 + return 0; 397 344 } 398 345 399 346 void 400 347 nv50_evo_fini(struct drm_device *dev) 401 348 { 402 349 struct nv50_display *disp = nv50_display(dev); 350 + int i; 351 + 352 + for (i = 0; i < 2; i++) { 353 + if (disp->crtc[i].sync) 354 + nv50_evo_channel_fini(disp->crtc[i].sync); 355 + } 403 356 404 357 if (disp->master) 405 358 nv50_evo_channel_fini(disp->master); 359 + 406 360 nv50_evo_destroy(dev); 407 361 }
+2
drivers/gpu/drm/nouveau/nv50_evo.h
··· 113 113 /* Both of these are needed, otherwise nothing happens. */ 114 114 #define NV50_EVO_CRTC_SCALE_RES1 0x000008d8 115 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 119 #endif