drm/nouveau/bus/hwsq: Implement VBLANK waiting heuristic
authorRoy Spliet <rspliet@eclipso.eu>
Tue, 29 Sep 2015 23:23:51 +0000 (00:23 +0100)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 3 Nov 2015 05:02:18 +0000 (15:02 +1000)
Avoids waiting for VBLANKS that never arrive on headless or otherwise
unconventional set-ups. Strategy taken from MEMX.

Signed-off-by: Roy Spliet <rspliet@eclipso.eu>
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h
drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c
drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h

index 6a04d9c..33a057c 100644 (file)
@@ -14,6 +14,7 @@ int  nvkm_hwsq_fini(struct nvkm_hwsq **, bool exec);
 void nvkm_hwsq_wr32(struct nvkm_hwsq *, u32 addr, u32 data);
 void nvkm_hwsq_setf(struct nvkm_hwsq *, u8 flag, int data);
 void nvkm_hwsq_wait(struct nvkm_hwsq *, u8 flag, u8 data);
+void nvkm_hwsq_wait_vblank(struct nvkm_hwsq *);
 void nvkm_hwsq_nsec(struct nvkm_hwsq *, u32 nsec);
 
 int nv04_bus_new(struct nvkm_device *, int, struct nvkm_bus **);
index 79f1cf5..2a56689 100644 (file)
@@ -132,6 +132,38 @@ nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data)
 }
 
 void
+nvkm_hwsq_wait_vblank(struct nvkm_hwsq *hwsq)
+{
+       struct nvkm_subdev *subdev = hwsq->subdev;
+       struct nvkm_device *device = subdev->device;
+       u32 heads, x, y, px = 0;
+       int i, head_sync;
+
+       heads = nvkm_rd32(device, 0x610050);
+       for (i = 0; i < 2; i++) {
+               /* Heuristic: sync to head with biggest resolution */
+               if (heads & (2 << (i << 3))) {
+                       x = nvkm_rd32(device, 0x610b40 + (0x540 * i));
+                       y = (x & 0xffff0000) >> 16;
+                       x &= 0x0000ffff;
+                       if ((x * y) > px) {
+                               px = (x * y);
+                               head_sync = i;
+                       }
+               }
+       }
+
+       if (px == 0) {
+               nvkm_debug(subdev, "WAIT VBLANK !NO ACTIVE HEAD\n");
+               return;
+       }
+
+       nvkm_debug(subdev, "WAIT VBLANK HEAD%d\n", head_sync);
+       nvkm_hwsq_wait(hwsq, head_sync ? 0x3 : 0x1, 0x0);
+       nvkm_hwsq_wait(hwsq, head_sync ? 0x3 : 0x1, 0x1);
+}
+
+void
 nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec)
 {
        u8 shift = 0, usec = nsec / 1000;
index 8117ec5..54ec3b1 100644 (file)
@@ -134,6 +134,12 @@ hwsq_wait(struct hwsq *ram, u8 flag, u8 data)
 }
 
 static inline void
+hwsq_wait_vblank(struct hwsq *ram)
+{
+       nvkm_hwsq_wait_vblank(ram->hwsq);
+}
+
+static inline void
 hwsq_nsec(struct hwsq *ram, u32 nsec)
 {
        nvkm_hwsq_nsec(ram->hwsq, nsec);
index d98d306..87bde8f 100644 (file)
@@ -308,8 +308,7 @@ nv50_ram_calc(struct nvkm_ram *base, u32 freq)
        /* Always disable this bit during reclock */
        ram_mask(hwsq, 0x100200, 0x00000800, 0x00000000);
 
-       ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */
-       ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */
+       ram_wait_vblank(hwsq);
        ram_wr32(hwsq, 0x611200, 0x00003300);
        ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
        ram_nsec(hwsq, 8000);
index 0f1f97c..8df7306 100644 (file)
@@ -11,5 +11,6 @@
 #define ram_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
 #define ram_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
 #define ram_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
+#define ram_wait_vblank(s)  hwsq_wait_vblank(&(s)->base)
 #define ram_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
 #endif