summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoy Spliet <rspliet@eclipso.eu>2015-09-30 00:23:51 +0100
committerBen Skeggs <bskeggs@redhat.com>2015-11-03 14:57:48 +1000
commit46868d4272d0744ae626546d05f0a924e7704b1a (patch)
tree62dec84e76d87f5e9d75ba2171f44b5c42c5c1c5
parent50940f81268c0c606e96e8a0019b414cd512059c (diff)
bus/hwsq: Implement VBLANK waiting heuristic
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>
-rw-r--r--drm/nouveau/include/nvkm/subdev/bus.h1
-rw-r--r--drm/nouveau/nvkm/subdev/bus/hwsq.c32
-rw-r--r--drm/nouveau/nvkm/subdev/bus/hwsq.h6
-rw-r--r--drm/nouveau/nvkm/subdev/fb/ramnv50.c3
-rw-r--r--drm/nouveau/nvkm/subdev/fb/ramseq.h1
5 files changed, 41 insertions, 2 deletions
diff --git a/drm/nouveau/include/nvkm/subdev/bus.h b/drm/nouveau/include/nvkm/subdev/bus.h
index 6a04d9c0..33a057c3 100644
--- a/drm/nouveau/include/nvkm/subdev/bus.h
+++ b/drm/nouveau/include/nvkm/subdev/bus.h
@@ -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 **);
diff --git a/drm/nouveau/nvkm/subdev/bus/hwsq.c b/drm/nouveau/nvkm/subdev/bus/hwsq.c
index 79f1cf51..2a566893 100644
--- a/drm/nouveau/nvkm/subdev/bus/hwsq.c
+++ b/drm/nouveau/nvkm/subdev/bus/hwsq.c
@@ -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;
diff --git a/drm/nouveau/nvkm/subdev/bus/hwsq.h b/drm/nouveau/nvkm/subdev/bus/hwsq.h
index 8117ec5a..54ec3b13 100644
--- a/drm/nouveau/nvkm/subdev/bus/hwsq.h
+++ b/drm/nouveau/nvkm/subdev/bus/hwsq.h
@@ -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);
diff --git a/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drm/nouveau/nvkm/subdev/fb/ramnv50.c
index d98d3069..87bde8ff 100644
--- a/drm/nouveau/nvkm/subdev/fb/ramnv50.c
+++ b/drm/nouveau/nvkm/subdev/fb/ramnv50.c
@@ -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);
diff --git a/drm/nouveau/nvkm/subdev/fb/ramseq.h b/drm/nouveau/nvkm/subdev/fb/ramseq.h
index 0f1f97cc..8df7306d 100644
--- a/drm/nouveau/nvkm/subdev/fb/ramseq.h
+++ b/drm/nouveau/nvkm/subdev/fb/ramseq.h
@@ -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