diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 125 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 168 | ||||
-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 | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c | 5 |
8 files changed, 35 insertions, 338 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index c7383e1f0966..06ab48052128 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -3,16 +3,12 @@ struct nvbios_init { struct nvkm_subdev *subdev; - struct nvkm_bios *bios; u32 offset; struct dcb_output *outp; int or; int link; - union { - int head; - int crtc; - }; + int head; /* internal state used during parsing */ u8 execute; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index f4a05549f642..d8765b57180b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -26,128 +26,6 @@ #include "ior.h" #include "rootnv50.h" -#include <subdev/bios.h> -#include <subdev/bios/disp.h> -#include <subdev/bios/init.h> -#include <subdev/bios/pll.h> -#include <subdev/devinit.h> - -static struct nvkm_output * -exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, - u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_outp *info) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_output *outp; - u16 mask, type; - - if (or < 4) { - type = DCB_OUTPUT_ANALOG; - mask = 0; - } else { - or -= 4; - switch (ctrl & 0x00000f00) { - case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; - case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; - case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; - case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; - case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; - case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; - default: - nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); - return NULL; - } - } - - mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << or; - mask |= 0x0100 << head; - - list_for_each_entry(outp, &disp->base.outp, head) { - if ((outp->info.hasht & 0xff) == type && - (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, mask, - ver, hdr, cnt, len, info); - if (!*data) - return NULL; - return outp; - } - } - - return NULL; -} - -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; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info1; - struct nvbios_ocfg info2; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!outp) - return NULL; - - *conf = (ctrl & 0x00000f00) >> 8; - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - if (*conf == 5) - *conf |= 0x0100; - break; - case DCB_OUTPUT_LVDS: - *conf |= disp->sor.lvdsconf; - break; - default: - break; - } - - data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8, - &ver, &hdr, &cnt, &len, &info2); - if (data && id < 0xff) { - data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); - if (data) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = data, - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - } - - return outp; -} - -static void -gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - u32 conf; - - exec_clkcmp(disp, head, 1, pclk, &conf); -} - void gf119_disp_super(struct work_struct *work) { @@ -195,8 +73,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 3.0 - head %d\n", head->id); - gf119_disp_intr_unk4_0(disp, head->id); + nv50_disp_super_3_0(disp, head); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index d6bfaa53f96b..1e11e25a41f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -52,6 +52,7 @@ struct nvkm_ior_func { int (*sense)(struct nvkm_ior *, u32 loadval); void (*clock)(struct nvkm_ior *); void (*war_2)(struct nvkm_ior *); + void (*war_3)(struct nvkm_ior *); struct { void (*ctrl)(struct nvkm_ior *, int head, bool enable, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index f21e0e92d6f1..0c570dbd3021 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -238,162 +238,23 @@ nv50_disp_super_ior_arm(struct nvkm_head *head) return NULL; } -static struct nvkm_output * -exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, - u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_outp *info) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_output *outp; - u16 mask, type; - - if (or < 4) { - type = DCB_OUTPUT_ANALOG; - mask = 0; - } else - if (or < 8) { - switch (ctrl & 0x00000f00) { - case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; - case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; - case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; - case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; - case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; - case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; - default: - nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); - return NULL; - } - or -= 4; - } else { - or = or - 8; - type = 0x0010; - mask = 0; - switch (ctrl & 0x00000f00) { - case 0x00000000: type |= disp->pior.type[or]; break; - default: - nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl); - return NULL; - } - } - - mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << or; - mask |= 0x0100 << head; - - list_for_each_entry(outp, &disp->base.outp, head) { - if ((outp->info.hasht & 0xff) == type && - (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, mask, - ver, hdr, cnt, len, info); - if (!*data) - return NULL; - return outp; - } - } - - return NULL; -} - -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; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info1; - struct nvbios_ocfg info2; - 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, 0x610b58 + (i * 8)); - - /* SOR */ - if (!(ctrl & (1 << head))) { - if (device->chipset < 0x90 || - device->chipset == 0x92 || - device->chipset == 0xa0) { - reg = 0x610b70; - } else { - reg = 0x610794; - } - 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, 0x610b80 + (i * 8)); - i += 8; - } - - if (!(ctrl & (1 << head))) - return NULL; - i--; - - outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!outp) - return NULL; - - *conf = (ctrl & 0x00000f00) >> 8; - if (outp->info.location == 0) { - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - if (*conf == 5) - *conf |= 0x0100; - break; - case DCB_OUTPUT_LVDS: - *conf |= disp->sor.lvdsconf; - break; - default: - break; - } - } else { - *conf = (ctrl & 0x00000f00) >> 8; - pclk = pclk / 2; - } - - data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8, - &ver, &hdr, &cnt, &len, &info2); - if (data && id < 0xff) { - data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); - if (data) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = data, - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - } - - return outp; -} - -static void -nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) +void +nv50_disp_super_3_0(struct nv50_disp *disp, struct nvkm_head *head) { - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_output *outp; - u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; - u32 conf; + struct nvkm_ior *ior; - outp = exec_clkcmp(disp, head, 1, pclk, &conf); - if (!outp) + /* Determine which OR, if any, we're attaching to the head. */ + HEAD_DBG(head, "supervisor 3.0"); + ior = nv50_disp_super_ior_asy(head); + if (!ior) return; - nv50_disp_dptmds_war_3(disp, &outp->info); + /* Execute OnInt3 IED script. */ + nv50_disp_super_ied_on(head, ior, 1, head->asy.hz / 1000); + + /* OR-specific handling. */ + if (ior->func->war_3) + ior->func->war_3(ior); } static void @@ -660,9 +521,8 @@ 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_unk40_0(disp, head->id); + nv50_disp_super_3_0(disp, head); } - nv50_disp_update_sppll1(disp); } nvkm_wr32(device, 0x610030, 0x80000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index b6092b8b528a..19c635663399 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -30,6 +30,7 @@ void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_1(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_2(struct nv50_disp *, struct nvkm_head *); +void nv50_disp_super_3_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 7655d9293911..146d101d4891 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -43,10 +43,6 @@ struct nvkm_outp_func { void (*release)(struct nvkm_outp *, struct nvkm_ior *); }; -#define nvkm_output nvkm_outp -#define nvkm_output_func nvkm_outp_func -#define nvkm_output_new_ nvkm_outp_new_ - #define OUTP_MSG(o,l,f,a...) do { \ struct nvkm_outp *_outp = (o); \ nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index bdace3852b37..771a1abbdf15 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" #include <subdev/timer.h> @@ -121,38 +120,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) } static bool -nv50_disp_dptmds_war(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x94: - case 0x96: - case 0x98: - return true; - default: - break; - } - return false; -} - -static bool -nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; - if (nv50_disp_dptmds_war(device) && outp->type == DCB_OUTPUT_TMDS) { - switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { - case 0x00000000: - case 0x00030000: - return true; - default: - break; - } - } - return false; - -} - -static bool g94_sor_war_needed(struct nvkm_ior *sor) { struct nvkm_device *device = sor->disp->engine.subdev.device; @@ -169,18 +136,19 @@ g94_sor_war_needed(struct nvkm_ior *sor) return false; } -void -nv50_disp_update_sppll1(struct nv50_disp *disp) +static void +g94_sor_war_update_sppll1(struct nvkm_disp *disp) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_ior *ior; bool used = false; - int sor; + u32 clksor; - if (!nv50_disp_dptmds_war(device)) - return; + list_for_each_entry(ior, &disp->ior, head) { + if (ior->type != SOR) + continue; - for (sor = 0; sor < disp->func->sor.nr; sor++) { - u32 clksor = nvkm_rd32(device, 0x614300 + (sor * 0x800)); + clksor = nvkm_rd32(device, 0x614300 + nv50_ior_base(ior)); switch (clksor & 0x03000000) { case 0x02000000: case 0x03000000: @@ -197,14 +165,14 @@ nv50_disp_update_sppll1(struct nv50_disp *disp) nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000); } -void -nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) +static void +g94_sor_war_3(struct nvkm_ior *sor) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); u32 sorpwr; - if (!nv50_disp_dptmds_war_needed(disp, outp)) + if (!g94_sor_war_needed(sor)) return; sorpwr = nvkm_rd32(device, 0x61c004 + soff); @@ -235,6 +203,8 @@ nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) if (sorpwr & 0x00000001) { nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001); } + + g94_sor_war_update_sppll1(sor->disp); } static void @@ -293,6 +263,7 @@ g94_sor = { .power = nv50_sor_power, .clock = nv50_sor_clock, .war_2 = g94_sor_war_2, + .war_3 = g94_sor_war_3, .dp = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 2095f43e16ac..b58ee99f7bfc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -2278,11 +2278,6 @@ nvbios_exec(struct nvbios_init *init) { struct nvkm_bios *bios = init->subdev->device->bios; - if (init->bios) { - init->or = init->outp ? ffs(init->outp->or) - 1 : -1; - init->link = init->outp ? init->outp->sorconf.link : 0; - } - init->nested++; while (init->offset) { u8 opcode = nvbios_rd08(bios, init->offset); |