summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/gm107.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv04.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c61
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv84.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv94.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva3.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c66
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c22
-rw-r--r--drivers/gpu/drm/nouveau/nvif/class.h23
-rw-r--r--drivers/gpu/drm/nouveau/nvif/object.h1
15 files changed, 204 insertions, 172 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
index f93d76e040fe..6a25f38d7fbf 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
@@ -45,7 +45,7 @@ gm107_disp_sclass[] = {
 
 static struct nouveau_oclass
 gm107_disp_base_oclass[] = {
-	{ GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
+	{ GM107_DISP_CLASS, &nvd0_disp_base_ofuncs },
 	{}
 };
 
@@ -99,4 +99,5 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nvd0_disp_sync_mthd_chan,
 	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
 	.mthd.prev = -0x020000,
+	.head.scanoutpos = nvd0_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
index f1f3bd15a5c0..6dba53df35fc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
@@ -24,60 +24,100 @@
 
 #include "priv.h"
 
+#include <core/client.h>
 #include <core/event.h>
 #include <core/class.h>
+#include <nvif/unpack.h>
+#include <nvif/class.h>
 
 struct nv04_disp_priv {
 	struct nouveau_disp base;
 };
 
 static int
-nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd,
-		     void *data, u32 size)
+nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv,
+		     void *data, u32 size, int head)
 {
-	struct nv04_disp_priv *priv = (void *)object->engine;
-	struct nv04_display_scanoutpos *args = data;
-	const int head = (mthd & NV04_DISP_MTHD_HEAD);
+	const u32 hoff = head * 0x2000;
+	union {
+		struct nv04_disp_scanoutpos_v0 v0;
+	} *args = data;
 	u32 line;
+	int ret;
+
+	nv_ioctl(object, "disp scanoutpos size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+		args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
+		args->v0.vtotal  = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
+		args->v0.vblanke = args->v0.vtotal - 1;
+
+		args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
+		args->v0.htotal  = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
+		args->v0.hblanke = args->v0.htotal - 1;
+
+		/*
+		 * If output is vga instead of digital then vtotal/htotal is
+		 * invalid so we have to give up and trigger the timestamping
+		 * fallback in the drm core.
+		 */
+		if (!args->v0.vtotal || !args->v0.htotal)
+			return -ENOTSUPP;
+
+		args->v0.time[0] = ktime_to_ns(ktime_get());
+		line = nv_rd32(priv, 0x600868 + hoff);
+		args->v0.time[1] = ktime_to_ns(ktime_get());
+		args->v0.hline = (line & 0xffff0000) >> 16;
+		args->v0.vline = (line & 0x0000ffff);
+	} else
+		return ret;
 
-	if (size < sizeof(*args))
-		return -EINVAL;
-
-	args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff;
-	args->vtotal  = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff;
-	args->vblanke = args->vtotal - 1;
-
-	args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff;
-	args->htotal  = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff;
-	args->hblanke = args->htotal - 1;
-
-	/*
-	 * If output is vga instead of digital then vtotal/htotal is invalid
-	 * so we have to give up and trigger the timestamping fallback in the
-	 * drm core.
-	 */
-	if (!args->vtotal || !args->htotal)
-		return -ENOTSUPP;
-
-	args->time[0] = ktime_to_ns(ktime_get());
-	line = nv_rd32(priv, 0x600868 + (head * 0x2000));
-	args->time[1] = ktime_to_ns(ktime_get());
-	args->hline = (line & 0xffff0000) >> 16;
-	args->vline = (line & 0x0000ffff);
 	return 0;
 }
 
