1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object)
25#include "priv.h"
26
27#include <core/client.h>
28
29#include <nvif/class.h>
30#include <nvif/unpack.h>
31
32struct nv04_disp_root {
33 struct nvkm_object object;
34 struct nvkm_disp *disp;
35};
36
37static int
38nv04_disp_scanoutpos(struct nv04_disp_root *root,
39 void *data, u32 size, int head)
40{
41 struct nvkm_device *device = root->disp->engine.subdev.device;
42 struct nvkm_object *object = &root->object;
43 const u32 hoff = head * 0x2000;
44 union {
45 struct nv04_disp_scanoutpos_v0 v0;
46 } *args = data;
47 u32 line;
48 int ret;
49
50 nvif_ioctl(object, "disp scanoutpos size %d\n", size);
51 if (nvif_unpack(args->v0, 0, 0, false)) {
52 nvif_ioctl(object, "disp scanoutpos vers %d\n",
53 args->v0.version);
54 args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff;
55 args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff;
56 args->v0.vblanke = args->v0.vtotal - 1;
57
58 args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff;
59 args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff;
60 args->v0.hblanke = args->v0.htotal - 1;
61
62
63
64
65
66
67 if (!args->v0.vtotal || !args->v0.htotal)
68 return -ENOTSUPP;
69
70 args->v0.time[0] = ktime_to_ns(ktime_get());
71 line = nvkm_rd32(device, 0x600868 + hoff);
72 args->v0.time[1] = ktime_to_ns(ktime_get());
73 args->v0.hline = (line & 0xffff0000) >> 16;
74 args->v0.vline = (line & 0x0000ffff);
75 } else
76 return ret;
77
78 return 0;
79}
80
81static int
82nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
83{
84 struct nv04_disp_root *root = nv04_disp_root(object);
85 union {
86 struct nv04_disp_mthd_v0 v0;
87 } *args = data;
88 int head, ret;
89
90 nvif_ioctl(object, "disp mthd size %d\n", size);
91 if (nvif_unpack(args->v0, 0, 0, true)) {
92 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
93 args->v0.version, args->v0.method, args->v0.head);
94 mthd = args->v0.method;
95 head = args->v0.head;
96 } else
97 return ret;
98
99 if (head < 0 || head >= 2)
100 return -ENXIO;
101
102 switch (mthd) {
103 case NV04_DISP_SCANOUTPOS:
104 return nv04_disp_scanoutpos(root, data, size, head);
105 default:
106 break;
107 }
108
109 return -EINVAL;
110}
111
112static struct nvkm_object_func
113nv04_disp_root = {
114 .mthd = nv04_disp_mthd,
115 .ntfy = nvkm_disp_ntfy,
116};
117
118static int
119nv04_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
120 void *data, u32 size, struct nvkm_object **pobject)
121{
122 struct nv04_disp_root *root;
123
124 if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
125 return -ENOMEM;
126 root->disp = disp;
127 *pobject = &root->object;
128
129 nvkm_object_ctor(&nv04_disp_root, oclass, &root->object);
130 return 0;
131}
132
133const struct nvkm_disp_oclass
134nv04_disp_root_oclass = {
135 .base.oclass = NV04_DISP,
136 .base.minver = -1,
137 .base.maxver = -1,
138 .ctor = nv04_disp_root_new,
139};
140