]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
drm/nouveau/disp/nv50-: port OR power state control to nvkm_ior
[mirror_ubuntu-artful-kernel.git] / drivers / gpu / drm / nouveau / nvkm / engine / disp / gf119.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 "nv50.h"
a1c93078 25#include "head.h"
78f1ad6f 26#include "ior.h"
2a7909c0
BS
27#include "rootnv50.h"
28
29#include <subdev/bios.h>
30#include <subdev/bios/disp.h>
31#include <subdev/bios/init.h>
32#include <subdev/bios/pll.h>
33#include <subdev/devinit.h>
34
2a7909c0
BS
35static struct nvkm_output *
36exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
37 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
38 struct nvbios_outp *info)
39{
40 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
41 struct nvkm_bios *bios = subdev->device->bios;
42 struct nvkm_output *outp;
43 u16 mask, type;
44
45 if (or < 4) {
46 type = DCB_OUTPUT_ANALOG;
47 mask = 0;
48 } else {
49 or -= 4;
50 switch (ctrl & 0x00000f00) {
51 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
52 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
53 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
54 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
55 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
56 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
57 default:
58 nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl);
59 return NULL;
60 }
61 }
62
63 mask = 0x00c0 & (mask << 6);
64 mask |= 0x0001 << or;
65 mask |= 0x0100 << head;
66
67 list_for_each_entry(outp, &disp->base.outp, head) {
68 if ((outp->info.hasht & 0xff) == type &&
69 (outp->info.hashm & mask) == mask) {
9a2b8131 70 *data = nvbios_outp_match(bios, outp->info.hasht, mask,
2a7909c0
BS
71 ver, hdr, cnt, len, info);
72 if (!*data)
73 return NULL;
74 return outp;
75 }
76 }
77
78 return NULL;
79}
80
81static struct nvkm_output *
82exec_script(struct nv50_disp *disp, int head, int id)
83{
70aa8670
BS
84 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
85 struct nvkm_device *device = subdev->device;
2a7909c0
BS
86 struct nvkm_bios *bios = device->bios;
87 struct nvkm_output *outp;
88 struct nvbios_outp info;
89 u8 ver, hdr, cnt, len;
90 u32 data, ctrl = 0;
91 int or;
92
93 for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
94 ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20));
95 if (ctrl & (1 << head))
96 break;
97 }
98
99 if (or == 8)
100 return NULL;
101
102 outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
103 if (outp) {
104 struct nvbios_init init = {
70aa8670 105 .subdev = subdev,
2a7909c0
BS
106 .bios = bios,
107 .offset = info.script[id],
108 .outp = &outp->info,
109 .crtc = head,
110 .execute = 1,
111 };
112
113 nvbios_exec(&init);
114 }
115
116 return outp;
117}
118
119static struct nvkm_output *
120exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
121{
70aa8670
BS
122 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
123 struct nvkm_device *device = subdev->device;
2a7909c0
BS
124 struct nvkm_bios *bios = device->bios;
125 struct nvkm_output *outp;
126 struct nvbios_outp info1;
127 struct nvbios_ocfg info2;
128 u8 ver, hdr, cnt, len;
129 u32 data, ctrl = 0;
130 int or;
131
132 for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
133 ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20));
134 if (ctrl & (1 << head))
135 break;
136 }
137
138 if (or == 8)
139 return NULL;
140
141 outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
142 if (!outp)
143 return NULL;
144
bc9139d2 145 *conf = (ctrl & 0x00000f00) >> 8;
2a7909c0
BS
146 switch (outp->info.type) {
147 case DCB_OUTPUT_TMDS:
16ef53a9 148 if (*conf == 5)
2a7909c0
BS
149 *conf |= 0x0100;
150 break;
151 case DCB_OUTPUT_LVDS:
bc9139d2 152 *conf |= disp->sor.lvdsconf;
2a7909c0 153 break;
2a7909c0 154 default:
2a7909c0
BS
155 break;
156 }
157
bc9139d2
BS
158 data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8,
159 &ver, &hdr, &cnt, &len, &info2);
2a7909c0
BS
160 if (data && id < 0xff) {
161 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
162 if (data) {
163 struct nvbios_init init = {
70aa8670 164 .subdev = subdev,
2a7909c0
BS
165 .bios = bios,
166 .offset = data,
167 .outp = &outp->info,
168 .crtc = head,
169 .execute = 1,
170 };
171
172 nvbios_exec(&init);
173 }
174 }
175
176 return outp;
177}
178
179static void
180gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head)
181{
182 exec_script(disp, head, 1);
183}
184
185static void
186gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head)
187{
46484438 188 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
2a7909c0
BS
189 struct nvkm_output *outp = exec_script(disp, head, 2);
190
191 /* see note in nv50_disp_intr_unk20_0() */
192 if (outp && outp->info.type == DCB_OUTPUT_DP) {
193 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
f2a40513
BS
194 if (!outpdp->lt.mst) {
195 struct nvbios_init init = {
196 .subdev = subdev,
197 .bios = subdev->device->bios,
198 .outp = &outp->info,
199 .crtc = head,
200 .offset = outpdp->info.script[4],
201 .execute = 1,
202 };
2a7909c0 203
f2a40513 204 atomic_set(&outpdp->lt.done, 0);
22e008f9 205 nvbios_exec(&init);
f2a40513 206 }
2a7909c0
BS
207 }
208}
209
210static void
211gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head)
212{
213 struct nvkm_device *device = disp->base.engine.subdev.device;
214 struct nvkm_devinit *devinit = device->devinit;
215 u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
216 if (pclk)
151abd44 217 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk);
2a7909c0
BS
218 nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000);
219}
220
221static void
222gf119_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head,
223 struct dcb_output *outp)
224{
225 struct nvkm_device *device = disp->base.engine.subdev.device;
226 const int or = ffs(outp->or) - 1;
227 const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020));
228 const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300));
229 const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff;
230 const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff;
231 const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff;
232 const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
233 const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
234 const u32 hoff = (head * 0x800);
235 const u32 soff = ( or * 0x800);
236 const u32 loff = (link * 0x080) + soff;
237 const u32 symbol = 100000;
238 const u32 TU = 64;
239 u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff);
240 u32 clksor = nvkm_rd32(device, 0x612300 + soff);
241 u32 datarate, link_nr, link_bw, bits;
242 u64 ratio, value;
243
244 link_nr = hweight32(dpctrl & 0x000f0000);
245 link_bw = (clksor & 0x007c0000) >> 18;
246 link_bw *= 27000;
247
248 /* symbols/hblank - algorithm taken from comments in tegra driver */
249 value = vblanke + vactive - vblanks - 7;
250 value = value * link_bw;
251 do_div(value, pclk);
252 value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
253 nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value);
254
255 /* symbols/vblank - algorithm taken from comments in tegra driver */
256 value = vblanks - vblanke - 25;
257 value = value * link_bw;
258 do_div(value, pclk);
259 value = value - ((36 / link_nr) + 3) - 1;
260 nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value);
261
262 /* watermark */
263 if ((conf & 0x3c0) == 0x180) bits = 30;
264 else if ((conf & 0x3c0) == 0x140) bits = 24;
265 else bits = 18;
266 datarate = (pclk * bits) / 8;
267
268 ratio = datarate;
269 ratio *= symbol;
270 do_div(ratio, link_nr * link_bw);
271
272 value = (symbol - ratio) * TU;
273 value *= ratio;
274 do_div(value, symbol);
275 do_div(value, symbol);
276
277 value += 5;
278 value |= 0x08000000;
279
280 nvkm_wr32(device, 0x616610 + hoff, value);
281}
282
283static void
284gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head)
285{
286 struct nvkm_device *device = disp->base.engine.subdev.device;
287 struct nvkm_output *outp;
288 u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
289 u32 conf, addr, data;
290
291 outp = exec_clkcmp(disp, head, 0xff, pclk, &conf);
292 if (!outp)
293 return;
294
295 /* see note in nv50_disp_intr_unk20_2() */
296 if (outp->info.type == DCB_OUTPUT_DP) {
297 u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300));
298 switch ((sync & 0x000003c0) >> 6) {
299 case 6: pclk = pclk * 30; break;
300 case 5: pclk = pclk * 24; break;
301 case 2:
302 default:
303 pclk = pclk * 18;
304 break;
305 }
306
1f8711ba 307 if (nvkm_output_dp_train(outp, pclk))
2a7909c0
BS
308 OUTP_ERR(outp, "link not trained before attach");
309 } else {
70aa8670
BS
310 if (disp->func->sor.magic)
311 disp->func->sor.magic(outp);
2a7909c0
BS
312 }
313
314 exec_clkcmp(disp, head, 0, pclk, &conf);
315
316 if (outp->info.type == DCB_OUTPUT_ANALOG) {
317 addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
318 data = 0x00000000;
319 } else {
320 addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
321 data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
322 switch (outp->info.type) {
323 case DCB_OUTPUT_TMDS:
324 nvkm_mask(device, addr, 0x007c0000, 0x00280000);
325 break;
326 case DCB_OUTPUT_DP:
327 gf119_disp_intr_unk2_2_tu(disp, head, &outp->info);
328 break;
329 default:
330 break;
331 }
332 }
333
334 nvkm_mask(device, addr, 0x00000707, data);
335}
336
337static void
338gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head)
339{
340 struct nvkm_device *device = disp->base.engine.subdev.device;
341 u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
342 u32 conf;
343
344 exec_clkcmp(disp, head, 1, pclk, &conf);
345}
346
347void
af85389c 348gf119_disp_super(struct work_struct *work)
2a7909c0
BS
349{
350 struct nv50_disp *disp =
351 container_of(work, struct nv50_disp, supervisor);
2a7909c0
BS
352 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
353 struct nvkm_device *device = subdev->device;
a1c93078 354 struct nvkm_head *head;
2a7909c0 355 u32 mask[4];
2a7909c0
BS
356
357 nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super));
a1c93078
BS
358 list_for_each_entry(head, &disp->base.head, head) {
359 mask[head->id] = nvkm_rd32(device, 0x6101d4 + (head->id * 0x800));
360 HEAD_DBG(head, "%08x", mask[head->id]);
2a7909c0
BS
361 }
362
363 if (disp->super & 0x00000001) {
0ce41e3c 364 nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG);
29c0ca73 365 nv50_disp_super_1(disp);
a1c93078
BS
366 list_for_each_entry(head, &disp->base.head, head) {
367 if (!(mask[head->id] & 0x00001000))
2a7909c0 368 continue;
a1c93078
BS
369 nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head->id);
370 gf119_disp_intr_unk1_0(disp, head->id);
2a7909c0
BS
371 }
372 } else
373 if (disp->super & 0x00000002) {
a1c93078
BS
374 list_for_each_entry(head, &disp->base.head, head) {
375 if (!(mask[head->id] & 0x00001000))
2a7909c0 376 continue;
a1c93078
BS
377 nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id);
378 gf119_disp_intr_unk2_0(disp, head->id);
2a7909c0 379 }
a1c93078
BS
380 list_for_each_entry(head, &disp->base.head, head) {
381 if (!(mask[head->id] & 0x00010000))
2a7909c0 382 continue;
a1c93078
BS
383 nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head->id);
384 gf119_disp_intr_unk2_1(disp, head->id);
2a7909c0 385 }
a1c93078
BS
386 list_for_each_entry(head, &disp->base.head, head) {
387 if (!(mask[head->id] & 0x00001000))
2a7909c0 388 continue;
a1c93078
BS
389 nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head->id);
390 gf119_disp_intr_unk2_2(disp, head->id);
2a7909c0
BS
391 }
392 } else
393 if (disp->super & 0x00000004) {
a1c93078
BS
394 list_for_each_entry(head, &disp->base.head, head) {
395 if (!(mask[head->id] & 0x00001000))
2a7909c0 396 continue;
a1c93078
BS
397 nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head->id);
398 gf119_disp_intr_unk4_0(disp, head->id);
2a7909c0
BS
399 }
400 }
401
a1c93078
BS
402 list_for_each_entry(head, &disp->base.head, head)
403 nvkm_wr32(device, 0x6101d4 + (head->id * 0x800), 0x00000000);
2a7909c0
BS
404 nvkm_wr32(device, 0x6101d0, 0x80000000);
405}
406
fd47877f 407void
2a7909c0
BS
408gf119_disp_intr_error(struct nv50_disp *disp, int chid)
409{
2a7909c0
BS
410 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
411 struct nvkm_device *device = subdev->device;
412 u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12));
413 u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12));
414 u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12));
415
416 nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n",
417 chid, (mthd & 0x0000ffc), data, mthd, unkn);
418
0ce41e3c 419 if (chid < ARRAY_SIZE(disp->chan)) {
2a7909c0
BS
420 switch (mthd & 0xffc) {
421 case 0x0080:
0ce41e3c 422 nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
2a7909c0
BS
423 break;
424 default:
425 break;
426 }
427 }
428
429 nvkm_wr32(device, 0x61009c, (1 << chid));
430 nvkm_wr32(device, 0x6101f0 + (chid * 12), 0x90000000);
431}
432
433void
70aa8670 434gf119_disp_intr(struct nv50_disp *disp)
2a7909c0 435{
70aa8670 436 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
2a7909c0 437 struct nvkm_device *device = subdev->device;
a1c93078 438 struct nvkm_head *head;
2a7909c0 439 u32 intr = nvkm_rd32(device, 0x610088);
2a7909c0
BS
440
441 if (intr & 0x00000001) {
442 u32 stat = nvkm_rd32(device, 0x61008c);
443 while (stat) {
444 int chid = __ffs(stat); stat &= ~(1 << chid);
445 nv50_disp_chan_uevent_send(disp, chid);
446 nvkm_wr32(device, 0x61008c, 1 << chid);
447 }
448 intr &= ~0x00000001;
449 }
450
451 if (intr & 0x00000002) {
452 u32 stat = nvkm_rd32(device, 0x61009c);
453 int chid = ffs(stat) - 1;
454 if (chid >= 0)
fd47877f 455 disp->func->intr_error(disp, chid);
2a7909c0
BS
456 intr &= ~0x00000002;
457 }
458
459 if (intr & 0x00100000) {
460 u32 stat = nvkm_rd32(device, 0x6100ac);
461 if (stat & 0x00000007) {
462 disp->super = (stat & 0x00000007);
3607bfd3 463 queue_work(disp->wq, &disp->supervisor);
2a7909c0
BS
464 nvkm_wr32(device, 0x6100ac, disp->super);
465 stat &= ~0x00000007;
466 }
467
468 if (stat) {
469 nvkm_warn(subdev, "intr24 %08x\n", stat);
470 nvkm_wr32(device, 0x6100ac, stat);
471 }
472
473 intr &= ~0x00100000;
474 }
475
a1c93078
BS
476 list_for_each_entry(head, &disp->base.head, head) {
477 const u32 hoff = head->id * 0x800;
478 u32 mask = 0x01000000 << head->id;
2a7909c0 479 if (mask & intr) {
a1c93078 480 u32 stat = nvkm_rd32(device, 0x6100bc + hoff);
2a7909c0 481 if (stat & 0x00000001)
a1c93078
BS
482 nvkm_disp_vblank(&disp->base, head->id);
483 nvkm_mask(device, 0x6100bc + hoff, 0, 0);
484 nvkm_rd32(device, 0x6100c0 + hoff);
2a7909c0
BS
485 }
486 }
487}
488
70aa8670
BS
489int
490gf119_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device,
491 int index, struct nvkm_disp **pdisp)
492{
493 u32 heads = nvkm_rd32(device, 0x022448);
494 return nv50_disp_new_(func, device, index, heads, pdisp);
495}
496
497static const struct nv50_disp_func
0ce41e3c 498gf119_disp = {
70aa8670 499 .intr = gf119_disp_intr,
fd47877f 500 .intr_error = gf119_disp_intr_error,
70aa8670 501 .uevent = &gf119_disp_chan_uevent,
af85389c 502 .super = gf119_disp_super,
0ce41e3c 503 .root = &gf119_disp_root_oclass,
a1c93078 504 .head.new = gf119_head_new,
70aa8670
BS
505 .outp.internal.crt = nv50_dac_output_new,
506 .outp.internal.tmds = nv50_sor_output_new,
507 .outp.internal.lvds = nv50_sor_output_new,
508 .outp.internal.dp = gf119_sor_dp_new,
509 .dac.nr = 3,
b3c9c022 510 .dac.new = gf119_dac_new,
70aa8670
BS
511 .dac.sense = nv50_dac_sense,
512 .sor.nr = 4,
78f1ad6f 513 .sor.new = gf119_sor_new,
70aa8670
BS
514 .sor.hda_eld = gf119_hda_eld,
515 .sor.hdmi = gf119_hdmi_ctrl,
0ce41e3c
BS
516};
517
70aa8670
BS
518int
519gf119_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
2a7909c0 520{
70aa8670 521 return gf119_disp_new_(&gf119_disp, device, index, pdisp);
2a7909c0 522}