-#define HEAD_MTHD(n) (n), (n) + 0x01
+static int
+nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
+{
+	union {
+		struct nv04_disp_mthd_v0 v0;
+	} *args = data;
+	struct nv04_disp_priv *priv = (void *)object->engine;
+	int head, ret;
+
+	nv_ioctl(object, "disp mthd size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
+			 args->v0.version, args->v0.method, args->v0.head);
+		mthd = args->v0.method;
+		head = args->v0.head;
+	} else
+		return ret;
+
+	if (head < 0 || head >= 2)
+		return -ENXIO;
+
+	switch (mthd) {
+	case NV04_DISP_SCANOUTPOS:
+		return nv04_disp_scanoutpos(object, priv, data, size, head);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
 
-static struct nouveau_omthds
-nv04_disp_omthds[] = {
-	{ HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos },
-	{}
+static struct nouveau_ofuncs
+nv04_disp_ofuncs = {
+	.ctor = _nouveau_object_ctor,
+	.dtor = nouveau_object_destroy,
+	.init = nouveau_object_init,
+	.fini = nouveau_object_fini,
+	.mthd = nv04_disp_mthd,
 };
 
 static struct nouveau_oclass
 nv04_disp_sclass[] = {
-	{ NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds },
+	{ NV04_DISP_CLASS, &nv04_disp_ofuncs },
 	{},
 };
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index d83d3efe8253..7e60c11d7d36 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -814,31 +814,34 @@ nv50_disp_curs_ofuncs = {
  ******************************************************************************/
 
 int
-nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
-			  void *data, u32 size)
+nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
 {
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv04_display_scanoutpos *args = data;
-	const int head = (mthd & NV50_DISP_MTHD_HEAD);
-	u32 blanke, blanks, total;
+	const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
+	const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
+	const u32 total  = nv_rd32(priv, 0x610afc + (head * 0x540));
+	union {
+		struct nv04_disp_scanoutpos_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "disp scanoutpos size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+		args->v0.vblanke = (blanke & 0xffff0000) >> 16;
+		args->v0.hblanke = (blanke & 0x0000ffff);
+		args->v0.vblanks = (blanks & 0xffff0000) >> 16;
+		args->v0.hblanks = (blanks & 0x0000ffff);
+		args->v0.vtotal  = ( total & 0xffff0000) >> 16;
+		args->v0.htotal  = ( total & 0x0000ffff);
+		args->v0.time[0] = ktime_to_ns(ktime_get());
+		args->v0.vline = /* vline read locks hline */
+			nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+		args->v0.time[1] = ktime_to_ns(ktime_get());
+		args->v0.hline =
+			nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+	} else
+		return ret;
 
-	if (size < sizeof(*args) || head >= priv->head.nr)
-		return -EINVAL;
-	blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
-	blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
-	total  = nv_rd32(priv, 0x610afc + (head * 0x540));
-
-	args->vblanke = (blanke & 0xffff0000) >> 16;
-	args->hblanke = (blanke & 0x0000ffff);
-	args->vblanks = (blanks & 0xffff0000) >> 16;
-	args->hblanks = (blanks & 0x0000ffff);
-	args->vtotal  = ( total & 0xffff0000) >> 16;
-	args->htotal  = ( total & 0x0000ffff);
-
-	args->time[0] = ktime_to_ns(ktime_get());
-	args->vline   = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
-	args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
-	args->hline   = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
 	return 0;
 }
 
@@ -846,6 +849,7 @@ int
 nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
 		    void *data, u32 size)
 {
+	const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
 	union {
 		struct nv50_disp_mthd_v0 v0;
 		struct nv50_disp_mthd_v1 v1;
@@ -894,6 +898,8 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
 	}
 
 	switch (mthd) {
+	case NV50_DISP_SCANOUTPOS:
+		return impl->head.scanoutpos(object, priv, data, size, head);
 	default:
 		break;
 	}
@@ -1081,15 +1087,9 @@ nv50_disp_base_ofuncs = {
 	.mthd = nv50_disp_base_mthd,
 };
 
-static struct nouveau_omthds
-nv50_disp_base_omthds[] = {
-	{ HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
-	{},
-};
-
 static struct nouveau_oclass
 nv50_disp_base_oclass[] = {
-	{ NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds },
+	{ NV50_DISP_CLASS, &nv50_disp_base_ofuncs },
 	{}
 };
 
@@ -1859,4 +1859,5 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nv50_disp_sync_mthd_chan,
 	.mthd.ovly = &nv50_disp_ovly_mthd_chan,
 	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
index 62a38b5f0024..81bf80fd8dcd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
@@ -14,16 +14,6 @@
 #include "outp.h"
 #include "outpdp.h"
 
-struct nv50_disp_impl {
-	struct nouveau_disp_impl base;
-	struct {
-		const struct nv50_disp_mthd_chan *core;
-		const struct nv50_disp_mthd_chan *base;
-		const struct nv50_disp_mthd_chan *ovly;
-		int prev;
-	} mthd;
-};
-
 #define NV50_DISP_MTHD_ struct nouveau_object *object,                         \
 	struct nv50_disp_priv *priv, void *data, u32 size
 #define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
@@ -58,18 +48,27 @@ struct nv50_disp_priv {
 	} pior;
 };
 
-#define HEAD_MTHD(n) (n), (n) + 0x03
+struct nv50_disp_impl {
+	struct nouveau_disp_impl base;
+	struct {
+		const struct nv50_disp_mthd_chan *core;
+		const struct nv50_disp_mthd_chan *base;
+		const struct nv50_disp_mthd_chan *ovly;
+		int prev;
+	} mthd;
+	struct {
+		int (*scanoutpos)(NV50_DISP_MTHD_V0);
+	} head;
+};
 
-int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32);
+int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
 int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
 
-#define DAC_MTHD(n) (n), (n) + 0x03
+int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
 
 int nv50_dac_power(NV50_DISP_MTHD_V1);
 int nv50_dac_sense(NV50_DISP_MTHD_V1);
 
-#define SOR_MTHD(n) (n), (n) + 0x3f
-
 int nva3_hda_eld(NV50_DISP_MTHD_V1);
 int nvd0_hda_eld(NV50_DISP_MTHD_V1);
 
@@ -97,8 +96,6 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
 int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
 		       struct dcb_output *);
 
