summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
index 67020933f4ff..5c557f3e6c2c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
@@ -23,6 +23,11 @@
*/
#include "head.h"
+#include <core/client.h>
+
+#include <nvif/cl0046.h>
+#include <nvif/unpack.h>
+
struct nvkm_head *
nvkm_head_find(struct nvkm_disp *disp, int id)
{
@@ -34,6 +39,44 @@ nvkm_head_find(struct nvkm_disp *disp, int id)
return NULL;
}
+int
+nvkm_head_mthd_scanoutpos(struct nvkm_object *object,
+ struct nvkm_head *head, void *data, u32 size)
+{
+ union {
+ struct nv04_disp_scanoutpos_v0 v0;
+ } *args = data;
+ int ret = -ENOSYS;
+
+ nvif_ioctl(object, "head scanoutpos size %d\n", size);
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
+ nvif_ioctl(object, "head scanoutpos vers %d\n",
+ args->v0.version);
+
+ head->func->state(head, &head->arm);
+ args->v0.vtotal = head->arm.vtotal;
+ args->v0.vblanks = head->arm.vblanks;
+ args->v0.vblanke = head->arm.vblanke;
+ args->v0.htotal = head->arm.htotal;
+ args->v0.hblanks = head->arm.hblanks;
+ args->v0.hblanke = head->arm.hblanke;
+
+ /* We don't support reading htotal/vtotal on pre-NV50 VGA,
+ * 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());
+ head->func->rgpos(head, &args->v0.hline, &args->v0.vline);
+ args->v0.time[1] = ktime_to_ns(ktime_get());
+ } else
+ return ret;
+
+ return 0;
+}
+
void
nvkm_head_del(struct nvkm_head **phead)
{