diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 66 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h | 1 |
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) return ret; } +static void +nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior) +{ + struct nvkm_dp *dp = nvkm_dp(outp); + + /* Prevent link from being retrained if sink sends an IRQ. */ + atomic_set(&dp->lt.done, 0); + ior->dp.nr = 0; + + /* Execute DisableLT script from DP Info Table. */ + nvbios_init(&ior->disp->engine.subdev, dp->info.script[4], + init.outp = &dp->outp.info; + init.or = ior->id; + init.link = ior->arm.link; + ); +} + int nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused) { @@ -557,6 +574,7 @@ nvkm_dp_func = { .dtor = nvkm_dp_dtor, .init = nvkm_dp_init, .fini = nvkm_dp_fini, + .release = nvkm_dp_release, }; static 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, } static struct nvkm_output * -exec_script(struct nv50_disp *disp, int head, int id) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); - if (outp) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = info.script[id], - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - - return outp; -} - -static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { 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) } static void -gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_output *outp = exec_script(disp, head, 2); - - /* see note in nv50_disp_intr_unk20_0() */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - if (!outpdp->lt.mst) { - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - atomic_set(&outpdp->lt.done, 0); - nvbios_exec(&init); - } - } -} - -static void gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) { struct nvkm_device *device = disp->base.engine.subdev.device; @@ -364,8 +301,7 @@ gf119_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id); - gf119_disp_intr_unk2_0(disp, head->id); + nv50_disp_super_2_0(disp, head); } nvkm_outp_route(&disp->base); 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, } static struct nvkm_output * -exec_script(struct nv50_disp *disp, int head, int id) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - u32 reg; - int i; - - /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) - ctrl = nvkm_rd32(device, 0x610b5c + (i * 8)); - - /* SOR */ - if (!(ctrl & (1 << head))) { - if (device->chipset < 0x90 || - device->chipset == 0x92 || - device->chipset == 0xa0) { - reg = 0x610b74; - } else { - reg = 0x610798; - } - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) - ctrl = nvkm_rd32(device, reg + (i * 8)); - i += 4; - } - - /* PIOR */ - if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) - ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); - i += 8; - } - - if (!(ctrl & (1 << head))) - return NULL; - i--; - - outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); - if (outp) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = info.script[id], - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - - return outp; -} - -static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { struct nvkm_subdev *subdev = &disp->base.engine.subdev; @@ -601,38 +542,27 @@ nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); } -static void -nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) +void +nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head) { - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_output *outp = exec_script(disp, head, 2); - - /* the binary driver does this outside of the supervisor handling - * (after the third supervisor from a detach). we (currently?) - * allow both detach/attach to happen in the same set of - * supervisor interrupts, so it would make sense to execute this - * (full power down?) script after all the detach phases of the - * supervisor handling. like with training if needed from the - * second supervisor, nvidia doesn't do this, so who knows if it's - * entirely safe, but it does appear to work.. - * - * without this script being run, on some configurations i've - * seen, switching from DP to TMDS on a DP connector may result - * in a blank screen (SOR_PWR off/on can restore it) + struct nvkm_outp *outp; + struct nvkm_ior *ior; + + /* Determine which OR, if any, we're detaching from the head. */ + HEAD_DBG(head, "supervisor 2.0"); + ior = nv50_disp_super_ior_arm(head); + if (!ior) + return; + + /* Execute OffInt2 IED script. */ + nv50_disp_super_ied_off(head, ior, 2); + + /* If we're shutting down the OR's only active head, execute + * the output path's release function. */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - atomic_set(&outpdp->lt.done, 0); - nvbios_exec(&init); + if (ior->arm.head == (1 << head->id)) { + if ((outp = ior->arm.outp) && outp->func->release) + outp->func->release(outp, ior); } } @@ -695,7 +625,7 @@ nv50_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_0(disp, head->id); + nv50_disp_super_2_0(disp, head); } nvkm_outp_route(&disp->base); 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 { void nv50_disp_super_1(struct nv50_disp *); void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); +void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *); int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, 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 { void *(*dtor)(struct nvkm_outp *); void (*init)(struct nvkm_outp *); void (*fini)(struct nvkm_outp *); + void (*release)(struct nvkm_outp *, struct nvkm_ior *); }; #define nvkm_output nvkm_outp |