-#define PIOR_MTHD(n) (n), (n) + 0x03
-
 int nv50_pior_power(NV50_DISP_MTHD_V1);
 
 struct nv50_disp_base {
@@ -203,7 +200,6 @@ extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
 extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head;
 extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan;
 extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
-extern struct nouveau_omthds nv84_disp_base_omthds[];
 
 extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan;
 
@@ -217,7 +213,6 @@ extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
 extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan;
 extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
 extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
-extern struct nouveau_omthds nvd0_disp_base_omthds[];
 extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
 extern struct nouveau_oclass nvd0_disp_cclass;
 void nvd0_disp_intr_supervisor(struct work_struct *);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
index c0012d8a450a..8746644d9ded 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
@@ -212,15 +212,9 @@ nv84_disp_sclass[] = {
 	{}
 };
 
-struct nouveau_omthds
-nv84_disp_base_omthds[] = {
-	{ HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
-	{},
-};
-
 static struct nouveau_oclass
 nv84_disp_base_oclass[] = {
-	{ NV84_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds },
+	{ NV84_DISP_CLASS, &nv50_disp_base_ofuncs },
 	{}
 };
 
@@ -274,4 +268,5 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nv84_disp_sync_mthd_chan,
 	.mthd.ovly = &nv84_disp_ovly_mthd_chan,
 	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
index 192c8085a1dc..11cd16abcee2 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
@@ -71,15 +71,9 @@ nv94_disp_sclass[] = {
 	{}
 };
 
-static struct nouveau_omthds
-nv94_disp_base_omthds[] = {
-	{ HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
-	{},
-};
-
 static struct nouveau_oclass
 nv94_disp_base_oclass[] = {
-	{ NV94_DISP_CLASS, &nv50_disp_base_ofuncs, nv94_disp_base_omthds },
+	{ NV94_DISP_CLASS, &nv50_disp_base_ofuncs },
 	{}
 };
 
@@ -140,4 +134,5 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nv84_disp_sync_mthd_chan,
 	.mthd.ovly = &nv84_disp_ovly_mthd_chan,
 	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
index bfd5cf14b0e4..381957586f03 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
@@ -90,7 +90,7 @@ nva0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nva0_disp_base_oclass[] = {
-	{ NVA0_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds },
+	{ NVA0_DISP_CLASS, &nv50_disp_base_ofuncs },
 	{}
 };
 
@@ -144,4 +144,5 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nv84_disp_sync_mthd_chan,
 	.mthd.ovly = &nva0_disp_ovly_mthd_chan,
 	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
index 38a79a0e358f..25df6b93c93a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
@@ -43,15 +43,9 @@ nva3_disp_sclass[] = {
 	{}
 };
 
-static struct nouveau_omthds
-nva3_disp_base_omthds[] = {
-	{ HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
-	{},
-};
-
 static struct nouveau_oclass
 nva3_disp_base_oclass[] = {
-	{ NVA3_DISP_CLASS, &nv50_disp_base_ofuncs, nva3_disp_base_omthds },
+	{ NVA3_DISP_CLASS, &nv50_disp_base_ofuncs },
 	{}
 };
 
@@ -106,4 +100,5 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nv84_disp_sync_mthd_chan,
 	.mthd.ovly = &nv84_disp_ovly_mthd_chan,
 	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 5aa44eca8056..deddd05e7c76 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -23,9 +23,12 @@
  */
 
 #include <core/object.h>
+#include <core/client.h>
 #include <core/parent.h>
 #include <core/handle.h>
 #include <core/class.h>
+#include <nvif/unpack.h>
+#include <nvif/class.h>
 
 #include <engine/disp.h>
 
@@ -589,33 +592,35 @@ nvd0_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
-static int
-nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
-			  void *data, u32 size)
+int
+nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
 {
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv04_display_scanoutpos *args = data;
-	const int head = (mthd & NV50_DISP_MTHD_HEAD);
-	u32 blanke, blanks, total;
-
-	if (size < sizeof(*args) || head >= priv->head.nr)
-		return -EINVAL;
-
-	total  = nv_rd32(priv, 0x640414 + (head * 0x300));
-	blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
-	blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
-
-	args->vblanke = (blanke & 0xffff0000) >> 16;
-	args->hblanke = (blanke & 0x0000ffff);
-	args->vblanks = (blanks & 0xffff0000) >> 16;
-	args->hblanks = (blanks & 0x0000ffff);
-	args->vtotal  = ( total & 0xffff0000) >> 16;
-	args->htotal  = ( total & 0x0000ffff);
-
-	args->time[0] = ktime_to_ns(ktime_get());
-	args->vline   = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
-	args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
-	args->hline   = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+	const u32 total  = nv_rd32(priv, 0x640414 + (head * 0x300));
+	const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
+	const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
+	union {
+		struct nv04_disp_scanoutpos_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "disp scanoutpos size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+		args->v0.vblanke = (blanke & 0xffff0000) >> 16;
+		args->v0.hblanke = (blanke & 0x0000ffff);
+		args->v0.vblanks = (blanks & 0xffff0000) >> 16;
+		args->v0.hblanks = (blanks & 0x0000ffff);
+		args->v0.vtotal  = ( total & 0xffff0000) >> 16;
+		args->v0.htotal  = ( total & 0x0000ffff);
+		args->v0.time[0] = ktime_to_ns(ktime_get());
+		args->v0.vline = /* vline read locks hline */
+			nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+		args->v0.time[1] = ktime_to_ns(ktime_get());
+		args->v0.hline =
+			nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+	} else
+		return ret;
+
 	return 0;
 }
 
@@ -709,15 +714,9 @@ nvd0_disp_base_ofuncs = {
 	.mthd = nv50_disp_base_mthd,
 };
 
-struct nouveau_omthds
-nvd0_disp_base_omthds[] = {
-	{ HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nvd0_disp_base_scanoutpos },
-	{},
-};
-
 static struct nouveau_oclass
 nvd0_disp_base_oclass[] = {
-	{ NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
+	{ NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs },
 	{}
 };
 
@@ -1242,4 +1241,5 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nvd0_disp_sync_mthd_chan,
 	.mthd.ovly = &nvd0_disp_ovly_mthd_chan,
 	.mthd.prev = -0x020000,
+	.head.scanoutpos = nvd0_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index 49ab742faae9..58b0ac101f16 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -210,7 +210,7 @@ nve0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nve0_disp_base_oclass[] = {
-	{ NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
+	{ NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs },
 	{}
 };
 
@@ -264,4 +264,5 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nvd0_disp_sync_mthd_chan,
 	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
 	.mthd.prev = -0x020000,
+	.head.scanoutpos = nvd0_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
index 448dc912d0ce..b6b01463eb6c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
@@ -45,7 +45,7 @@ nvf0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nvf0_disp_base_oclass[] = {
-	{ NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
+	{ NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs },
 	{}
 };
 
@@ -99,4 +99,5 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
 	.mthd.base = &nvd0_disp_sync_mthd_chan,
 	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
 	.mthd.prev = -0x020000,
+	.head.scanoutpos = nvd0_disp_base_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index 9f8066d252f0..24b85a9ac657 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -8,26 +8,9 @@
 
 #define NV04_DISP_CLASS                                              0x00000046
 
-#define NV04_DISP_MTHD                                               0x00000000
-#define NV04_DISP_MTHD_HEAD                                          0x00000001
-
-#define NV04_DISP_SCANOUTPOS                                         0x00000000
-
 struct nv04_display_class {
 };
 
-struct nv04_display_scanoutpos {
-	s64 time[2];
-	u32 vblanks;
-	u32 vblanke;
-	u32 vtotal;
-	u32 vline;
-	u32 hblanks;
-	u32 hblanke;
-	u32 htotal;
-	u32 hline;
-};
-
 /* 5070: NV50_DISP
  * 8270: NV84_DISP
  * 8370: NVA0_DISP
@@ -49,10 +32,6 @@ struct nv04_display_scanoutpos {
 #define NVF0_DISP_CLASS                                              0x00009270
 #define GM107_DISP_CLASS                                             0x00009470
 
-#define NV50_DISP_MTHD_HEAD                                          0x00000003
-
-#define NV50_DISP_SCANOUTPOS                                         0x00000000
-
 struct nv50_display_class {
 };
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index ffea6c4f9b30..f00e56c79ac4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -95,17 +95,22 @@ int
 nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
 				ktime_t *stime, ktime_t *etime)
 {
-	const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index;
+	struct {
+		struct nv04_disp_mthd_v0 base;
+		struct nv04_disp_scanoutpos_v0 scan;
+	} args = {
+		.base.method = NV04_DISP_SCANOUTPOS,
+		.base.head = nouveau_crtc(crtc)->index,
+	};
 	struct nouveau_display *disp = nouveau_display(crtc->dev);
-	struct nv04_display_scanoutpos args;
 	int ret, retry = 1;
 
 	do {
-		ret = nvif_exec(&disp->disp, mthd, &args, sizeof(args));
+		ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));
 		if (ret != 0)
 			return 0;
 
-		if (args.vline) {
+		if (args.scan.vline) {
 			ret |= DRM_SCANOUTPOS_ACCURATE;
 			ret |= DRM_SCANOUTPOS_VALID;
 			break;
@@ -114,10 +119,11 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
 		if (retry) ndelay(crtc->linedur_ns);
 	} while (retry--);
 
-	*hpos = args.hline;
-	*vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
-	if (stime) *stime = ns_to_ktime(args.time[0]);
-	if (etime) *etime = ns_to_ktime(args.time[1]);
+	*hpos = args.scan.hline;
+	*vpos = calc(args.scan.vblanks, args.scan.vblanke,
+		     args.scan.vtotal, args.scan.vline);
+	if (stime) *stime = ns_to_ktime(args.scan.time[0]);
+	if (etime) *etime = ns_to_ktime(args.scan.time[1]);
 
 	if (*vpos < 0)
 		ret |= DRM_SCANOUTPOS_INVBL;
diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h
index f869f94d41c1..b0998e7a5396 100644
--- a/drivers/gpu/drm/nouveau/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/nvif/class.h
@@ -294,6 +294,28 @@ struct kepler_channel_gpfifo_a_v0 {
  * legacy display
  ******************************************************************************/
 
+struct nv04_disp_mthd_v0 {
+	__u8  version;
+#define NV04_DISP_SCANOUTPOS                                               0x00
+	__u8  method;
+	__u8  head;
+	__u8  pad03[5];
+};
+
+struct nv04_disp_scanoutpos_v0 {
+	__u8  version;
+	__u8  pad01[7];
+	__s64 time[2];
+	__u16 vblanks;
+	__u16 vblanke;
+	__u16 vtotal;
+	__u16 vline;
+	__u16 hblanks;
+	__u16 hblanke;
+	__u16 htotal;
+	__u16 hline;
+};
+
 
 /*******************************************************************************
  * display
@@ -303,6 +325,7 @@ struct kepler_channel_gpfifo_a_v0 {
 
 struct nv50_disp_mthd_v0 {
 	__u8  version;
+#define NV50_DISP_SCANOUTPOS                                               0x00
 	__u8  method;
 	__u8  head;
 	__u8  pad03[5];
diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h
index a5d82814a9b0..fac3a3bbec44 100644
--- a/drivers/gpu/drm/nouveau/nvif/object.h
+++ b/drivers/gpu/drm/nouveau/nvif/object.h
@@ -71,6 +71,5 @@ void nvif_object_unmap(struct nvif_object *);
 /*XXX*/
 #include <core/object.h>
 #define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv)
-#define nvif_exec(a,b,c,d) nv_exec(nvkm_object(a), (b), (c), (d))
 
 #endif