]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
drm/nouveau/disp/nv50-: implement a common supervisor 3.0
authorBen Skeggs <bskeggs@redhat.com>
Fri, 19 May 2017 13:59:35 +0000 (23:59 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 16 Jun 2017 04:05:00 +0000 (14:05 +1000)
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>
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c

index c7383e1f0966e9ee19f21207344318a3d919725b..06ab48052128ef404a4b483646537f08bbd045f5 100644 (file)
@@ -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;
index f4a05549f642dfdaff2585a411a289bfce8953d5..d8765b57180b9530154583bd37c41ef255dc2d0a 100644 (file)
 #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);
                }
        }
 
index d6bfaa53f96b237a810788ddfc526a327c98330d..1e11e25a41f1ae35b4c123995e2ccd5077acb869 100644 (file)
@@ -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,
index f21e0e92d6f1a65acb46e4a651c1ca8f84d87378..0c570dbd3021b45472a31a96afee19e88a4adea0 100644 (file)
@@ -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);
index b6092b8b528a5f3c1ab58666c727daee26ed2502..19c635663399a2442b670479df18621119595043 100644 (file)
@@ -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 **);
index 7655d9293911ea509c8924694f9016175a5da584..146d101d4891de39b88fa69919a56a50665d9997 100644 (file)
@@ -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",    \
index bdace3852b37399189a1318524b30a215956b8de..771a1abbdf15aa2d1bdf75d206ee318de5b2ce9c 100644 (file)
@@ -22,7 +22,6 @@
  * Authors: Ben Skeggs
  */
 #include "ior.h"
-#include "nv50.h"
 
 #include <subdev/timer.h>
 
@@ -120,38 +119,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
        return 0;
 }
 
-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)
 {
@@ -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,
index 2095f43e16ac76f8645cd9cc9e1c0a65149ccd1d..b58ee99f7bfc8a3ec3ff608fdf7a6202955a3cf5 100644 (file)
@@ -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);