Commit 4b569ded authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/acr/ga102: initial support

v2. fixup for ga103 early merge
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Signed-off-by: default avatarGourav Samaiya <gsamaiya@nvidia.com>
parent a51c69ee
......@@ -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];
......
......@@ -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
......@@ -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
......@@ -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;
......
......@@ -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 *);
......
......@@ -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
......@@ -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,
......
......@@ -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
......@@ -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 *
......
......@@ -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
......@@ -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);
}
......
/*
* 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);
}
......@@ -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)
{
......
......@@ -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 **);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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;
}
......@@ -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
/*
* 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);
}
/*
* 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);
}
......@@ -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
......
......@@ -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
......
......@@ -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);
......@@ -176,6 +177,75 @@ nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *subdev,
return 0;
}
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,
......
......@@ -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 **);
......
......@@ -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");
......
# 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
/*
* 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment