]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
drm/nouveau/disp: convert user classes to new-style nvkm_object
[mirror_ubuntu-zesty-kernel.git] / drivers / gpu / drm / nouveau / nvkm / engine / disp / rootnv50.c
CommitLineData
2a7909c0
BS
1/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24#include "rootnv50.h"
25#include "dmacnv50.h"
26
27#include <core/client.h>
28#include <core/ramht.h>
29#include <subdev/timer.h>
30
31#include <nvif/class.h>
32#include <nvif/unpack.h>
33
34int
35nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0)
36{
37 struct nvkm_device *device = disp->base.engine.subdev.device;
38 const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540));
39 const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540));
40 const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540));
41 union {
42 struct nv04_disp_scanoutpos_v0 v0;
43 } *args = data;
44 int ret;
45
46 nvif_ioctl(object, "disp scanoutpos size %d\n", size);
47 if (nvif_unpack(args->v0, 0, 0, false)) {
48 nvif_ioctl(object, "disp scanoutpos vers %d\n",
49 args->v0.version);
50 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
51 args->v0.hblanke = (blanke & 0x0000ffff);
52 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
53 args->v0.hblanks = (blanks & 0x0000ffff);
54 args->v0.vtotal = ( total & 0xffff0000) >> 16;
55 args->v0.htotal = ( total & 0x0000ffff);
56 args->v0.time[0] = ktime_to_ns(ktime_get());
57 args->v0.vline = /* vline read locks hline */
58 nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff;
59 args->v0.time[1] = ktime_to_ns(ktime_get());
60 args->v0.hline =
61 nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff;
62 } else
63 return ret;
64
65 return 0;
66}
67
68int
0ce41e3c 69nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
2a7909c0 70{
2a7909c0
BS
71 union {
72 struct nv50_disp_mthd_v0 v0;
73 struct nv50_disp_mthd_v1 v1;
74 } *args = data;
0ce41e3c
BS
75 struct nv50_disp_root *root = nv50_disp_root(object);
76 struct nv50_disp *disp = root->disp;
77 const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
2a7909c0
BS
78 struct nvkm_output *outp = NULL;
79 struct nvkm_output *temp;
80 u16 type, mask = 0;
81 int head, ret;
82
83 if (mthd != NV50_DISP_MTHD)
84 return -EINVAL;
85
86 nvif_ioctl(object, "disp mthd size %d\n", size);
87 if (nvif_unpack(args->v0, 0, 0, true)) {
88 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
89 args->v0.version, args->v0.method, args->v0.head);
90 mthd = args->v0.method;
91 head = args->v0.head;
92 } else
93 if (nvif_unpack(args->v1, 1, 1, true)) {
94 nvif_ioctl(object, "disp mthd vers %d mthd %02x "
95 "type %04x mask %04x\n",
96 args->v1.version, args->v1.method,
97 args->v1.hasht, args->v1.hashm);
98 mthd = args->v1.method;
99 type = args->v1.hasht;
100 mask = args->v1.hashm;
101 head = ffs((mask >> 8) & 0x0f) - 1;
102 } else
103 return ret;
104
105 if (head < 0 || head >= disp->head.nr)
106 return -ENXIO;
107
108 if (mask) {
109 list_for_each_entry(temp, &disp->base.outp, head) {
110 if ((temp->info.hasht == type) &&
111 (temp->info.hashm & mask) == mask) {
112 outp = temp;
113 break;
114 }
115 }
116 if (outp == NULL)
117 return -ENXIO;
118 }
119
120 switch (mthd) {
121 case NV50_DISP_SCANOUTPOS:
122 return impl->head.scanoutpos(object, disp, data, size, head);
123 default:
124 break;
125 }
126
127 switch (mthd * !!outp) {
128 case NV50_DISP_MTHD_V1_DAC_PWR:
129 return disp->dac.power(object, disp, data, size, head, outp);
130 case NV50_DISP_MTHD_V1_DAC_LOAD:
131 return disp->dac.sense(object, disp, data, size, head, outp);
132 case NV50_DISP_MTHD_V1_SOR_PWR:
133 return disp->sor.power(object, disp, data, size, head, outp);
134 case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
135 if (!disp->sor.hda_eld)
136 return -ENODEV;
137 return disp->sor.hda_eld(object, disp, data, size, head, outp);
138 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
139 if (!disp->sor.hdmi)
140 return -ENODEV;
141 return disp->sor.hdmi(object, disp, data, size, head, outp);
142 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
143 union {
144 struct nv50_disp_sor_lvds_script_v0 v0;
145 } *args = data;
146 nvif_ioctl(object, "disp sor lvds script size %d\n", size);
147 if (nvif_unpack(args->v0, 0, 0, false)) {
148 nvif_ioctl(object, "disp sor lvds script "
149 "vers %d name %04x\n",
150 args->v0.version, args->v0.script);
151 disp->sor.lvdsconf = args->v0.script;
152 return 0;
153 } else
154 return ret;
155 }
156 break;
157 case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
158 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
159 union {
160 struct nv50_disp_sor_dp_pwr_v0 v0;
161 } *args = data;
162 nvif_ioctl(object, "disp sor dp pwr size %d\n", size);
163 if (nvif_unpack(args->v0, 0, 0, false)) {
164 nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n",
165 args->v0.version, args->v0.state);
166 if (args->v0.state == 0) {
167 nvkm_notify_put(&outpdp->irq);
168 outpdp->func->lnk_pwr(outpdp, 0);
169 atomic_set(&outpdp->lt.done, 0);
170 return 0;
171 } else
172 if (args->v0.state != 0) {
173 nvkm_output_dp_train(&outpdp->base, 0, true);
174 return 0;
175 }
176 } else
177 return ret;
178 }
179 break;
180 case NV50_DISP_MTHD_V1_PIOR_PWR:
181 if (!disp->pior.power)
182 return -ENODEV;
183 return disp->pior.power(object, disp, data, size, head, outp);
184 default:
185 break;
186 }
187
188 return -EINVAL;
189}
190
0ce41e3c
BS
191static int
192nv50_disp_root_dmac_new_(const struct nvkm_oclass *oclass,
193 void *data, u32 size, struct nvkm_object **pobject)
194{
195 const struct nv50_disp_dmac_oclass *sclass = oclass->priv;
196 struct nv50_disp_root *root = nv50_disp_root(oclass->parent);
197 return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid,
198 oclass, data, size, pobject);
199}
200
201static int
202nv50_disp_root_pioc_new_(const struct nvkm_oclass *oclass,
203 void *data, u32 size, struct nvkm_object **pobject)
204{
205 const struct nv50_disp_pioc_oclass *sclass = oclass->priv;
206 struct nv50_disp_root *root = nv50_disp_root(oclass->parent);
207 return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid,
208 oclass, data, size, pobject);
209}
210
211static int
212nv50_disp_root_child_get_(struct nvkm_object *object, int index,
213 struct nvkm_oclass *sclass)
214{
215 struct nv50_disp_root *root = nv50_disp_root(object);
216
217 if (index < ARRAY_SIZE(root->func->dmac)) {
218 sclass->base = root->func->dmac[index]->base;
219 sclass->priv = root->func->dmac[index];
220 sclass->ctor = nv50_disp_root_dmac_new_;
221 return 0;
222 }
223
224 index -= ARRAY_SIZE(root->func->dmac);
225
226 if (index < ARRAY_SIZE(root->func->pioc)) {
227 sclass->base = root->func->pioc[index]->base;
228 sclass->priv = root->func->pioc[index];
229 sclass->ctor = nv50_disp_root_pioc_new_;
230 return 0;
231 }
232
233 return -EINVAL;
234}
235
236static int
237nv50_disp_root_fini_(struct nvkm_object *object, bool suspend)
238{
239 struct nv50_disp_root *root = nv50_disp_root(object);
240 root->func->fini(root);
241 return 0;
242}
243
244static int
245nv50_disp_root_init_(struct nvkm_object *object)
246{
247 struct nv50_disp_root *root = nv50_disp_root(object);
248 return root->func->init(root);
249}
250
251static void *
252nv50_disp_root_dtor_(struct nvkm_object *object)
253{
254 struct nv50_disp_root *root = nv50_disp_root(object);
255 nvkm_ramht_del(&root->ramht);
256 nvkm_gpuobj_del(&root->instmem);
257 return root;
258}
259
260static const struct nvkm_object_func
261nv50_disp_root_ = {
262 .dtor = nv50_disp_root_dtor_,
263 .init = nv50_disp_root_init_,
264 .fini = nv50_disp_root_fini_,
265 .mthd = nv50_disp_root_mthd_,
266 .ntfy = nvkm_disp_ntfy,
267 .sclass = nv50_disp_root_child_get_,
268};
269
2a7909c0 270int
0ce41e3c
BS
271nv50_disp_root_new_(const struct nv50_disp_root_func *func,
272 struct nvkm_disp *base, const struct nvkm_oclass *oclass,
273 void *data, u32 size, struct nvkm_object **pobject)
2a7909c0 274{
0ce41e3c 275 struct nv50_disp *disp = nv50_disp(base);
2a7909c0
BS
276 struct nv50_disp_root *root;
277 struct nvkm_device *device = disp->base.engine.subdev.device;
2a7909c0
BS
278 int ret;
279
0ce41e3c
BS
280 if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
281 return -ENOMEM;
282 *pobject = &root->object;
283
284 nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object);
285 root->func = func;
286 root->disp = disp;
287
288 ret = nvkm_gpuobj_new(disp->base.engine.subdev.device, 0x10000, 0x10000,
289 false, NULL, &root->instmem);
2a7909c0
BS
290 if (ret)
291 return ret;
292
0ce41e3c 293 return nvkm_ramht_new(device, 0x1000, 0, root->instmem, &root->ramht);
2a7909c0
BS
294}
295
296void
0ce41e3c 297nv50_disp_root_fini(struct nv50_disp_root *root)
2a7909c0 298{
0ce41e3c
BS
299 struct nvkm_device *device = root->disp->base.engine.subdev.device;
300 /* disable all interrupts */
301 nvkm_wr32(device, 0x610024, 0x00000000);
302 nvkm_wr32(device, 0x610020, 0x00000000);
2a7909c0
BS
303}
304
0ce41e3c
BS
305int
306nv50_disp_root_init(struct nv50_disp_root *root)
2a7909c0 307{
0ce41e3c 308 struct nv50_disp *disp = root->disp;
2a7909c0 309 struct nvkm_device *device = disp->base.engine.subdev.device;
2a7909c0 310 u32 tmp;
0ce41e3c 311 int i;
2a7909c0
BS
312
313 /* The below segments of code copying values from one register to
314 * another appear to inform EVO of the display capabilities or
315 * something similar. NFI what the 0x614004 caps are for..
316 */
317 tmp = nvkm_rd32(device, 0x614004);
318 nvkm_wr32(device, 0x610184, tmp);
319
320 /* ... CRTC caps */
321 for (i = 0; i < disp->head.nr; i++) {
322 tmp = nvkm_rd32(device, 0x616100 + (i * 0x800));
323 nvkm_wr32(device, 0x610190 + (i * 0x10), tmp);
324 tmp = nvkm_rd32(device, 0x616104 + (i * 0x800));
325 nvkm_wr32(device, 0x610194 + (i * 0x10), tmp);
326 tmp = nvkm_rd32(device, 0x616108 + (i * 0x800));
327 nvkm_wr32(device, 0x610198 + (i * 0x10), tmp);
328 tmp = nvkm_rd32(device, 0x61610c + (i * 0x800));
329 nvkm_wr32(device, 0x61019c + (i * 0x10), tmp);
330 }
331
332 /* ... DAC caps */
333 for (i = 0; i < disp->dac.nr; i++) {
334 tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
335 nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp);
336 }
337
338 /* ... SOR caps */
339 for (i = 0; i < disp->sor.nr; i++) {
340 tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
341 nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp);
342 }
343
344 /* ... PIOR caps */
345 for (i = 0; i < disp->pior.nr; i++) {
346 tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800));
347 nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp);
348 }
349
350 /* steal display away from vbios, or something like that */
351 if (nvkm_rd32(device, 0x610024) & 0x00000100) {
352 nvkm_wr32(device, 0x610024, 0x00000100);
353 nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
354 if (nvkm_msec(device, 2000,
355 if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
356 break;
357 ) < 0)
358 return -EBUSY;
359 }
360
361 /* point at display engine memory area (hash table, objects) */
0ce41e3c 362 nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9);
2a7909c0
BS
363
364 /* enable supervisor interrupts, disable everything else */
365 nvkm_wr32(device, 0x61002c, 0x00000370);
366 nvkm_wr32(device, 0x610028, 0x00000000);
367 return 0;
368}
369
0ce41e3c
BS
370static const struct nv50_disp_root_func
371nv50_disp_root = {
2a7909c0
BS
372 .init = nv50_disp_root_init,
373 .fini = nv50_disp_root_fini,
0ce41e3c
BS
374 .dmac = {
375 &nv50_disp_core_oclass,
376 &nv50_disp_base_oclass,
377 &nv50_disp_ovly_oclass,
378 },
379 .pioc = {
380 &nv50_disp_oimm_oclass,
381 &nv50_disp_curs_oclass,
382 },
2a7909c0
BS
383};
384
0ce41e3c
BS
385static int
386nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
387 void *data, u32 size, struct nvkm_object **pobject)
388{
389 return nv50_disp_root_new_(&nv50_disp_root, disp, oclass,
390 data, size, pobject);
391}
2a7909c0 392
0ce41e3c
BS
393const struct nvkm_disp_oclass
394nv50_disp_root_oclass = {
395 .base.oclass = NV50_DISP,
396 .base.minver = -1,
397 .base.maxver = -1,
398 .ctor = nv50_disp_root_new,
2a7909c0 399};