aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2017-05-19 09:59:35 -0400
committerBen Skeggs <bskeggs@redhat.com>2017-06-16 00:04:59 -0400
commitd52e948c67b263d0ceb71d734673ff8b1d4b10ce (patch)
treeeee2752a21067b79a87692a42fa253dd8aefe18b
parent327c5581d303183e9e56b50238034f419dcca3ce (diff)
drm/nouveau/disp/nv50-: implement a common supervisor 2.0
This makes use of all the additional routing and state added in previous commits, making it possible to deal with GM20x macro link routing, while also sharing code between the NV50 and GF119 implementations. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c18
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c110
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h1
5 files changed, 41 insertions, 155 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index da5aa4683d16..12e52529413c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -411,6 +411,23 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
411 return ret; 411 return ret;
412} 412}
413 413
414static void
415nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior)
416{
417 struct nvkm_dp *dp = nvkm_dp(outp);
418
419 /* Prevent link from being retrained if sink sends an IRQ. */
420 atomic_set(&dp->lt.done, 0);
421 ior->dp.nr = 0;
422
423 /* Execute DisableLT script from DP Info Table. */
424 nvbios_init(&ior->disp->engine.subdev, dp->info.script[4],
425 init.outp = &dp->outp.info;
426 init.or = ior->id;
427 init.link = ior->arm.link;
428 );
429}
430
414int 431int
415nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused) 432nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused)
416{ 433{
@@ -557,6 +574,7 @@ nvkm_dp_func = {
557 .dtor = nvkm_dp_dtor, 574 .dtor = nvkm_dp_dtor,
558 .init = nvkm_dp_init, 575 .init = nvkm_dp_init,
559 .fini = nvkm_dp_fini, 576 .fini = nvkm_dp_fini,
577 .release = nvkm_dp_release,
560}; 578};
561 579
562static int 580static int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index e8bfb6ee89ae..986069f82d24 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -79,44 +79,6 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
79} 79}
80 80
81static struct nvkm_output * 81static struct nvkm_output *
82exec_script(struct nv50_disp *disp, int head, int id)
83{
84 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
85 struct nvkm_device *device = subdev->device;
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 = {
105 .subdev = subdev,
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) 82exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
121{ 83{
122 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 84 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
@@ -177,31 +139,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
177} 139}
178 140
179static void 141static void
180gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head)
181{
182 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
183 struct nvkm_output *outp = exec_script(disp, head, 2);
184
185 /* see note in nv50_disp_intr_unk20_0() */
186 if (outp && outp->info.type == DCB_OUTPUT_DP) {
187 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
188 if (!outpdp->lt.mst) {
189 struct nvbios_init init = {
190 .subdev = subdev,
191 .bios = subdev->device->bios,
192 .outp = &outp->info,
193 .crtc = head,
194 .offset = outpdp->info.script[4],
195 .execute = 1,
196 };
197
198 atomic_set(&outpdp->lt.done, 0);
199 nvbios_exec(&init);
200 }
201 }
202}
203
204static void
205gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) 142gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head)
206{ 143{
207 struct nvkm_device *device = disp->base.engine.subdev.device; 144 struct nvkm_device *device = disp->base.engine.subdev.device;
@@ -364,8 +301,7 @@ gf119_disp_super(struct work_struct *work)
364 list_for_each_entry(head, &disp->base.head, head) { 301 list_for_each_entry(head, &disp->base.head, head) {
365 if (!(mask[head->id] & 0x00001000)) 302 if (!(mask[head->id] & 0x00001000))
366 continue; 303 continue;
367 nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id); 304 nv50_disp_super_2_0(disp, head);
368 gf119_disp_intr_unk2_0(disp, head->id);
369 } 305 }
370 nvkm_outp_route(&disp->base); 306 nvkm_outp_route(&disp->base);
371 list_for_each_entry(head, &disp->base.head, head) { 307 list_for_each_entry(head, &disp->base.head, head) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 96d281568765..6c51045e284a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -226,65 +226,6 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
226} 226}
227 227
228static struct nvkm_output * 228static struct nvkm_output *
229exec_script(struct nv50_disp *disp, int head, int id)
230{
231 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
232 struct nvkm_device *device = subdev->device;
233 struct nvkm_bios *bios = device->bios;
234 struct nvkm_output *outp;
235 struct nvbios_outp info;
236 u8 ver, hdr, cnt, len;
237 u32 data, ctrl = 0;
238 u32 reg;
239 int i;
240
241 /* DAC */
242 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++)
243 ctrl = nvkm_rd32(device, 0x610b5c + (i * 8));
244
245 /* SOR */
246 if (!(ctrl & (1 << head))) {
247 if (device->chipset < 0x90 ||
248 device->chipset == 0x92 ||
249 device->chipset == 0xa0) {
250 reg = 0x610b74;
251 } else {
252 reg = 0x610798;
253 }
254 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++)
255 ctrl = nvkm_rd32(device, reg + (i * 8));
256 i += 4;
257 }
258
259 /* PIOR */
260 if (!(ctrl & (1 << head))) {
261 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++)
262 ctrl = nvkm_rd32(device, 0x610b84 + (i * 8));
263 i += 8;
264 }
265
266 if (!(ctrl & (1 << head)))
267 return NULL;
268 i--;
269
270 outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
271 if (outp) {
272 struct nvbios_init init = {
273 .subdev = subdev,
274 .bios = bios,
275 .offset = info.script[id],
276 .outp = &outp->info,
277 .crtc = head,
278 .execute = 1,
279 };
280
281 nvbios_exec(&init);
282 }
283
284 return outp;
285}
286
287static struct nvkm_output *
288exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) 229exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
289{ 230{
290 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 231 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
@@ -601,38 +542,27 @@ nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head)
601 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); 542 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk);
602} 543}
603 544
604static void 545void
605nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) 546nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head)
606{ 547{
607 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 548 struct nvkm_outp *outp;
608 struct nvkm_output *outp = exec_script(disp, head, 2); 549 struct nvkm_ior *ior;
609 550
610 /* the binary driver does this outside of the supervisor handling 551 /* Determine which OR, if any, we're detaching from the head. */
611 * (after the third supervisor from a detach). we (currently?) 552 HEAD_DBG(head, "supervisor 2.0");
612 * allow both detach/attach to happen in the same set of 553 ior = nv50_disp_super_ior_arm(head);
613 * supervisor interrupts, so it would make sense to execute this 554 if (!ior)
614 * (full power down?) script after all the detach phases of the 555 return;
615 * supervisor handling. like with training if needed from the 556
616 * second supervisor, nvidia doesn't do this, so who knows if it's 557 /* Execute OffInt2 IED script. */
617 * entirely safe, but it does appear to work.. 558 nv50_disp_super_ied_off(head, ior, 2);
618 * 559
619 * without this script being run, on some configurations i've 560 /* If we're shutting down the OR's only active head, execute
620 * seen, switching from DP to TMDS on a DP connector may result 561 * the output path's release function.
621 * in a blank screen (SOR_PWR off/on can restore it)
622 */ 562 */
623 if (outp && outp->info.type == DCB_OUTPUT_DP) { 563 if (ior->arm.head == (1 << head->id)) {
624 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); 564 if ((outp = ior->arm.outp) && outp->func->release)
625 struct nvbios_init init = { 565 outp->func->release(outp, ior);
626 .subdev = subdev,
627 .bios = subdev->device->bios,
628 .outp = &outp->info,
629 .crtc = head,
630 .offset = outpdp->info.script[4],
631 .execute = 1,
632 };
633
634 atomic_set(&outpdp->lt.done, 0);
635 nvbios_exec(&init);
636 } 566 }
637} 567}
638 568
@@ -695,7 +625,7 @@ nv50_disp_super(struct work_struct *work)
695 list_for_each_entry(head, &disp->base.head, head) { 625 list_for_each_entry(head, &disp->base.head, head) {
696 if (!(super & (0x00000080 << head->id))) 626 if (!(super & (0x00000080 << head->id)))
697 continue; 627 continue;
698 nv50_disp_intr_unk20_0(disp, head->id); 628 nv50_disp_super_2_0(disp, head);
699 } 629 }
700 nvkm_outp_route(&disp->base); 630 nvkm_outp_route(&disp->base);
701 list_for_each_entry(head, &disp->base.head, head) { 631 list_for_each_entry(head, &disp->base.head, head) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
index 921ed0fa87f3..f6bafe6dcaa4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -28,6 +28,7 @@ struct nv50_disp {
28 28
29void nv50_disp_super_1(struct nv50_disp *); 29void nv50_disp_super_1(struct nv50_disp *);
30void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); 30void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *);
31void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *);
31 32
32int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, 33int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
33 int index, int heads, struct nvkm_disp **); 34 int index, int heads, struct nvkm_disp **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index 106141eb3e32..da4347e27e65 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -39,6 +39,7 @@ struct nvkm_outp_func {
39 void *(*dtor)(struct nvkm_outp *); 39 void *(*dtor)(struct nvkm_outp *);
40 void (*init)(struct nvkm_outp *); 40 void (*init)(struct nvkm_outp *);
41 void (*fini)(struct nvkm_outp *); 41 void (*fini)(struct nvkm_outp *);
42 void (*release)(struct nvkm_outp *, struct nvkm_ior *);
42}; 43};
43 44
44#define nvkm_output nvkm_outp 45#define nvkm_output nvkm_outp