drm/nouveau/fb/ga102: load and boot VPR scrubber FW
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:48:32 +0000 (20:48 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 9 Nov 2022 00:45:21 +0000 (10:45 +1000)
v2. fixup for ga103 early merge

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Gourav Samaiya <gsamaiya@nvidia.com>
19 files changed:
drivers/gpu/drm/nouveau/include/nvfw/hs.h
drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h
drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild
drivers/gpu/drm/nouveau/nvkm/falcon/base.c
drivers/gpu/drm/nouveau/nvkm/falcon/fw.c
drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c
drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c

index b53bbc4cd130cfc56c95892ff4b84c2378966716..8c4cd08a7b5f8d7fff1204c2f2b0856aac1d3ac4 100644 (file)
@@ -17,6 +17,20 @@ struct nvfw_hs_header {
 
 const struct nvfw_hs_header *nvfw_hs_header(struct nvkm_subdev *, const void *);
 
+struct nvfw_hs_header_v2 {
+       u32 sig_prod_offset;
+       u32 sig_prod_size;
+       u32 patch_loc;
+       u32 patch_sig;
+       u32 meta_data_offset;
+       u32 meta_data_size;
+       u32 num_sig;
+       u32 header_offset;
+       u32 header_size;
+};
+
+const struct nvfw_hs_header_v2 *nvfw_hs_header_v2(struct nvkm_subdev *, const void *);
+
 struct nvfw_hs_load_header {
        u32 non_sec_code_off;
        u32 non_sec_code_size;
@@ -28,4 +42,18 @@ struct nvfw_hs_load_header {
 
 const struct nvfw_hs_load_header *
 nvfw_hs_load_header(struct nvkm_subdev *, const void *);
+
+struct nvfw_hs_load_header_v2 {
+       u32 os_code_offset;
+       u32 os_code_size;
+       u32 os_data_offset;
+       u32 os_data_size;
+       u32 num_apps;
+       struct {
+               u32 offset;
+               u32 size;
+       } app[0];
+};
+
+const struct nvfw_hs_load_header_v2 *nvfw_hs_load_header_v2(struct nvkm_subdev *, const void *);
 #endif
index 4868d2cb796f8f3905480c5a34ebb9dedf7d4ab2..45d70aa4fd6d328fdb4bdff0545283dd612925dd 100644 (file)
@@ -31,6 +31,13 @@ struct nvkm_falcon_func_pio {
        void (*rd)(struct nvkm_falcon *, u8 port, const u8 *img, int len);
 };
 
+struct nvkm_falcon_func_dma {
+       int (*init)(struct nvkm_falcon *, u64 dma_addr, int xfer_len,
+                   enum nvkm_falcon_mem, bool sec, u32 *cmd);
+       void (*xfer)(struct nvkm_falcon *, u32 mem_base, u32 dma_base, u32 cmd);
+       bool (*done)(struct nvkm_falcon *);
+};
+
 int nvkm_falcon_ctor(const struct nvkm_falcon_func *, struct nvkm_subdev *owner,
                     const char *name, u32 addr, struct nvkm_falcon *);
 void nvkm_falcon_dtor(struct nvkm_falcon *);
@@ -39,6 +46,8 @@ int nvkm_falcon_pio_wr(struct nvkm_falcon *, const u8 *img, u32 img_base, u8 por
                       enum nvkm_falcon_mem mem_type, u32 mem_base, int len, u16 tag, bool sec);
 int nvkm_falcon_pio_rd(struct nvkm_falcon *, u8 port, enum nvkm_falcon_mem type, u32 mem_base,
                       const u8 *img, u32 img_base, int len);
+int nvkm_falcon_dma_wr(struct nvkm_falcon *, const u8 *img, u64 dma_addr, u32 dma_base,
+                      enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec);
 
 int gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *);
 int gm200_flcn_disable(struct nvkm_falcon *);
@@ -52,6 +61,10 @@ void gm200_flcn_tracepc(struct nvkm_falcon *);
 int gp102_flcn_reset_eng(struct nvkm_falcon *);
 extern const struct nvkm_falcon_func_pio gp102_flcn_emem_pio;
 
+int ga102_flcn_reset_prep(struct nvkm_falcon *);
+int ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *);
+extern const struct nvkm_falcon_func_dma ga102_flcn_dma;
+
 void nvkm_falcon_v1_load_imem(struct nvkm_falcon *,
                              void *, u32, u32, u16, u8, bool);
 void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8);
@@ -87,6 +100,9 @@ struct nvkm_falcon_fw {
        u32 sig_size;
        int sig_nr;
        u8 *sigs;
+       u32 fuse_ver;
+       u32 engine_id;
+       u32 ucode_id;
 
        u32 nmem_base_img;
        u32 nmem_base;
@@ -117,6 +133,9 @@ int nvkm_falcon_fw_ctor(const struct nvkm_falcon_fw_func *, const char *name, st
 int nvkm_falcon_fw_ctor_hs(const struct nvkm_falcon_fw_func *, const char *name,
                           struct nvkm_subdev *, const char *bl, const char *img, int ver,
                           struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw);
+int nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *, const char *name,
+                             struct nvkm_subdev *, const char *img, int ver, struct nvkm_falcon *,
+                             struct nvkm_falcon_fw *);
 int nvkm_falcon_fw_sign(struct nvkm_falcon_fw *, u32 sig_base_img, u32 sig_size, const u8 *sigs,
                        int sig_nr_prd, u32 sig_base_prd, int sig_nr_dbg, u32 sig_base_dbg);
 int nvkm_falcon_fw_patch(struct nvkm_falcon_fw *);
@@ -132,6 +151,12 @@ int gm200_flcn_fw_reset(struct nvkm_falcon_fw *);
 int gm200_flcn_fw_load(struct nvkm_falcon_fw *);
 int gm200_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32);
 
+int ga100_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *);
+
+extern const struct nvkm_falcon_fw_func ga102_flcn_fw;
+int ga102_flcn_fw_load(struct nvkm_falcon_fw *);
+int ga102_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32);
+
 #define FLCNFW_PRINTK(f,l,p,fmt,a...) FLCN_PRINTK((f)->falcon, l, p, "%s: "fmt, (f)->fw.name, ##a)
 #define FLCNFW_DBG(f,fmt,a...) FLCNFW_PRINTK((f), DEBUG, info, fmt"\n", ##a)
 #define FLCNFW_ERR(f,fmt,a...) FLCNFW_PRINTK((f), ERROR, err, fmt"\n", ##a)
index f576ca246d100d01e1e6dc76c19f5d0c9b41dcec..dacbd92edcd56724aca987546c462c7925b8a83c 100644 (file)
@@ -19,6 +19,7 @@ struct nvkm_falcon {
        struct nvkm_subdev *owner;
        const char *name;
        u32 addr;
+       u32 addr2;
 
        struct mutex mutex;
        struct mutex dmem_mutex;
@@ -59,8 +60,10 @@ int nvkm_falcon_new_(const struct nvkm_falcon_func *, struct nvkm_device *,
 struct nvkm_falcon_func {
        int (*disable)(struct nvkm_falcon *);
        int (*enable)(struct nvkm_falcon *);
+       u32 addr2;
        bool reset_pmc;
        int (*reset_eng)(struct nvkm_falcon *);
+       int (*reset_prep)(struct nvkm_falcon *);
        int (*reset_wait_mem_scrubbing)(struct nvkm_falcon *);
 
        u32 debug;
@@ -69,7 +72,10 @@ struct nvkm_falcon_func {
        bool bind_intr;
 
        const struct nvkm_falcon_func_pio *imem_pio;
+       const struct nvkm_falcon_func_dma *imem_dma;
+
        const struct nvkm_falcon_func_pio *dmem_pio;
+       const struct nvkm_falcon_func_dma *dmem_dma;
 
        u32 emem_addr;
        const struct nvkm_falcon_func_pio *emem_pio;
index 97bd3092f68a6c520c6c13258e53726fbd757f3d..9baf197ac8336f3a0b6c5d25125ce33981c24f0e 100644 (file)
@@ -12,4 +12,5 @@ struct nvkm_nvdec {
 };
 
 int gm107_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **);
+int ga102_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **);
 #endif
index 931a59581815968eb11e107eb402a3da09e638cd..8162efcf2dd64c81670ca1bdf9a268b43f4266bc 100644 (file)
@@ -2615,6 +2615,7 @@ nv172_chipset = {
        .disp     = { 0x00000001, ga102_disp_new },
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
+       .nvdec    = { 0x00000001, ga102_nvdec_new },
 };
 
 static const struct nvkm_device_chip
@@ -2639,6 +2640,7 @@ nv173_chipset = {
        .disp     = { 0x00000001, ga102_disp_new },
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
+       .nvdec    = { 0x00000001, ga102_nvdec_new },
 };
 
 static const struct nvkm_device_chip
@@ -2663,6 +2665,7 @@ nv174_chipset = {
        .disp     = { 0x00000001, ga102_disp_new },
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
+       .nvdec    = { 0x00000001, ga102_nvdec_new },
 };
 
 static const struct nvkm_device_chip
@@ -2687,6 +2690,7 @@ nv176_chipset = {
        .disp     = { 0x00000001, ga102_disp_new },
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
+       .nvdec    = { 0x00000001, ga102_nvdec_new },
 };
 
 static const struct nvkm_device_chip
@@ -2711,6 +2715,7 @@ nv177_chipset = {
        .disp     = { 0x00000001, ga102_disp_new },
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
+       .nvdec    = { 0x00000001, ga102_nvdec_new },
 };
 
 struct nvkm_subdev *
index 9a0fd9812750dd2224de1316f7a2351322ed3566..f05e79670d22736647b3995b0065907bbfd0573a 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/nvdec/base.o
 nvkm-y += nvkm/engine/nvdec/gm107.o
+nvkm-y += nvkm/engine/nvdec/ga102.o
index b0181cc5953bc827a8477d360c7089925cd670ab..1f6e3b32ba163cfc70c8e21acbb1cdb58c3d94e8 100644 (file)
@@ -37,7 +37,7 @@ nvkm_nvdec = {
 
 int
 nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device,
-               enum nvkm_subdev_type type, int inst, struct nvkm_nvdec **pnvdec)
+               enum nvkm_subdev_type type, int inst, u32 addr, struct nvkm_nvdec **pnvdec)
 {
        struct nvkm_nvdec *nvdec;
        int ret;
@@ -57,5 +57,5 @@ nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device,
        nvdec->func = fwif->func;
 
        return nvkm_falcon_ctor(nvdec->func->flcn, &nvdec->engine.subdev,
-                               nvdec->engine.subdev.name, 0, &nvdec->falcon);
+                               nvdec->engine.subdev.name, addr, &nvdec->falcon);
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c
new file mode 100644 (file)
index 0000000..37d8c3c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+static const struct nvkm_falcon_func
+ga102_nvdec_flcn = {
+       .disable = gm200_flcn_disable,
+       .enable = gm200_flcn_enable,
+       .addr2 = 0x1c00,
+       .reset_pmc = true,
+       .reset_prep = ga102_flcn_reset_prep,
+       .reset_wait_mem_scrubbing = ga102_flcn_reset_wait_mem_scrubbing,
+       .imem_dma = &ga102_flcn_dma,
+       .dmem_dma = &ga102_flcn_dma,
+};
+
+static const struct nvkm_nvdec_func
+ga102_nvdec = {
+       .flcn = &ga102_nvdec_flcn,
+};
+
+static int
+ga102_nvdec_nofw(struct nvkm_nvdec *nvdec, int ver, const struct nvkm_nvdec_fwif *fwif)
+{
+       return 0;
+}
+
+static const struct nvkm_nvdec_fwif
+ga102_nvdec_fwif[] = {
+       { -1, ga102_nvdec_nofw, &ga102_nvdec },
+       {}
+};
+
+int
+ga102_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+               struct nvkm_nvdec **pnvdec)
+{
+       return nvkm_nvdec_new_(ga102_nvdec_fwif, device, type, inst, 0x848000, pnvdec);
+}
index 5d04ded35cc34648d34b2b46703c2542d7050fb9..564f7e8960a2016d1af1cade0bbf16156c15f862 100644 (file)
@@ -54,5 +54,5 @@ int
 gm107_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
                struct nvkm_nvdec **pnvdec)
 {
-       return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, pnvdec);
+       return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, 0, pnvdec);
 }
index 0920f6a887e2a1f4b047507cb62dd00b678b7b44..61e1f7aaa50933ae2ef32bd699fad679bd5c03fe 100644 (file)
@@ -15,5 +15,5 @@ struct nvkm_nvdec_fwif {
 };
 
 int nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *,
-                   enum nvkm_subdev_type, int, struct nvkm_nvdec **);
+                   enum nvkm_subdev_type, int, u32 addr, struct nvkm_nvdec **);
 #endif
index 6ffde5290b8764677b78b653466ccbb35bd376b6..9ffe7b921ccb528d712efc94076d8655dd57fbcd 100644 (file)
@@ -8,3 +8,5 @@ nvkm-y += nvkm/falcon/v1.o
 
 nvkm-y += nvkm/falcon/gm200.o
 nvkm-y += nvkm/falcon/gp102.o
+nvkm-y += nvkm/falcon/ga100.o
+nvkm-y += nvkm/falcon/ga102.o
index e4075aa441f37a8ee15a109a541c047199d2c7fb..235149f73a690d8dfef496c84e20774581e7e79e 100644 (file)
 #include <subdev/timer.h>
 #include <subdev/top.h>
 
+static const struct nvkm_falcon_func_dma *
+nvkm_falcon_dma(struct nvkm_falcon *falcon, enum nvkm_falcon_mem *mem_type, u32 *mem_base)
+{
+       switch (*mem_type) {
+       case IMEM: return falcon->func->imem_dma;
+       case DMEM: return falcon->func->dmem_dma;
+       default:
+               return NULL;
+       }
+}
+
+int
+nvkm_falcon_dma_wr(struct nvkm_falcon *falcon, const u8 *img, u64 dma_addr, u32 dma_base,
+                  enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec)
+{
+       const struct nvkm_falcon_func_dma *dma = nvkm_falcon_dma(falcon, &mem_type, &mem_base);
+       const char *type = nvkm_falcon_mem(mem_type);
+       const int dmalen = 256;
+       u32 dma_start = 0;
+       u32 dst, src, cmd;
+       int ret, i;
+
+       if (WARN_ON(!dma->xfer))
+               return -EINVAL;
+
+       if (mem_type == DMEM) {
+               dma_start = dma_base;
+               dma_addr += dma_base;
+       }
+
+       FLCN_DBG(falcon, "%s %08x <- %08x bytes at %08x (%010llx %08x)",
+                type, mem_base, len, dma_base, dma_addr - dma_base, dma_start);
+       if (WARN_ON(!len || (len & (dmalen - 1))))
+               return -EINVAL;
+
+       ret = dma->init(falcon, dma_addr, dmalen, mem_type, sec, &cmd);
+       if (ret)
+               return ret;
+
+       dst = mem_base;
+       src = dma_base;
+       if (len) {
+               while (len >= dmalen) {
+                       dma->xfer(falcon, dst, src - dma_start, cmd);
+
+                       if (img && nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) {
+                               for (i = 0; i < dmalen; i += 4, mem_base += 4) {
+                                       const int w = 8, x = (i / 4) % w;
+
+                                       if (x == 0)
+                                               printk(KERN_INFO "%s %08x <-", type, mem_base);
+                                       printk(KERN_CONT " %08x", *(u32 *)(img + src + i));
+                                       if (x == (w - 1) || ((i + 4) == dmalen))
+                                               printk(KERN_CONT " <- %08x+%08x", dma_base,
+                                                      src + i - dma_base - (x * 4));
+                                       if (i == (7 * 4))
+                                               printk(KERN_CONT " *");
+                               }
+                       }
+
+                       if (nvkm_msec(falcon->owner->device, 2000,
+                               if (dma->done(falcon))
+                                       break;
+                       ) < 0)
+                               return -ETIMEDOUT;
+
+                       src += dmalen;
+                       dst += dmalen;
+                       len -= dmalen;
+               }
+               WARN_ON(len);
+       }
+
+       return 0;
+}
+
 static const struct nvkm_falcon_func_pio *
 nvkm_falcon_pio(struct nvkm_falcon *falcon, enum nvkm_falcon_mem *mem_type, u32 *mem_base)
 {
@@ -239,6 +315,7 @@ nvkm_falcon_ctor(const struct nvkm_falcon_func *func,
        falcon->owner = subdev;
        falcon->name = name;
        falcon->addr = addr;
+       falcon->addr2 = func->addr2;
        mutex_init(&falcon->mutex);
        mutex_init(&falcon->dmem_mutex);
        return 0;
index 13d52d7e4f60bd58595b55006ce0dbb816de282a..80a480b12174680b859cd0468eb087c9ffba8055 100644 (file)
@@ -294,3 +294,61 @@ done:
        nvkm_firmware_put(blob);
        return ret;
 }
+
+int
+nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *func, const char *name,
+                         struct nvkm_subdev *subdev, const char *img, int ver,
+                         struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw)
+{
+       const struct nvfw_bin_hdr *hdr;
+       const struct nvfw_hs_header_v2 *hshdr;
+       const struct nvfw_hs_load_header_v2 *lhdr;
+       const struct firmware *blob;
+       u32 loc, sig, cnt, *meta;
+       int ret;
+
+       ret = nvkm_firmware_load_name(subdev, img, "", ver, &blob);
+       if (ret)
+               return ret;
+
+       hdr = nvfw_bin_hdr(subdev, blob->data);
+       hshdr = nvfw_hs_header_v2(subdev, blob->data + hdr->header_offset);
+       meta = (u32 *)(blob->data + hshdr->meta_data_offset);
+       loc = *(u32 *)(blob->data + hshdr->patch_loc);
+       sig = *(u32 *)(blob->data + hshdr->patch_sig);
+       cnt = *(u32 *)(blob->data + hshdr->num_sig);
+
+       ret = nvkm_falcon_fw_ctor(func, name, subdev->device, true,
+                                 blob->data + hdr->data_offset, hdr->data_size, falcon, fw);
+       if (ret)
+               goto done;
+
+       ret = nvkm_falcon_fw_sign(fw, loc, hshdr->sig_prod_size / cnt, blob->data,
+                                 cnt, hshdr->sig_prod_offset + sig, 0, 0);
+       if (ret)
+               goto done;
+
+       lhdr = nvfw_hs_load_header_v2(subdev, blob->data + hshdr->header_offset);
+
+       fw->imem_base_img = lhdr->app[0].offset;
+       fw->imem_base = 0;
+       fw->imem_size = lhdr->app[0].size;
+
+       fw->dmem_base_img = lhdr->os_data_offset;
+       fw->dmem_base = 0;
+       fw->dmem_size = lhdr->os_data_size;
+       fw->dmem_sign = loc - lhdr->os_data_offset;
+
+       fw->boot_addr = lhdr->app[0].offset;
+
+       fw->fuse_ver = meta[0];
+       fw->engine_id = meta[1];
+       fw->ucode_id = meta[2];
+
+done:
+       if (ret)
+               nvkm_falcon_fw_dtor(fw);
+
+       nvkm_firmware_put(blob);
+       return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c b/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c
new file mode 100644 (file)
index 0000000..49fd329
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+int
+ga100_flcn_fw_signature(struct nvkm_falcon_fw *fw, u32 *src_base_src)
+{
+       struct nvkm_falcon *falcon = fw->falcon;
+       struct nvkm_device *device = falcon->owner->device;
+       u32 reg_fuse_version;
+       int idx;
+
+       FLCN_DBG(falcon, "brom: %08x %08x", fw->engine_id, fw->ucode_id);
+       FLCN_DBG(falcon, "fuse_version: %d", fw->fuse_ver);
+
+       if (fw->engine_id & 0x00000001) {
+               reg_fuse_version = nvkm_rd32(device, 0x824140 + (fw->ucode_id - 1) * 4);
+       } else
+       if (fw->engine_id & 0x00000004) {
+               reg_fuse_version = nvkm_rd32(device, 0x824100 + (fw->ucode_id - 1) * 4);
+       } else
+       if (fw->engine_id & 0x00000400) {
+               reg_fuse_version = nvkm_rd32(device, 0x8241c0 + (fw->ucode_id - 1) * 4);
+       } else {
+               WARN_ON(1);
+               return -ENOSYS;
+       }
+
+       FLCN_DBG(falcon, "reg_fuse_version: %08x", reg_fuse_version);
+       if (reg_fuse_version) {
+               reg_fuse_version = fls(reg_fuse_version);
+               FLCN_DBG(falcon, "reg_fuse_version: %d", reg_fuse_version);
+
+               if (WARN_ON(fw->fuse_ver < reg_fuse_version))
+                       return -EINVAL;
+
+               idx = fw->fuse_ver - reg_fuse_version;
+       } else {
+               idx = fw->sig_nr - 1;
+       }
+
+       return idx;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c b/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c
new file mode 100644 (file)
index 0000000..38306f9
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2022 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+static bool
+ga102_flcn_dma_done(struct nvkm_falcon *falcon)
+{
+       return !!(nvkm_falcon_rd32(falcon, 0x118) & 0x00000002);
+}
+
+static void
+ga102_flcn_dma_xfer(struct nvkm_falcon *falcon, u32 mem_base, u32 dma_base, u32 cmd)
+{
+       nvkm_falcon_wr32(falcon, 0x114, mem_base);
+       nvkm_falcon_wr32(falcon, 0x11c, dma_base);
+       nvkm_falcon_wr32(falcon, 0x118, cmd);
+}
+
+static int
+ga102_flcn_dma_init(struct nvkm_falcon *falcon, u64 dma_addr, int xfer_len,
+                   enum nvkm_falcon_mem mem_type, bool sec, u32 *cmd)
+{
+       *cmd = (ilog2(xfer_len) - 2) << 8;
+       if (mem_type == IMEM)
+               *cmd |= 0x00000010;
+       if (sec)
+               *cmd |= 0x00000004;
+
+       nvkm_falcon_wr32(falcon, 0x110, dma_addr >> 8);
+       nvkm_falcon_wr32(falcon, 0x128, 0x00000000);
+       return 0;
+}
+
+const struct nvkm_falcon_func_dma
+ga102_flcn_dma = {
+       .init = ga102_flcn_dma_init,
+       .xfer = ga102_flcn_dma_xfer,
+       .done = ga102_flcn_dma_done,
+};
+
+int
+ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon)
+{
+       nvkm_falcon_mask(falcon, 0x040, 0x00000000, 0x00000000);
+
+       if (nvkm_msec(falcon->owner->device, 20,
+               if (!(nvkm_falcon_rd32(falcon, 0x0f4) & 0x00001000))
+                       break;
+       ) < 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+int
+ga102_flcn_reset_prep(struct nvkm_falcon *falcon)
+{
+       const u32 addr2 = (falcon->owner->type != NVKM_ENGINE_NVDEC) ? 0x530 : 0x930;
+
+       if (nvkm_msec(falcon->owner->device, 10,
+               if ((nvkm_falcon_rd32(falcon, falcon->addr2 + 0x1ec) & 0x00000003) == 0x00000001 &&
+                   (nvkm_falcon_rd32(falcon,                 addr2) & 0x00000008) == 0x00000008)
+                       break;
+       ) < 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+int
+ga102_flcn_fw_boot(struct nvkm_falcon_fw *fw, u32 *mbox0, u32 *mbox1, u32 mbox0_ok, u32 irqsclr)
+{
+       struct nvkm_falcon *falcon = fw->falcon;
+
+       nvkm_falcon_wr32(falcon, falcon->addr2 + 0x210, fw->dmem_sign);
+       nvkm_falcon_wr32(falcon, falcon->addr2 + 0x19c, fw->engine_id);
+       nvkm_falcon_wr32(falcon, falcon->addr2 + 0x198, fw->ucode_id);
+       nvkm_falcon_wr32(falcon, falcon->addr2 + 0x180, 0x00000001);
+
+       return gm200_flcn_fw_boot(fw, mbox0, mbox1, mbox0_ok, irqsclr);
+}
+
+int
+ga102_flcn_fw_load(struct nvkm_falcon_fw *fw)
+{
+       struct nvkm_falcon *falcon = fw->falcon;
+       int ret = 0;
+
+       nvkm_falcon_mask(falcon, 0x624, 0x00000080, 0x00000080);
+       nvkm_falcon_wr32(falcon, 0x10c, 0x00000000);
+       nvkm_falcon_mask(falcon, 0x600, 0x00010007, (0 << 16) | (1 << 2) | 1);
+
+       ret = nvkm_falcon_dma_wr(falcon, fw->fw.img, fw->fw.phys, fw->imem_base_img,
+                                IMEM, fw->imem_base, fw->imem_size, true);
+       if (ret)
+               return ret;
+
+       ret = nvkm_falcon_dma_wr(falcon, fw->fw.img, fw->fw.phys, fw->dmem_base_img,
+                                DMEM, fw->dmem_base, fw->dmem_size, false);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+const struct nvkm_falcon_fw_func
+ga102_flcn_fw = {
+       .signature = ga100_flcn_fw_signature,
+       .reset = gm200_flcn_fw_reset,
+       .load = ga102_flcn_fw_load,
+       .boot = ga102_flcn_fw_boot,
+};
index af53cbbc632ca63fd0cee05f90992b85ab91ccc6..6990890a760e68c7adb4938de05faa6434c3a6d2 100644 (file)
@@ -171,8 +171,15 @@ gm200_flcn_disable(struct nvkm_falcon *falcon)
        nvkm_falcon_mask(falcon, 0x048, 0x00000003, 0x00000000);
        nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
 
-       if (falcon->func->reset_pmc)
+       if (falcon->func->reset_pmc) {
+               if (falcon->func->reset_prep) {
+                       ret = falcon->func->reset_prep(falcon);
+                       if (ret)
+                               return ret;
+               }
+
                nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst);
+       }
 
        if (falcon->func->reset_eng) {
                ret = falcon->func->reset_eng(falcon);
index c70beacb8d30b807966f7e7648d6463001d627c2..c774935f3077b5baf9042b197f8f34cef347cf04 100644 (file)
@@ -66,6 +66,14 @@ gp102_flcn_emem_pio = {
 int
 gp102_flcn_reset_eng(struct nvkm_falcon *falcon)
 {
+       int ret;
+
+       if (falcon->func->reset_prep) {
+               ret = falcon->func->reset_prep(falcon);
+               if (ret)
+                       return ret;
+       }
+
        nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000001);
        udelay(10);
        nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000000);
index 04ed77cb2ebabee2ff1ba55167e054f6294a23d2..a7e0583401d0ea8c8cccf8ec07709b9d5e582809 100644 (file)
@@ -38,6 +38,24 @@ nvfw_hs_header(struct nvkm_subdev *subdev, const void *data)
        return hdr;
 }
 
+const struct nvfw_hs_header_v2 *
+nvfw_hs_header_v2(struct nvkm_subdev *subdev, const void *data)
+{
+       const struct nvfw_hs_header_v2 *hdr = data;
+
+       nvkm_debug(subdev, "hsHeader:\n");
+       nvkm_debug(subdev, "\tsigProdOffset    : 0x%x\n", hdr->sig_prod_offset);
+       nvkm_debug(subdev, "\tsigProdSize      : 0x%x\n", hdr->sig_prod_size);
+       nvkm_debug(subdev, "\tpatchLoc         : 0x%x\n", hdr->patch_loc);
+       nvkm_debug(subdev, "\tpatchSig         : 0x%x\n", hdr->patch_sig);
+       nvkm_debug(subdev, "\tmetadataOffset   : 0x%x\n", hdr->meta_data_offset);
+       nvkm_debug(subdev, "\tmetadataSize     : 0x%x\n", hdr->meta_data_size);
+       nvkm_debug(subdev, "\tnumSig           : 0x%x\n", hdr->num_sig);
+       nvkm_debug(subdev, "\theaderOffset     : 0x%x\n", hdr->header_offset);
+       nvkm_debug(subdev, "\theaderSize       : 0x%x\n", hdr->header_size);
+       return hdr;
+}
+
 const struct nvfw_hs_load_header *
 nvfw_hs_load_header(struct nvkm_subdev *subdev, const void *data)
 {
@@ -60,3 +78,24 @@ nvfw_hs_load_header(struct nvkm_subdev *subdev, const void *data)
 
        return hdr;
 }
+
+const struct nvfw_hs_load_header_v2 *
+nvfw_hs_load_header_v2(struct nvkm_subdev *subdev, const void *data)
+{
+       const struct nvfw_hs_load_header_v2 *hdr = data;
+       int i;
+
+       nvkm_debug(subdev, "hsLoadHeader:\n");
+       nvkm_debug(subdev, "\tosCodeOffset     : 0x%x\n", hdr->os_code_offset);
+       nvkm_debug(subdev, "\tosCodeSize       : 0x%x\n", hdr->os_code_size);
+       nvkm_debug(subdev, "\tosDataOffset     : 0x%x\n", hdr->os_data_offset);
+       nvkm_debug(subdev, "\tosDataSize       : 0x%x\n", hdr->os_data_size);
+       nvkm_debug(subdev, "\tnumApps          : 0x%x\n", hdr->num_apps);
+       for (i = 0; i < hdr->num_apps; i++) {
+               nvkm_debug(subdev,
+                          "\tApp[%d]           : offset 0x%x size 0x%x\n", i,
+                          hdr->app[i].offset, hdr->app[i].size);
+       }
+
+       return hdr;
+}
index 52435c0a485c70bd3468e1ebc467f8578f293d3f..8b7c8ea5e8a5f3f887f20fb3c3a92b1b1b2b8e1c 100644 (file)
 #include "gf100.h"
 #include "ram.h"
 
+#include <engine/nvdec.h>
+
+static int
+ga102_fb_vpr_scrub(struct nvkm_fb *fb)
+{
+       struct nvkm_falcon_fw fw = {};
+       int ret;
+
+       ret = nvkm_falcon_fw_ctor_hs_v2(&ga102_flcn_fw, "mem-unlock", &fb->subdev, "nvdec/scrubber",
+                                       0, &fb->subdev.device->nvdec[0]->falcon, &fw);
+       if (ret)
+               return ret;
+
+       ret = nvkm_falcon_fw_boot(&fw, &fb->subdev, true, NULL, NULL, 0, 0);
+       nvkm_falcon_fw_dtor(&fw);
+       return ret;
+}
+
+static bool
+ga102_fb_vpr_scrub_required(struct nvkm_fb *fb)
+{
+       return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0;
+}
+
 static const struct nvkm_fb_func
 ga102_fb = {
        .dtor = gf100_fb_dtor,
@@ -32,6 +56,8 @@ ga102_fb = {
        .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = ga102_ram_new,
        .default_bigpage = 16,
+       .vpr.scrub_required = ga102_fb_vpr_scrub_required,
+       .vpr.scrub = ga102_fb_vpr_scrub,
 };
 
 int
@@ -39,3 +65,9 @@ ga102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, s
 {
        return gp102_fb_new_(&ga102_fb, device, type, inst, pfb);
 }
+
+MODULE_FIRMWARE("nvidia/ga102/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga103/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga104/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga106/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga107/nvdec/scrubber.bin");