drm/nouveau/acr/ga102: initial support
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:48:33 +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>
28 files changed:
drivers/gpu/drm/nouveau/include/nvfw/acr.h
drivers/gpu/drm/nouveau/include/nvfw/ls.h
drivers/gpu/drm/nouveau/include/nvfw/sec2.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/sec2.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c
drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c
drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c
drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c
drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c [new file with mode: 0644]

index e65d6a8..6f19560 100644 (file)
@@ -39,6 +39,23 @@ struct wpr_header_v1 {
 
 void wpr_header_v1_dump(struct nvkm_subdev *, const struct wpr_header_v1 *);
 
+struct wpr_generic_header {
+#define WPR_GENERIC_HEADER_ID_LSF_UCODE_DESC     1
+#define WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER     2
+#define WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR 3
+#define WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER     4
+       u16 identifier;
+       u16 version;
+       u32 size;
+};
+
+struct wpr_header_v2 {
+       struct wpr_generic_header hdr;
+       struct wpr_header_v1 wpr;
+};
+
+void wpr_header_v2_dump(struct nvkm_subdev *, const struct wpr_header_v2 *);
+
 struct lsf_signature {
        u8 prd_keys[2][16];
        u8 dbg_keys[2][16];
@@ -89,6 +106,74 @@ struct lsb_header_v1 {
 
 void lsb_header_v1_dump(struct nvkm_subdev *, struct lsb_header_v1 *);
 
+struct lsb_header_v2 {
+       struct wpr_generic_header hdr;
+       struct lsf_signature_v2 {
+               struct wpr_generic_header hdr;
+               u32 falcon_id;
+               u8 prd_present;
+               u8 dbg_present;
+               u16 reserved;
+               u32 sig_size;
+               u8 prod_sig[2][384 + 128];
+               u8 debug_sig[2][384 + 128];
+               u16 sig_algo_ver;
+               u16 sig_algo;
+               u16 hash_algo_ver;
+               u16 hash_algo;
+               u32 sig_algo_padding_type;
+               u8 depmap[11 * 2 * 4];
+               u32 depmap_count;
+               u8 supports_versioning;
+               u8 pad[3];
+               u32 ls_ucode_version;
+               u32 ls_ucode_id;
+               u32 ucode_ls_encrypted;
+               u32 ls_eng_algo_type;
+               u32 ls_eng_algo_ver;
+               u8 ls_enc_iv[16];
+               u8 rsvd[36];
+       } signature;
+       u32 ucode_off;
+       u32 ucode_size;
+       u32 data_size;
+       u32 bl_code_size;
+       u32 bl_imem_off;
+       u32 bl_data_off;
+       u32 bl_data_size;
+       u32 rsvd0;
+       u32 app_code_off;
+       u32 app_code_size;
+       u32 app_data_off;
+       u32 app_data_size;
+       u32 app_imem_offset;
+       u32 app_dmem_offset;
+       u32 flags;
+       u32 monitor_code_offset;
+       u32 monitor_data_offset;
+       u32 manifest_offset;
+       struct hs_fmc_params {
+               u8 hs_fmc;
+               u8 padding[3];
+               u16 pkc_algo;
+               u16 pkc_algo_version;
+               u32 engid_mask;
+               u32 ucode_id;
+               u32 fuse_ver;
+               u8 pkc_signature[384 + 128];
+               u8 pkc_key[2048];
+               u8 rsvd[4];
+       } hs_fmc_params;
+       struct hs_ovl_sig_blob_params {
+               u8 hs_ovl_sig_blob_present;
+               u32 hs_ovl_sig_blob_offset;
+               u32 hs_ovl_sig_blob_size;
+       } hs_ovl_sig_blob_params;
+       u8 rsvd[20];
+};
+
+void lsb_header_v2_dump(struct nvkm_subdev *, struct lsb_header_v2 *);
+
 struct flcn_acr_desc {
        union {
                u8 reserved_dmem[0x200];
index f63692a..d531121 100644 (file)
@@ -50,4 +50,55 @@ struct nvfw_ls_desc_v1 {
 
 const struct nvfw_ls_desc_v1 *
 nvfw_ls_desc_v1(struct nvkm_subdev *, const void *);
+
+struct nvfw_ls_desc_v2 {
+       u32 descriptor_size;
+       u32 image_size;
+       u32 tools_version;
+       u32 app_version;
+       char date[64];
+       u32 secure_bootloader;
+       u32 bootloader_start_offset;
+       u32 bootloader_size;
+       u32 bootloader_imem_offset;
+       u32 bootloader_entry_point;
+       u32 app_start_offset;
+       u32 app_size;
+       u32 app_imem_offset;
+       u32 app_imem_entry;
+       u32 app_dmem_offset;
+       u32 app_resident_code_offset;
+       u32 app_resident_code_size;
+       u32 app_resident_data_offset;
+       u32 app_resident_data_size;
+       u32 nb_imem_overlays;
+       u32 nb_dmem_overlays;
+       struct {
+               u32 start;
+               u32 size;
+       } load_ovl[64];
+};
+
+const struct nvfw_ls_desc_v2 *nvfw_ls_desc_v2(struct nvkm_subdev *, const void *);
+
+struct nvfw_ls_hsbl_bin_hdr {
+       u32 bin_magic;
+       u32 bin_ver;
+       u32 bin_size;
+       u32 header_offset;
+};
+
+const struct nvfw_ls_hsbl_bin_hdr *nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *, const void *);
+
+struct nvfw_ls_hsbl_hdr {
+       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;
+};
+
+const struct nvfw_ls_hsbl_hdr *nvfw_ls_hsbl_hdr(struct nvkm_subdev *, const void *);
 #endif
index 07d7094..b3331d6 100644 (file)
@@ -34,6 +34,29 @@ struct nv_sec2_init_msg {
        u16 sw_managed_area_size;
 };
 
+struct nv_sec2_init_msg_v1 {
+       struct nvfw_falcon_msg hdr;
+#define NV_SEC2_INIT_MSG_INIT                                              0x00
+       u8 msg_type;
+
+       u8 num_queues;
+       u16 os_debug_entry_point;
+
+       struct {
+               u32 offset;
+               u16 size;
+               u8 index;
+#define NV_SEC2_INIT_MSG_QUEUE_ID_CMDQ                                     0x00
+#define NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ                                     0x01
+               u8 id;
+       } queue_info[2];
+
+       u32 sw_managed_area_offset;
+       u16 sw_managed_area_size;
+
+       u32 unkn[8];
+};
+
 struct nv_sec2_acr_cmd {
        struct nvfw_falcon_cmd hdr;
 #define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON                                   0x00
@@ -62,4 +85,21 @@ struct nv_sec2_acr_bootstrap_falcon_msg {
 #define NV_SEC2_UNIT_V2_INIT   0x01
 #define NV_SEC2_UNIT_V2_UNLOAD 0x05
 #define NV_SEC2_UNIT_V2_ACR    0x07
+
+struct nv_sec2_acr_bootstrap_falcon_cmd_v1 {
+       struct nv_sec2_acr_cmd cmd;
+#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES                 0x00000000
+#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO                  0x00000001
+       u32 flags;
+       u32 falcon_id;
+       u32 unkn08;
+       u32 unkn0c;
+};
+
+struct nv_sec2_acr_bootstrap_falcon_msg_v1 {
+       struct nv_sec2_acr_msg msg;
+       u32 error_code;
+       u32 falcon_id;
+       u32 unkn08;
+};
 #endif
index 45d70aa..b857cf1 100644 (file)
@@ -61,6 +61,7 @@ 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_select(struct nvkm_falcon *);
 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;
index dacbd92..cd86d91 100644 (file)
@@ -60,6 +60,7 @@ 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 *);
+       int (*select)(struct nvkm_falcon *);
        u32 addr2;
        bool reset_pmc;
        int (*reset_eng)(struct nvkm_falcon *);
index a41b864..8d48fb2 100644 (file)
@@ -23,4 +23,5 @@ struct nvkm_sec2 {
 int gp102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
 int gp108_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
 int tu102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
+int ga102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
 #endif
index 12c0b83..4c1f81e 100644 (file)
@@ -67,6 +67,7 @@ int gp108_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
 int gp10b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
 int gv100_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
 int tu102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
+int ga102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
 
 struct nvkm_acr_lsfw {
        const struct nvkm_acr_lsf_func *func;
@@ -79,6 +80,7 @@ struct nvkm_acr_lsfw {
 
        const struct firmware *sig;
 
+       bool secure_bootloader;
        u32 bootloader_size;
        u32 bootloader_imem_offset;
 
@@ -89,10 +91,19 @@ struct nvkm_acr_lsfw {
        u32 app_resident_code_size;
        u32 app_resident_data_offset;
        u32 app_resident_data_size;
+       u32 app_imem_offset;
+       u32 app_dmem_offset;
 
        u32 ucode_size;
        u32 data_size;
 
+       u32 fuse_ver;
+       u32 engine_id;
+       u32 ucode_id;
+       u32 sig_size;
+       u32 sig_nr;
+       u8 *sigs;
+
        struct {
                u32 lsb;
                u32 img;
@@ -123,6 +134,12 @@ int
 nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *, struct nvkm_falcon *,
                                     enum nvkm_acr_lsf_id, const char *path,
                                     int ver, const struct nvkm_acr_lsf_func *);
+
+int
+nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *, struct nvkm_falcon *,
+                                    enum nvkm_acr_lsf_id, const char *path,
+                                    int ver, const struct nvkm_acr_lsf_func *);
+
 int
 nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *, struct nvkm_falcon *,
                                    enum nvkm_acr_lsf_id, const char *path,
index ccf886e..72619d7 100644 (file)
@@ -12,4 +12,5 @@ struct nvkm_gsp {
 };
 
 int gv100_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **);
+int ga102_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **);
 #endif
index 8162efc..666300d 100644 (file)
@@ -2596,12 +2596,14 @@ nv170_chipset = {
 static const struct nvkm_device_chip
 nv172_chipset = {
        .name = "GA102",
+       .acr      = { 0x00000001, ga102_acr_new },
        .bar      = { 0x00000001, tu102_bar_new },
        .bios     = { 0x00000001, nvkm_bios_new },
        .devinit  = { 0x00000001, ga100_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
        .fb       = { 0x00000001, ga102_fb_new },
        .gpio     = { 0x00000001, ga102_gpio_new },
+       .gsp      = { 0x00000001, ga102_gsp_new },
        .i2c      = { 0x00000001, gm200_i2c_new },
        .imem     = { 0x00000001, nv50_instmem_new },
        .mc       = { 0x00000001, ga100_mc_new },
@@ -2616,17 +2618,20 @@ nv172_chipset = {
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
        .nvdec    = { 0x00000001, ga102_nvdec_new },
+       .sec2     = { 0x00000001, ga102_sec2_new },
 };
 
 static const struct nvkm_device_chip
 nv173_chipset = {
        .name = "GA103",
+       .acr      = { 0x00000001, ga102_acr_new },
        .bar      = { 0x00000001, tu102_bar_new },
        .bios     = { 0x00000001, nvkm_bios_new },
        .devinit  = { 0x00000001, ga100_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
        .fb       = { 0x00000001, ga102_fb_new },
        .gpio     = { 0x00000001, ga102_gpio_new },
+       .gsp      = { 0x00000001, ga102_gsp_new },
        .i2c      = { 0x00000001, gm200_i2c_new },
        .imem     = { 0x00000001, nv50_instmem_new },
        .mc       = { 0x00000001, ga100_mc_new },
@@ -2641,17 +2646,20 @@ nv173_chipset = {
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
        .nvdec    = { 0x00000001, ga102_nvdec_new },
+       .sec2     = { 0x00000001, ga102_sec2_new },
 };
 
 static const struct nvkm_device_chip
 nv174_chipset = {
        .name = "GA104",
+       .acr      = { 0x00000001, ga102_acr_new },
        .bar      = { 0x00000001, tu102_bar_new },
        .bios     = { 0x00000001, nvkm_bios_new },
        .devinit  = { 0x00000001, ga100_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
        .fb       = { 0x00000001, ga102_fb_new },
        .gpio     = { 0x00000001, ga102_gpio_new },
+       .gsp      = { 0x00000001, ga102_gsp_new },
        .i2c      = { 0x00000001, gm200_i2c_new },
        .imem     = { 0x00000001, nv50_instmem_new },
        .mc       = { 0x00000001, ga100_mc_new },
@@ -2666,17 +2674,20 @@ nv174_chipset = {
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
        .nvdec    = { 0x00000001, ga102_nvdec_new },
+       .sec2     = { 0x00000001, ga102_sec2_new },
 };
 
 static const struct nvkm_device_chip
 nv176_chipset = {
        .name = "GA106",
+       .acr      = { 0x00000001, ga102_acr_new },
        .bar      = { 0x00000001, tu102_bar_new },
        .bios     = { 0x00000001, nvkm_bios_new },
        .devinit  = { 0x00000001, ga100_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
        .fb       = { 0x00000001, ga102_fb_new },
        .gpio     = { 0x00000001, ga102_gpio_new },
+       .gsp      = { 0x00000001, ga102_gsp_new },
        .i2c      = { 0x00000001, gm200_i2c_new },
        .imem     = { 0x00000001, nv50_instmem_new },
        .mc       = { 0x00000001, ga100_mc_new },
@@ -2691,17 +2702,20 @@ nv176_chipset = {
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
        .nvdec    = { 0x00000001, ga102_nvdec_new },
+       .sec2     = { 0x00000001, ga102_sec2_new },
 };
 
 static const struct nvkm_device_chip
 nv177_chipset = {
        .name = "GA107",
+       .acr      = { 0x00000001, ga102_acr_new },
        .bar      = { 0x00000001, tu102_bar_new },
        .bios     = { 0x00000001, nvkm_bios_new },
        .devinit  = { 0x00000001, ga100_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
        .fb       = { 0x00000001, ga102_fb_new },
        .gpio     = { 0x00000001, ga102_gpio_new },
+       .gsp      = { 0x00000001, ga102_gsp_new },
        .i2c      = { 0x00000001, gm200_i2c_new },
        .imem     = { 0x00000001, nv50_instmem_new },
        .mc       = { 0x00000001, ga100_mc_new },
@@ -2716,6 +2730,7 @@ nv177_chipset = {
        .dma      = { 0x00000001, gv100_dma_new },
        .fifo     = { 0x00000001, ga102_fifo_new },
        .nvdec    = { 0x00000001, ga102_nvdec_new },
+       .sec2     = { 0x00000001, ga102_sec2_new },
 };
 
 struct nvkm_subdev *
index 63cd2be..19feadb 100644 (file)
@@ -3,3 +3,4 @@ nvkm-y += nvkm/engine/sec2/base.o
 nvkm-y += nvkm/engine/sec2/gp102.o
 nvkm-y += nvkm/engine/sec2/gp108.o
 nvkm-y += nvkm/engine/sec2/tu102.o
+nvkm-y += nvkm/engine/sec2/ga102.o
index b1e5f54..f2c60da 100644 (file)
@@ -100,6 +100,12 @@ nvkm_sec2_oneinit(struct nvkm_engine *engine)
        struct nvkm_intr *intr = &sec2->engine.subdev.device->mc->intr;
        enum nvkm_intr_type type = NVKM_INTR_SUBDEV;
 
+       if (sec2->func->intr_vector) {
+               intr = sec2->func->intr_vector(sec2, &type);
+               if (IS_ERR(intr))
+                       return PTR_ERR(intr);
+       }
+
        return nvkm_inth_add(intr, type, NVKM_INTR_PRIO_NORMAL, subdev, sec2->func->intr,
                             &subdev->inth);
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c
new file mode 100644 (file)
index 0000000..945abb8
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * 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/acr.h>
+#include <subdev/vfn.h>
+
+#include <nvfw/flcn.h>
+#include <nvfw/sec2.h>
+
+static int
+ga102_sec2_initmsg(struct nvkm_sec2 *sec2)
+{
+       struct nv_sec2_init_msg_v1 msg;
+       int ret, i;
+
+       ret = nvkm_falcon_msgq_recv_initmsg(sec2->msgq, &msg, sizeof(msg));
+       if (ret)
+               return ret;
+
+       if (msg.hdr.unit_id != NV_SEC2_UNIT_INIT ||
+           msg.msg_type != NV_SEC2_INIT_MSG_INIT)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(msg.queue_info); i++) {
+               if (msg.queue_info[i].id == NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ) {
+                       nvkm_falcon_msgq_init(sec2->msgq, msg.queue_info[i].index,
+                                                         msg.queue_info[i].offset,
+                                                         msg.queue_info[i].size);
+               } else {
+                       nvkm_falcon_cmdq_init(sec2->cmdq, msg.queue_info[i].index,
+                                                         msg.queue_info[i].offset,
+                                                         msg.queue_info[i].size);
+               }
+       }
+
+       return 0;
+}
+
+static struct nvkm_intr *
+ga102_sec2_intr_vector(struct nvkm_sec2 *sec2, enum nvkm_intr_type *pvector)
+{
+       struct nvkm_device *device = sec2->engine.subdev.device;
+       struct nvkm_falcon *falcon = &sec2->falcon;
+       int ret;
+
+       ret = ga102_flcn_select(falcon);
+       if (ret)
+               return ERR_PTR(ret);
+
+       *pvector = nvkm_rd32(device, 0x8403e0) & 0x000000ff;
+       return &device->vfn->intr;
+}
+
+static int
+ga102_sec2_acr_bootstrap_falcon_callback(void *priv, struct nvfw_falcon_msg *hdr)
+{
+       struct nv_sec2_acr_bootstrap_falcon_msg_v1 *msg =
+               container_of(hdr, typeof(*msg), msg.hdr);
+       struct nvkm_subdev *subdev = priv;
+       const char *name = nvkm_acr_lsf_id(msg->falcon_id);
+
+       if (msg->error_code) {
+               nvkm_error(subdev, "ACR_BOOTSTRAP_FALCON failed for falcon %d [%s]: %08x %08x\n",
+                          msg->falcon_id, name, msg->error_code, msg->unkn08);
+               return -EINVAL;
+       }
+
+       nvkm_debug(subdev, "%s booted\n", name);
+       return 0;
+}
+
+static int
+ga102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon, enum nvkm_acr_lsf_id id)
+{
+       struct nvkm_sec2 *sec2 = container_of(falcon, typeof(*sec2), falcon);
+       struct nv_sec2_acr_bootstrap_falcon_cmd_v1 cmd = {
+               .cmd.hdr.unit_id = sec2->func->unit_acr,
+               .cmd.hdr.size = sizeof(cmd),
+               .cmd.cmd_type = NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON,
+               .flags = NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES,
+               .falcon_id = id,
+       };
+
+       return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.cmd.hdr,
+                                    ga102_sec2_acr_bootstrap_falcon_callback,
+                                    &sec2->engine.subdev,
+                                    msecs_to_jiffies(1000));
+}
+
+static const struct nvkm_acr_lsf_func
+ga102_sec2_acr_0 = {
+       .bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
+       .bld_write = gp102_sec2_acr_bld_write_1,
+       .bld_patch = gp102_sec2_acr_bld_patch_1,
+       .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
+                            BIT_ULL(NVKM_ACR_LSF_GPCCS) |
+                            BIT_ULL(NVKM_ACR_LSF_SEC2),
+       .bootstrap_falcon = ga102_sec2_acr_bootstrap_falcon,
+};
+
+static const struct nvkm_falcon_func
+ga102_sec2_flcn = {
+       .disable = gm200_flcn_disable,
+       .enable = gm200_flcn_enable,
+       .select = ga102_flcn_select,
+       .addr2 = 0x1000,
+       .reset_pmc = true,
+       .reset_eng = gp102_flcn_reset_eng,
+       .reset_prep = ga102_flcn_reset_prep,
+       .reset_wait_mem_scrubbing = ga102_flcn_reset_wait_mem_scrubbing,
+       .imem_dma = &ga102_flcn_dma,
+       .dmem_pio = &gm200_flcn_dmem_pio,
+       .dmem_dma = &ga102_flcn_dma,
+       .emem_addr = 0x01000000,
+       .emem_pio = &gp102_flcn_emem_pio,
+       .start = nvkm_falcon_v1_start,
+       .cmdq = { 0xc00, 0xc04, 8 },
+       .msgq = { 0xc80, 0xc84, 8 },
+};
+
+static const struct nvkm_sec2_func
+ga102_sec2 = {
+       .flcn = &ga102_sec2_flcn,
+       .intr_vector = ga102_sec2_intr_vector,
+       .intr = gp102_sec2_intr,
+       .initmsg = ga102_sec2_initmsg,
+       .unit_acr = NV_SEC2_UNIT_V2_ACR,
+       .unit_unload = NV_SEC2_UNIT_V2_UNLOAD,
+};
+
+MODULE_FIRMWARE("nvidia/ga102/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga102/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga102/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga102/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga103/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga103/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga103/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga103/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga104/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga104/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga104/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga104/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga106/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga106/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga106/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga106/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga107/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga107/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga107/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga107/sec2/hs_bl_sig.bin");
+
+static int
+ga102_sec2_load(struct nvkm_sec2 *sec2, int ver,
+               const struct nvkm_sec2_fwif *fwif)
+{
+       return nvkm_acr_lsfw_load_sig_image_desc_v2(&sec2->engine.subdev, &sec2->falcon,
+                                                   NVKM_ACR_LSF_SEC2, "sec2/", ver, fwif->acr);
+}
+
+static const struct nvkm_sec2_fwif
+ga102_sec2_fwif[] = {
+       {  0, ga102_sec2_load, &ga102_sec2, &ga102_sec2_acr_0 },
+       { -1, gp102_sec2_nofw, &ga102_sec2 }
+};
+
+int
+ga102_sec2_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+              struct nvkm_sec2 **psec2)
+{
+       /* TOP info wasn't updated on Turing to reflect the PRI
+        * address change for some reason.  We override it here.
+        */
+       return nvkm_sec2_new_(ga102_sec2_fwif, device, type, inst, 0x840000, psec2);
+}
index b1e74bc..c64013d 100644 (file)
@@ -237,7 +237,7 @@ MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin");
 MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin");
 MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin");
 
-static void
+void
 gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust)
 {
        struct flcn_bl_dmem_desc_v2 hdr;
@@ -248,7 +248,7 @@ gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust)
        flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hdr);
 }
 
-static void
+void
 gp102_sec2_acr_bld_write_1(struct nvkm_acr *acr, u32 bld,
                           struct nvkm_acr_lsfw *lsfw)
 {
index 4997b89..172d270 100644 (file)
@@ -2,11 +2,13 @@
 #ifndef __NVKM_SEC2_PRIV_H__
 #define __NVKM_SEC2_PRIV_H__
 #include <engine/sec2.h>
+struct nvkm_acr_lsfw;
 
 struct nvkm_sec2_func {
        const struct nvkm_falcon_func *flcn;
        u8 unit_unload;
        u8 unit_acr;
+       struct nvkm_intr *(*intr_vector)(struct nvkm_sec2 *, enum nvkm_intr_type *);
        irqreturn_t (*intr)(struct nvkm_inth *);
        int (*initmsg)(struct nvkm_sec2 *);
 };
@@ -25,6 +27,8 @@ int gp102_sec2_nofw(struct nvkm_sec2 *, int, const struct nvkm_sec2_fwif *);
 int gp102_sec2_load(struct nvkm_sec2 *, int, const struct nvkm_sec2_fwif *);
 extern const struct nvkm_sec2_func gp102_sec2;
 extern const struct nvkm_acr_lsf_func gp102_sec2_acr_1;
+void gp102_sec2_acr_bld_write_1(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *);
+void gp102_sec2_acr_bld_patch_1(struct nvkm_acr *, u32, s64);
 
 int nvkm_sec2_new_(const struct nvkm_sec2_fwif *, struct nvkm_device *, enum nvkm_subdev_type,
                   int, u32 addr, struct nvkm_sec2 **);
index 38306f9..0ff450f 100644 (file)
@@ -77,14 +77,28 @@ ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon)
 int
 ga102_flcn_reset_prep(struct nvkm_falcon *falcon)
 {
-       const u32 addr2 = (falcon->owner->type != NVKM_ENGINE_NVDEC) ? 0x530 : 0x930;
+       nvkm_falcon_rd32(falcon, 0x0f4);
 
-       if (nvkm_msec(falcon->owner->device, 10,
-               if ((nvkm_falcon_rd32(falcon, falcon->addr2 + 0x1ec) & 0x00000003) == 0x00000001 &&
-                   (nvkm_falcon_rd32(falcon,                 addr2) & 0x00000008) == 0x00000008)
+       nvkm_usec(falcon->owner->device, 150,
+               if (nvkm_falcon_rd32(falcon, 0x0f4) & 0x80000000)
                        break;
-       ) < 0)
-               return -ETIMEDOUT;
+               _warn = false;
+       );
+
+       return 0;
+}
+
+int
+ga102_flcn_select(struct nvkm_falcon *falcon)
+{
+       if ((nvkm_falcon_rd32(falcon, falcon->addr2 + 0x668) & 0x00000010) != 0x00000000) {
+               nvkm_falcon_wr32(falcon, falcon->addr2 + 0x668, 0x00000000);
+               if (nvkm_msec(falcon->owner->device, 10,
+                       if (nvkm_falcon_rd32(falcon, falcon->addr2 + 0x668) & 0x00000001)
+                               break;
+               ) < 0)
+                       return -ETIMEDOUT;
+       }
 
        return 0;
 }
index 6990890..393ade9 100644 (file)
@@ -151,6 +151,12 @@ gm200_flcn_enable(struct nvkm_falcon *falcon)
                        return ret;
        }
 
+       if (falcon->func->select) {
+               ret = falcon->func->select(falcon);
+               if (ret)
+                       return ret;
+       }
+
        if (falcon->func->reset_pmc)
                nvkm_mc_enable(device, falcon->owner->type, falcon->owner->inst);
 
@@ -168,6 +174,12 @@ gm200_flcn_disable(struct nvkm_falcon *falcon)
        struct nvkm_device *device = falcon->owner->device;
        int ret;
 
+       if (falcon->func->select) {
+               ret = falcon->func->select(falcon);
+               if (ret)
+                       return ret;
+       }
+
        nvkm_falcon_mask(falcon, 0x048, 0x00000003, 0x00000000);
        nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
 
index bef790a..83a9c48 100644 (file)
@@ -45,6 +45,47 @@ wpr_header_v1_dump(struct nvkm_subdev *subdev, const struct wpr_header_v1 *hdr)
        nvkm_debug(subdev, "\tstatus        : %d\n", hdr->status);
 }
 
+void
+wpr_generic_header_dump(struct nvkm_subdev *subdev, const struct wpr_generic_header *hdr)
+{
+       nvkm_debug(subdev, "wprGenericHeader\n");
+       nvkm_debug(subdev, "\tidentifier : %04x\n", hdr->identifier);
+       nvkm_debug(subdev, "\tversion    : %04x\n", hdr->version);
+       nvkm_debug(subdev, "\tsize       : %08x\n", hdr->size);
+}
+
+void
+wpr_header_v2_dump(struct nvkm_subdev *subdev, const struct wpr_header_v2 *hdr)
+{
+       wpr_generic_header_dump(subdev, &hdr->hdr);
+       wpr_header_v1_dump(subdev, &hdr->wpr);
+}
+
+void
+lsb_header_v2_dump(struct nvkm_subdev *subdev, struct lsb_header_v2 *hdr)
+{
+       wpr_generic_header_dump(subdev, &hdr->hdr);
+       nvkm_debug(subdev, "lsbHeader\n");
+       nvkm_debug(subdev, "\tucodeOff      : 0x%x\n", hdr->ucode_off);
+       nvkm_debug(subdev, "\tucodeSize     : 0x%x\n", hdr->ucode_size);
+       nvkm_debug(subdev, "\tdataSize      : 0x%x\n", hdr->data_size);
+       nvkm_debug(subdev, "\tblCodeSize    : 0x%x\n", hdr->bl_code_size);
+       nvkm_debug(subdev, "\tblImemOff     : 0x%x\n", hdr->bl_imem_off);
+       nvkm_debug(subdev, "\tblDataOff     : 0x%x\n", hdr->bl_data_off);
+       nvkm_debug(subdev, "\tblDataSize    : 0x%x\n", hdr->bl_data_size);
+       nvkm_debug(subdev, "\treserved0     : %08x\n", hdr->rsvd0);
+       nvkm_debug(subdev, "\tappCodeOff    : 0x%x\n", hdr->app_code_off);
+       nvkm_debug(subdev, "\tappCodeSize   : 0x%x\n", hdr->app_code_size);
+       nvkm_debug(subdev, "\tappDataOff    : 0x%x\n", hdr->app_data_off);
+       nvkm_debug(subdev, "\tappDataSize   : 0x%x\n", hdr->app_data_size);
+       nvkm_debug(subdev, "\tappImemOffset : 0x%x\n", hdr->app_imem_offset);
+       nvkm_debug(subdev, "\tappDmemOffset : 0x%x\n", hdr->app_dmem_offset);
+       nvkm_debug(subdev, "\tflags         : 0x%x\n", hdr->flags);
+       nvkm_debug(subdev, "\tmonitorCodeOff: 0x%x\n", hdr->monitor_code_offset);
+       nvkm_debug(subdev, "\tmonitorDataOff: 0x%x\n", hdr->monitor_data_offset);
+       nvkm_debug(subdev, "\tmanifestOffset: 0x%x\n", hdr->manifest_offset);
+}
+
 static void
 lsb_header_tail_dump(struct nvkm_subdev *subdev, struct lsb_header_tail *hdr)
 {
index b847f28..45c3a6c 100644 (file)
@@ -106,3 +106,75 @@ nvfw_ls_desc_v1(struct nvkm_subdev *subdev, const void *data)
 
        return hdr;
 }
+
+const struct nvfw_ls_desc_v2 *
+nvfw_ls_desc_v2(struct nvkm_subdev *subdev, const void *data)
+{
+       const struct nvfw_ls_desc_v2 *hdr = data;
+       char *date;
+       int i;
+
+       nvkm_debug(subdev, "lsUcodeImgDesc:\n");
+       nvkm_debug(subdev, "\tdescriptorSize       : %d\n", hdr->descriptor_size);
+       nvkm_debug(subdev, "\timageSize            : %d\n", hdr->image_size);
+       nvkm_debug(subdev, "\ttoolsVersion         : 0x%x\n", hdr->tools_version);
+       nvkm_debug(subdev, "\tappVersion           : 0x%x\n", hdr->app_version);
+
+       date = kstrndup(hdr->date, sizeof(hdr->date), GFP_KERNEL);
+       nvkm_debug(subdev, "\tdate                 : %s\n", date);
+       kfree(date);
+
+       nvkm_debug(subdev, "\tsecureBootloader     : 0x%x\n", hdr->secure_bootloader);
+       nvkm_debug(subdev, "\tbootloaderStartOffset: 0x%x\n", hdr->bootloader_start_offset);
+       nvkm_debug(subdev, "\tbootloaderSize       : 0x%x\n", hdr->bootloader_size);
+       nvkm_debug(subdev, "\tbootloaderImemOffset : 0x%x\n", hdr->bootloader_imem_offset);
+       nvkm_debug(subdev, "\tbootloaderEntryPoint : 0x%x\n", hdr->bootloader_entry_point);
+
+       nvkm_debug(subdev, "\tappStartOffset       : 0x%x\n", hdr->app_start_offset);
+       nvkm_debug(subdev, "\tappSize              : 0x%x\n", hdr->app_size);
+       nvkm_debug(subdev, "\tappImemOffset        : 0x%x\n", hdr->app_imem_offset);
+       nvkm_debug(subdev, "\tappImemEntry         : 0x%x\n", hdr->app_imem_entry);
+       nvkm_debug(subdev, "\tappDmemOffset        : 0x%x\n", hdr->app_dmem_offset);
+       nvkm_debug(subdev, "\tappResidentCodeOffset: 0x%x\n", hdr->app_resident_code_offset);
+       nvkm_debug(subdev, "\tappResidentCodeSize  : 0x%x\n", hdr->app_resident_code_size);
+       nvkm_debug(subdev, "\tappResidentDataOffset: 0x%x\n", hdr->app_resident_data_offset);
+       nvkm_debug(subdev, "\tappResidentDataSize  : 0x%x\n", hdr->app_resident_data_size);
+
+       nvkm_debug(subdev, "\tnbImemOverlays       : %d\n", hdr->nb_imem_overlays);
+       nvkm_debug(subdev, "\tnbDmemOverlays       : %d\n", hdr->nb_dmem_overlays);
+       for (i = 0; i < ARRAY_SIZE(hdr->load_ovl); i++) {
+               nvkm_debug(subdev, "\tloadOvl[%d]          : 0x%x %d\n", i,
+                          hdr->load_ovl[i].start, hdr->load_ovl[i].size);
+       }
+
+       return hdr;
+}
+
+const struct nvfw_ls_hsbl_bin_hdr *
+nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *subdev, const void *data)
+{
+       const struct nvfw_ls_hsbl_bin_hdr *hdr = data;
+
+       nvkm_debug(subdev, "lsHsblBinHdr:\n");
+       nvkm_debug(subdev, "\tbinMagic         : 0x%08x\n", hdr->bin_magic);
+       nvkm_debug(subdev, "\tbinVer           : %d\n", hdr->bin_ver);
+       nvkm_debug(subdev, "\tbinSize          : %d\n", hdr->bin_size);
+       nvkm_debug(subdev, "\theaderOffset     : 0x%x\n", hdr->header_offset);
+       return hdr;
+}
+
+const struct nvfw_ls_hsbl_hdr *
+nvfw_ls_hsbl_hdr(struct nvkm_subdev *subdev, const void *data)
+{
+       const struct nvfw_ls_hsbl_hdr *hdr = data;
+
+       nvkm_debug(subdev, "lsHsblHdr:\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);
+       return hdr;
+}
index ce6ece7..5731f35 100644 (file)
@@ -8,3 +8,5 @@ nvkm-y += nvkm/subdev/acr/gp108.o
 nvkm-y += nvkm/subdev/acr/gv100.o
 nvkm-y += nvkm/subdev/acr/gp10b.o
 nvkm-y += nvkm/subdev/acr/tu102.o
+nvkm-y += nvkm/subdev/acr/ga100.o
+nvkm-y += nvkm/subdev/acr/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c
new file mode 100644 (file)
index 0000000..e3370c1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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"
+
+void
+ga100_acr_wpr_check(struct nvkm_acr *acr, u64 *start, u64 *limit)
+{
+       struct nvkm_device *device = acr->subdev.device;
+
+       *start = (u64)(nvkm_rd32(device, 0x1fa81c) & 0xffffff00) << 8;
+       *limit = (u64)(nvkm_rd32(device, 0x1fa820) & 0xffffff00) << 8;
+       *limit = *limit + 0x20000;
+}
+
+int
+ga100_acr_hsfw_ctor(struct nvkm_acr *acr, const char *bl, const char *fw,
+                   const char *name, int ver, const struct nvkm_acr_hsf_fwif *fwif)
+{
+       struct nvkm_acr_hsfw *hsfw;
+
+       if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL)))
+               return -ENOMEM;
+
+       hsfw->falcon_id = fwif->falcon_id;
+       hsfw->boot_mbox0 = fwif->boot_mbox0;
+       hsfw->intr_clear = fwif->intr_clear;
+       list_add_tail(&hsfw->head, &acr->hsfw);
+
+       return nvkm_falcon_fw_ctor_hs_v2(fwif->func, name, &acr->subdev, fw, ver, NULL, &hsfw->fw);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c
new file mode 100644 (file)
index 0000000..45dcf49
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * 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 <nvfw/acr.h>
+
+static int
+ga102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
+{
+       struct wpr_header_v2 hdr;
+       struct lsb_header_v2 *lsb;
+       struct nvkm_acr_lsfw *lsfw;
+       u32 offset = 0;
+
+       lsb = kvmalloc(sizeof(*lsb), GFP_KERNEL);
+       if (!lsb)
+               return -ENOMEM;
+
+       do {
+               nvkm_robj(acr->wpr, offset, &hdr, sizeof(hdr));
+               wpr_header_v2_dump(&acr->subdev, &hdr);
+
+               list_for_each_entry(lsfw, &acr->lsfw, head) {
+                       if (lsfw->id != hdr.wpr.falcon_id)
+                               continue;
+
+                       nvkm_robj(acr->wpr, hdr.wpr.lsb_offset, lsb, sizeof(*lsb));
+                       lsb_header_v2_dump(&acr->subdev, lsb);
+
+                       lsfw->func->bld_patch(acr, lsb->bl_data_off, adjust);
+                       break;
+               }
+
+               offset += sizeof(hdr);
+       } while (hdr.wpr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID);
+
+       kvfree(lsb);
+       return 0;
+}
+
+static int
+ga102_acr_wpr_build_lsb(struct nvkm_acr *acr, struct nvkm_acr_lsfw *lsfw)
+{
+       struct lsb_header_v2 *hdr;
+       int ret = 0;
+
+       if (WARN_ON(lsfw->sig->size != sizeof(hdr->signature)))
+               return -EINVAL;
+
+       hdr = kvzalloc(sizeof(*hdr), GFP_KERNEL);
+       if (!hdr)
+               return -ENOMEM;
+
+       hdr->hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER;
+       hdr->hdr.version = 2;
+       hdr->hdr.size = sizeof(*hdr);
+
+       memcpy(&hdr->signature, lsfw->sig->data, lsfw->sig->size);
+       hdr->ucode_off = lsfw->offset.img;
+       hdr->ucode_size = lsfw->ucode_size;
+       hdr->data_size = lsfw->data_size;
+       hdr->bl_code_size = lsfw->bootloader_size;
+       hdr->bl_imem_off = lsfw->bootloader_imem_offset;
+       hdr->bl_data_off = lsfw->offset.bld;
+       hdr->bl_data_size = lsfw->bl_data_size;
+       hdr->app_code_off = lsfw->app_start_offset + lsfw->app_resident_code_offset;
+       hdr->app_code_size = ALIGN(lsfw->app_resident_code_size, 0x100);
+       hdr->app_data_off = lsfw->app_start_offset + lsfw->app_resident_data_offset;
+       hdr->app_data_size = ALIGN(lsfw->app_resident_data_size, 0x100);
+       hdr->app_imem_offset = lsfw->app_imem_offset;
+       hdr->app_dmem_offset = lsfw->app_dmem_offset;
+       hdr->flags = lsfw->func->flags;
+       hdr->monitor_code_offset = 0;
+       hdr->monitor_data_offset = 0;
+       hdr->manifest_offset = 0;
+
+       if (lsfw->secure_bootloader) {
+               struct nvkm_falcon_fw fw = {
+                       .fw.img = hdr->hs_fmc_params.pkc_signature,
+                       .fw.name = "LSFW",
+                       .func = &(const struct nvkm_falcon_fw_func) {
+                               .signature = ga100_flcn_fw_signature,
+                       },
+                       .sig_size = lsfw->sig_size,
+                       .sig_nr = lsfw->sig_nr,
+                       .sigs = lsfw->sigs,
+                       .fuse_ver = lsfw->fuse_ver,
+                       .engine_id = lsfw->engine_id,
+                       .ucode_id = lsfw->ucode_id,
+                       .falcon = lsfw->falcon,
+
+               };
+
+               ret = nvkm_falcon_get(fw.falcon, &acr->subdev);
+               if (ret == 0) {
+                       hdr->hs_fmc_params.hs_fmc = 1;
+                       hdr->hs_fmc_params.pkc_algo = 0;
+                       hdr->hs_fmc_params.pkc_algo_version = 1;
+                       hdr->hs_fmc_params.engid_mask = lsfw->engine_id;
+                       hdr->hs_fmc_params.ucode_id = lsfw->ucode_id;
+                       hdr->hs_fmc_params.fuse_ver = lsfw->fuse_ver;
+                       ret = nvkm_falcon_fw_patch(&fw);
+                       nvkm_falcon_put(fw.falcon, &acr->subdev);
+               }
+       }
+
+       nvkm_wobj(acr->wpr, lsfw->offset.lsb, hdr, sizeof(*hdr));
+       kvfree(hdr);
+       return ret;
+}
+
+static int
+ga102_acr_wpr_build(struct nvkm_acr *acr, struct nvkm_acr_lsf *rtos)
+{
+       struct nvkm_acr_lsfw *lsfw;
+       struct wpr_header_v2 hdr;
+       u32 offset = 0;
+       int ret;
+
+       /*XXX: shared sub-WPR headers, fill terminator for now. */
+       nvkm_wo32(acr->wpr, 0x300, (2 << 16) | WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR);
+       nvkm_wo32(acr->wpr, 0x304, 0x14);
+       nvkm_wo32(acr->wpr, 0x308, 0xffffffff);
+       nvkm_wo32(acr->wpr, 0x30c, 0);
+       nvkm_wo32(acr->wpr, 0x310, 0);
+
+       /* Fill per-LSF structures. */
+       list_for_each_entry(lsfw, &acr->lsfw, head) {
+               struct lsf_signature_v2 *sig = (void *)lsfw->sig->data;
+
+               hdr.hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER;
+               hdr.hdr.version = 2;
+               hdr.hdr.size = sizeof(hdr);
+               hdr.wpr.falcon_id = lsfw->id;
+               hdr.wpr.lsb_offset = lsfw->offset.lsb;
+               hdr.wpr.bootstrap_owner = NVKM_ACR_LSF_GSPLITE;
+               hdr.wpr.lazy_bootstrap = 1;
+               hdr.wpr.bin_version = sig->ls_ucode_version;
+               hdr.wpr.status = WPR_HEADER_V1_STATUS_COPY;
+
+               /* Write WPR header. */
+               nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr));
+               offset += sizeof(hdr);
+
+               /* Write LSB header. */
+               ret = ga102_acr_wpr_build_lsb(acr, lsfw);
+               if (ret)
+                       return ret;
+
+               /* Write ucode image. */
+               nvkm_wobj(acr->wpr, lsfw->offset.img,
+                                   lsfw->img.data,
+                                   lsfw->img.size);
+
+               /* Write bootloader data. */
+               lsfw->func->bld_write(acr, lsfw->offset.bld, lsfw);
+       }
+
+       /* Finalise WPR. */
+       hdr.hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER;
+       hdr.hdr.version = 2;
+       hdr.hdr.size = sizeof(hdr);
+       hdr.wpr.falcon_id = WPR_HEADER_V1_FALCON_ID_INVALID;
+       nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr));
+       return 0;
+}
+
+static u32
+ga102_acr_wpr_layout(struct nvkm_acr *acr)
+{
+       struct nvkm_acr_lsfw *lsfw;
+       u32 wpr = 0;
+
+       wpr += 21 /* MAX_LSF */ * sizeof(struct wpr_header_v2);
+       wpr  = ALIGN(wpr, 256);
+
+       wpr += 0x100; /* Shared sub-WPR headers. */
+
+       list_for_each_entry(lsfw, &acr->lsfw, head) {
+               wpr  = ALIGN(wpr, 256);
+               lsfw->offset.lsb = wpr;
+               wpr += sizeof(struct lsb_header_v2);
+
+               wpr  = ALIGN(wpr, 4096);
+               lsfw->offset.img = wpr;
+               wpr += lsfw->img.size;
+
+               wpr  = ALIGN(wpr, 256);
+               lsfw->offset.bld = wpr;
+               lsfw->bl_data_size = ALIGN(lsfw->func->bld_size, 256);
+               wpr += lsfw->bl_data_size;
+       }
+
+       return wpr;
+}
+
+static int
+ga102_acr_wpr_parse(struct nvkm_acr *acr)
+{
+       const struct wpr_header_v2 *hdr = (void *)acr->wpr_fw->data;
+
+       while (hdr->wpr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID) {
+               wpr_header_v2_dump(&acr->subdev, hdr);
+               if (!nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->wpr.falcon_id))
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+MODULE_FIRMWARE("nvidia/ga102/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga103/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga104/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga106/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga107/acr/ucode_unload.bin");
+
+static const struct nvkm_acr_hsf_fwif
+ga102_acr_unload_fwif[] = {
+       {  0, ga100_acr_hsfw_ctor, &ga102_flcn_fw, NVKM_ACR_HSF_SEC2 },
+       {}
+};
+
+MODULE_FIRMWARE("nvidia/ga102/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga103/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga104/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga106/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga107/acr/ucode_asb.bin");
+
+static const struct nvkm_acr_hsf_fwif
+ga102_acr_asb_fwif[] = {
+       {  0, ga100_acr_hsfw_ctor, &ga102_flcn_fw, NVKM_ACR_HSF_GSP },
+       {}
+};
+
+static const struct nvkm_falcon_fw_func
+ga102_acr_ahesasc_0 = {
+       .signature = ga100_flcn_fw_signature,
+       .reset = gm200_flcn_fw_reset,
+       .setup = gp102_acr_load_setup,
+       .load = ga102_flcn_fw_load,
+       .boot = ga102_flcn_fw_boot,
+};
+
+MODULE_FIRMWARE("nvidia/ga102/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga103/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga104/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga106/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga107/acr/ucode_ahesasc.bin");
+
+static const struct nvkm_acr_hsf_fwif
+ga102_acr_ahesasc_fwif[] = {
+       {  0, ga100_acr_hsfw_ctor, &ga102_acr_ahesasc_0, NVKM_ACR_HSF_SEC2 },
+       {}
+};
+
+static const struct nvkm_acr_func
+ga102_acr = {
+       .ahesasc = ga102_acr_ahesasc_fwif,
+       .asb = ga102_acr_asb_fwif,
+       .unload = ga102_acr_unload_fwif,
+       .wpr_parse = ga102_acr_wpr_parse,
+       .wpr_layout = ga102_acr_wpr_layout,
+       .wpr_alloc = gp102_acr_wpr_alloc,
+       .wpr_patch = ga102_acr_wpr_patch,
+       .wpr_build = ga102_acr_wpr_build,
+       .wpr_check = ga100_acr_wpr_check,
+       .init = tu102_acr_init,
+};
+
+static int
+ga102_acr_load(struct nvkm_acr *acr, int version,
+              const struct nvkm_acr_fwif *fwif)
+{
+       struct nvkm_subdev *subdev = &acr->subdev;
+       const struct nvkm_acr_hsf_fwif *hsfwif;
+
+       hsfwif = nvkm_firmware_load(subdev, fwif->func->ahesasc, "AcrAHESASC",
+                                   acr, NULL, "acr/ucode_ahesasc", "AHESASC");
+       if (IS_ERR(hsfwif))
+               return PTR_ERR(hsfwif);
+
+       hsfwif = nvkm_firmware_load(subdev, fwif->func->asb, "AcrASB",
+                                   acr, NULL, "acr/ucode_asb", "ASB");
+       if (IS_ERR(hsfwif))
+               return PTR_ERR(hsfwif);
+
+       hsfwif = nvkm_firmware_load(subdev, fwif->func->unload, "AcrUnload",
+                                   acr, NULL, "acr/ucode_unload", "unload");
+       if (IS_ERR(hsfwif))
+               return PTR_ERR(hsfwif);
+
+       return 0;
+}
+
+static const struct nvkm_acr_fwif
+ga102_acr_fwif[] = {
+       {  0, ga102_acr_load, &ga102_acr },
+       { -1, gm200_acr_nofw, &gm200_acr },
+       {}
+};
+
+int
+ga102_acr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+             struct nvkm_acr **pacr)
+{
+       return nvkm_acr_new_(ga102_acr_fwif, device, type, inst, pacr);
+}
index 7a11151..31079c9 100644 (file)
@@ -61,7 +61,7 @@ gm200_acr_wpr_check(struct nvkm_acr *acr, u64 *start, u64 *limit)
        *limit = *limit + 0x20000;
 }
 
-void
+int
 gm200_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
 {
        struct nvkm_subdev *subdev = &acr->subdev;
@@ -86,6 +86,8 @@ gm200_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
                }
                offset += sizeof(hdr);
        } while (hdr.falcon_id != WPR_HEADER_V0_FALCON_ID_INVALID);
+
+       return 0;
 }
 
 void
