289 lines · c
1/*2 * Copyright 2019 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 */22#include "priv.h"23 24#include <core/firmware.h>25#include <core/memory.h>26#include <subdev/mmu.h>27#include <engine/sec2.h>28 29#include <nvfw/acr.h>30#include <nvfw/flcn.h>31 32int33gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)34{35 struct wpr_header_v1 hdr;36 struct lsb_header_v1 lsb;37 struct nvkm_acr_lsfw *lsfw;38 u32 offset = 0;39 40 do {41 nvkm_robj(acr->wpr, offset, &hdr, sizeof(hdr));42 wpr_header_v1_dump(&acr->subdev, &hdr);43 44 list_for_each_entry(lsfw, &acr->lsfw, head) {45 if (lsfw->id != hdr.falcon_id)46 continue;47 48 nvkm_robj(acr->wpr, hdr.lsb_offset, &lsb, sizeof(lsb));49 lsb_header_v1_dump(&acr->subdev, &lsb);50 51 lsfw->func->bld_patch(acr, lsb.tail.bl_data_off, adjust);52 break;53 }54 55 offset += sizeof(hdr);56 } while (hdr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID);57 58 return 0;59}60 61int62gp102_acr_wpr_build_lsb(struct nvkm_acr *acr, struct nvkm_acr_lsfw *lsfw)63{64 struct lsb_header_v1 hdr;65 66 if (WARN_ON(lsfw->sig->size != sizeof(hdr.signature)))67 return -EINVAL;68 69 memcpy(&hdr.signature, lsfw->sig->data, lsfw->sig->size);70 gm200_acr_wpr_build_lsb_tail(lsfw, &hdr.tail);71 72 nvkm_wobj(acr->wpr, lsfw->offset.lsb, &hdr, sizeof(hdr));73 return 0;74}75 76int77gp102_acr_wpr_build(struct nvkm_acr *acr, struct nvkm_acr_lsf *rtos)78{79 struct nvkm_acr_lsfw *lsfw;80 u32 offset = 0;81 int ret;82 83 /* Fill per-LSF structures. */84 list_for_each_entry(lsfw, &acr->lsfw, head) {85 struct lsf_signature_v1 *sig = (void *)lsfw->sig->data;86 struct wpr_header_v1 hdr = {87 .falcon_id = lsfw->id,88 .lsb_offset = lsfw->offset.lsb,89 .bootstrap_owner = NVKM_ACR_LSF_SEC2,90 .lazy_bootstrap = rtos && lsfw->id != rtos->id,91 .bin_version = sig->version,92 .status = WPR_HEADER_V1_STATUS_COPY,93 };94 95 /* Write WPR header. */96 nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr));97 offset += sizeof(hdr);98 99 /* Write LSB header. */100 ret = gp102_acr_wpr_build_lsb(acr, lsfw);101 if (ret)102 return ret;103 104 /* Write ucode image. */105 nvkm_wobj(acr->wpr, lsfw->offset.img,106 lsfw->img.data,107 lsfw->img.size);108 109 /* Write bootloader data. */110 lsfw->func->bld_write(acr, lsfw->offset.bld, lsfw);111 }112 113 /* Finalise WPR. */114 nvkm_wo32(acr->wpr, offset, WPR_HEADER_V1_FALCON_ID_INVALID);115 return 0;116}117 118int119gp102_acr_wpr_alloc(struct nvkm_acr *acr, u32 wpr_size)120{121 int ret = nvkm_memory_new(acr->subdev.device, NVKM_MEM_TARGET_INST,122 ALIGN(wpr_size, 0x40000) << 1, 0x40000, true,123 &acr->wpr);124 if (ret)125 return ret;126 127 acr->shadow_start = nvkm_memory_addr(acr->wpr);128 acr->wpr_start = acr->shadow_start + (nvkm_memory_size(acr->wpr) >> 1);129 acr->wpr_end = acr->wpr_start + (nvkm_memory_size(acr->wpr) >> 1);130 return 0;131}132 133u32134gp102_acr_wpr_layout(struct nvkm_acr *acr)135{136 struct nvkm_acr_lsfw *lsfw;137 u32 wpr = 0;138 139 wpr += 11 /* MAX_LSF */ * sizeof(struct wpr_header_v1);140 wpr = ALIGN(wpr, 256);141 142 wpr += 0x100; /* Shared sub-WPR headers. */143 144 list_for_each_entry(lsfw, &acr->lsfw, head) {145 wpr = ALIGN(wpr, 256);146 lsfw->offset.lsb = wpr;147 wpr += sizeof(struct lsb_header_v1);148 149 wpr = ALIGN(wpr, 4096);150 lsfw->offset.img = wpr;151 wpr += lsfw->img.size;152 153 wpr = ALIGN(wpr, 256);154 lsfw->offset.bld = wpr;155 lsfw->bl_data_size = ALIGN(lsfw->func->bld_size, 256);156 wpr += lsfw->bl_data_size;157 }158 159 return wpr;160}161 162int163gp102_acr_wpr_parse(struct nvkm_acr *acr)164{165 const struct wpr_header_v1 *hdr = (void *)acr->wpr_fw->data;166 struct nvkm_acr_lsfw *lsfw;167 168 while (hdr->falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID) {169 wpr_header_v1_dump(&acr->subdev, hdr);170 lsfw = nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->falcon_id);171 if (IS_ERR(lsfw))172 return PTR_ERR(lsfw);173 }174 175 return 0;176}177 178MODULE_FIRMWARE("nvidia/gp102/acr/unload_bl.bin");179MODULE_FIRMWARE("nvidia/gp102/acr/ucode_unload.bin");180 181MODULE_FIRMWARE("nvidia/gp104/acr/unload_bl.bin");182MODULE_FIRMWARE("nvidia/gp104/acr/ucode_unload.bin");183 184MODULE_FIRMWARE("nvidia/gp106/acr/unload_bl.bin");185MODULE_FIRMWARE("nvidia/gp106/acr/ucode_unload.bin");186 187MODULE_FIRMWARE("nvidia/gp107/acr/unload_bl.bin");188MODULE_FIRMWARE("nvidia/gp107/acr/ucode_unload.bin");189 190static const struct nvkm_acr_hsf_fwif191gp102_acr_unload_fwif[] = {192 { 0, gm200_acr_hsfw_ctor, &gm200_acr_unload_0, NVKM_ACR_HSF_PMU, 0x1d, 0x00000010 },193 {}194};195 196int197gp102_acr_load_setup(struct nvkm_falcon_fw *fw)198{199 struct flcn_acr_desc_v1 *desc = (void *)&fw->fw.img[fw->dmem_base_img];200 struct nvkm_acr *acr = fw->falcon->owner->device->acr;201 202 desc->wpr_region_id = 1;203 desc->regions.no_regions = 2;204 desc->regions.region_props[0].start_addr = acr->wpr_start >> 8;205 desc->regions.region_props[0].end_addr = acr->wpr_end >> 8;206 desc->regions.region_props[0].region_id = 1;207 desc->regions.region_props[0].read_mask = 0xf;208 desc->regions.region_props[0].write_mask = 0xc;209 desc->regions.region_props[0].client_mask = 0x2;210 desc->regions.region_props[0].shadow_mem_start_addr = acr->shadow_start >> 8;211 flcn_acr_desc_v1_dump(&acr->subdev, desc);212 return 0;213}214 215static const struct nvkm_falcon_fw_func216gp102_acr_load_0 = {217 .signature = gm200_flcn_fw_signature,218 .reset = gm200_flcn_fw_reset,219 .setup = gp102_acr_load_setup,220 .load = gm200_flcn_fw_load,221 .load_bld = gm200_acr_hsfw_load_bld,222 .boot = gm200_flcn_fw_boot,223};224 225MODULE_FIRMWARE("nvidia/gp102/acr/bl.bin");226MODULE_FIRMWARE("nvidia/gp102/acr/ucode_load.bin");227 228MODULE_FIRMWARE("nvidia/gp104/acr/bl.bin");229MODULE_FIRMWARE("nvidia/gp104/acr/ucode_load.bin");230 231MODULE_FIRMWARE("nvidia/gp106/acr/bl.bin");232MODULE_FIRMWARE("nvidia/gp106/acr/ucode_load.bin");233 234MODULE_FIRMWARE("nvidia/gp107/acr/bl.bin");235MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin");236 237static const struct nvkm_acr_hsf_fwif238gp102_acr_load_fwif[] = {239 { 0, gm200_acr_hsfw_ctor, &gp102_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 },240 {}241};242 243static const struct nvkm_acr_func244gp102_acr = {245 .load = gp102_acr_load_fwif,246 .unload = gp102_acr_unload_fwif,247 .wpr_parse = gp102_acr_wpr_parse,248 .wpr_layout = gp102_acr_wpr_layout,249 .wpr_alloc = gp102_acr_wpr_alloc,250 .wpr_build = gp102_acr_wpr_build,251 .wpr_patch = gp102_acr_wpr_patch,252 .wpr_check = gm200_acr_wpr_check,253 .init = gm200_acr_init,254};255 256int257gp102_acr_load(struct nvkm_acr *acr, int ver, const struct nvkm_acr_fwif *fwif)258{259 struct nvkm_subdev *subdev = &acr->subdev;260 const struct nvkm_acr_hsf_fwif *hsfwif;261 262 hsfwif = nvkm_firmware_load(subdev, fwif->func->load, "AcrLoad",263 acr, "acr/bl", "acr/ucode_load", "load");264 if (IS_ERR(hsfwif))265 return PTR_ERR(hsfwif);266 267 hsfwif = nvkm_firmware_load(subdev, fwif->func->unload, "AcrUnload",268 acr, "acr/unload_bl", "acr/ucode_unload",269 "unload");270 if (IS_ERR(hsfwif))271 return PTR_ERR(hsfwif);272 273 return 0;274}275 276static const struct nvkm_acr_fwif277gp102_acr_fwif[] = {278 { 0, gp102_acr_load, &gp102_acr },279 { -1, gm200_acr_nofw, &gm200_acr },280 {}281};282 283int284gp102_acr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,285 struct nvkm_acr **pacr)286{287 return nvkm_acr_new_(gp102_acr_fwif, device, type, inst, pacr);288}289