index f4c2d37..084f284 100644 (file)
@@ -29,7 +29,7 @@
 #include <nvfw/acr.h>
 #include <nvfw/flcn.h>
 
-void
+int
 gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
 {
        struct wpr_header_v1 hdr;
@@ -54,6 +54,8 @@ gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
 
                offset += sizeof(hdr);
        } while (hdr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID);
+
+       return 0;
 }
 
 int
index 9b1cf67..69a059c 100644 (file)
@@ -29,6 +29,7 @@ void
 nvkm_acr_lsfw_del(struct nvkm_acr_lsfw *lsfw)
 {
        nvkm_blob_dtor(&lsfw->img);
+       kfree(lsfw->sigs);
        nvkm_firmware_put(lsfw->sig);
        list_del(&lsfw->head);
        kfree(lsfw);
@@ -177,6 +178,75 @@ nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *subdev,
 }
 
 int
+nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *subdev,
+                                    struct nvkm_falcon *falcon,
+                                    enum nvkm_acr_lsf_id id,
+                                    const char *path, int ver,
+                                    const struct nvkm_acr_lsf_func *func)
+{
+       const struct firmware *fw;
+       struct nvkm_acr_lsfw *lsfw;
+       const struct nvfw_ls_desc_v2 *desc;
+       int ret = 0;
+
+       lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver, func, &fw);
+       if (IS_ERR(lsfw))
+               return PTR_ERR(lsfw);
+
+       desc = nvfw_ls_desc_v2(subdev, fw->data);
+
+       lsfw->secure_bootloader = desc->secure_bootloader;
+       lsfw->bootloader_size = ALIGN(desc->bootloader_size, 256);
+       lsfw->bootloader_imem_offset = desc->bootloader_imem_offset;
+
+       lsfw->app_size = ALIGN(desc->app_size, 256);
+       lsfw->app_start_offset = desc->app_start_offset;
+       lsfw->app_imem_entry = desc->app_imem_entry;
+       lsfw->app_resident_code_offset = desc->app_resident_code_offset;
+       lsfw->app_resident_code_size = desc->app_resident_code_size;
+       lsfw->app_resident_data_offset = desc->app_resident_data_offset;
+       lsfw->app_resident_data_size = desc->app_resident_data_size;
+       lsfw->app_imem_offset = desc->app_imem_offset;
+       lsfw->app_dmem_offset = desc->app_dmem_offset;
+
+       lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + lsfw->bootloader_size;
+       lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - lsfw->ucode_size;
+
+       nvkm_firmware_put(fw);
+
+       if (lsfw->secure_bootloader) {
+               const struct firmware *hsbl;
+               const struct nvfw_ls_hsbl_bin_hdr *hdr;
+               const struct nvfw_ls_hsbl_hdr *hshdr;
+               u32 loc, sig, cnt, *meta;
+
+               ret = nvkm_firmware_load_name(subdev, path, "hs_bl_sig", ver, &hsbl);
+               if (ret)
+                       return ret;
+
+               hdr = nvfw_ls_hsbl_bin_hdr(subdev, hsbl->data);
+               hshdr = nvfw_ls_hsbl_hdr(subdev, hsbl->data + hdr->header_offset);
+               meta = (u32 *)(hsbl->data + hshdr->meta_data_offset);
+               loc = *(u32 *)(hsbl->data + hshdr->patch_loc);
+               sig = *(u32 *)(hsbl->data + hshdr->patch_sig);
+               cnt = *(u32 *)(hsbl->data + hshdr->num_sig);
+
+               lsfw->fuse_ver = meta[0];
+               lsfw->engine_id = meta[1];
+               lsfw->ucode_id = meta[2];
+               lsfw->sig_size = hshdr->sig_prod_size / cnt;
+               lsfw->sig_nr = cnt;
+               lsfw->sigs = kmemdup(hsbl->data + hshdr->sig_prod_offset + sig,
+                                    lsfw->sig_nr * lsfw->sig_size, GFP_KERNEL);
+               nvkm_firmware_put(hsbl);
+               if (!lsfw->sigs)
+                       ret = -ENOMEM;
+       }
+
+       return ret;
+}
+
+int
 nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *subdev,
                                    struct nvkm_falcon *falcon,
                                    enum nvkm_acr_lsf_id id,
index 66a764e..4881c8b 100644 (file)
@@ -24,7 +24,7 @@ struct nvkm_acr_func {
        u32 (*wpr_layout)(struct nvkm_acr *);
        int (*wpr_alloc)(struct nvkm_acr *, u32 wpr_size);
        int (*wpr_build)(struct nvkm_acr *, struct nvkm_acr_lsf *rtos);
-       void (*wpr_patch)(struct nvkm_acr *, s64 adjust);
+       int (*wpr_patch)(struct nvkm_acr *, s64 adjust);
        void (*wpr_check)(struct nvkm_acr *, u64 *start, u64 *limit);
        int (*init)(struct nvkm_acr *);
        void (*fini)(struct nvkm_acr *);
@@ -35,7 +35,7 @@ extern const struct nvkm_acr_func gm200_acr;
 int gm200_acr_wpr_parse(struct nvkm_acr *);
 u32 gm200_acr_wpr_layout(struct nvkm_acr *);
 int gm200_acr_wpr_build(struct nvkm_acr *, struct nvkm_acr_lsf *);
-void gm200_acr_wpr_patch(struct nvkm_acr *, s64);
+int gm200_acr_wpr_patch(struct nvkm_acr *, s64);
 void gm200_acr_wpr_check(struct nvkm_acr *, u64 *, u64 *);
 void gm200_acr_wpr_build_lsb_tail(struct nvkm_acr_lsfw *,
                                  struct lsb_header_tail *);
@@ -48,7 +48,11 @@ u32 gp102_acr_wpr_layout(struct nvkm_acr *);
 int gp102_acr_wpr_alloc(struct nvkm_acr *, u32 wpr_size);
 int gp102_acr_wpr_build(struct nvkm_acr *, struct nvkm_acr_lsf *);
 int gp102_acr_wpr_build_lsb(struct nvkm_acr *, struct nvkm_acr_lsfw *);
-void gp102_acr_wpr_patch(struct nvkm_acr *, s64);
+int gp102_acr_wpr_patch(struct nvkm_acr *, s64);
+
+int tu102_acr_init(struct nvkm_acr *);
+
+void ga100_acr_wpr_check(struct nvkm_acr *, u64 *, u64 *);
 
 struct nvkm_acr_hsfw {
        struct nvkm_falcon_fw fw;
@@ -93,6 +97,9 @@ extern const struct nvkm_falcon_fw_func gp108_acr_load_0;
 extern const struct nvkm_falcon_fw_func gp108_acr_hsfw_0;
 int gp108_acr_hsfw_load_bld(struct nvkm_falcon_fw *);
 
+int ga100_acr_hsfw_ctor(struct nvkm_acr *, const char *, const char *, const char *, int,
+                       const struct nvkm_acr_hsf_fwif *);
+
 int nvkm_acr_new_(const struct nvkm_acr_fwif *, struct nvkm_device *, enum nvkm_subdev_type,
                  int inst, struct nvkm_acr **);
 
index ad45f5c..c22d551 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <nvfw/acr.h>
 
-static int
+int
 tu102_acr_init(struct nvkm_acr *acr)
 {
        int ret = nvkm_acr_hsfw_boot(acr, "AHESASC");
index 67cc3b3..7f61a1e 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/gsp/base.o
 nvkm-y += nvkm/subdev/gsp/gv100.o
+nvkm-y += nvkm/subdev/gsp/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c
new file mode 100644 (file)
index 0000000..5252674
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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"
+
+static const struct nvkm_falcon_func
+ga102_gsp_flcn = {
+       .disable = gm200_flcn_disable,
+       .enable = gm200_flcn_enable,
+       .select = ga102_flcn_select,
+       .addr2 = 0x1000,
+       .reset_eng = gp102_flcn_reset_eng,
+       .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_gsp_func
+ga102_gsp = {
+       .flcn = &ga102_gsp_flcn,
+};
+
+static int
+ga102_gsp_nofw(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif)
+{
+       return 0;
+}
+
+struct nvkm_gsp_fwif
+ga102_gsps[] = {
+       { -1, ga102_gsp_nofw, &ga102_gsp },
+       {}
+};
+
+int
+ga102_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+             struct nvkm_gsp **pgsp)
+{
+       return nvkm_gsp_new_(ga102_gsps, device, type, inst, pgsp);
+}