| .. | .. |
|---|
| 19 | 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|---|
| 20 | 20 | * DEALINGS IN THE SOFTWARE. |
|---|
| 21 | 21 | */ |
|---|
| 22 | | - |
|---|
| 23 | 22 | #include "priv.h" |
|---|
| 24 | 23 | |
|---|
| 24 | +#include <core/memory.h> |
|---|
| 25 | +#include <subdev/acr.h> |
|---|
| 26 | +#include <subdev/timer.h> |
|---|
| 27 | + |
|---|
| 28 | +#include <nvfw/flcn.h> |
|---|
| 29 | +#include <nvfw/sec2.h> |
|---|
| 30 | + |
|---|
| 25 | 31 | int |
|---|
| 26 | | -gp102_sec2_new(struct nvkm_device *device, int index, |
|---|
| 27 | | - struct nvkm_sec2 **psec2) |
|---|
| 32 | +gp102_sec2_nofw(struct nvkm_sec2 *sec2, int ver, |
|---|
| 33 | + const struct nvkm_sec2_fwif *fwif) |
|---|
| 28 | 34 | { |
|---|
| 29 | | - return nvkm_sec2_new_(device, index, psec2); |
|---|
| 35 | + nvkm_warn(&sec2->engine.subdev, "firmware unavailable\n"); |
|---|
| 36 | + return 0; |
|---|
| 37 | +} |
|---|
| 38 | + |
|---|
| 39 | +static int |
|---|
| 40 | +gp102_sec2_acr_bootstrap_falcon_callback(void *priv, struct nvfw_falcon_msg *hdr) |
|---|
| 41 | +{ |
|---|
| 42 | + struct nv_sec2_acr_bootstrap_falcon_msg *msg = |
|---|
| 43 | + container_of(hdr, typeof(*msg), msg.hdr); |
|---|
| 44 | + struct nvkm_subdev *subdev = priv; |
|---|
| 45 | + const char *name = nvkm_acr_lsf_id(msg->falcon_id); |
|---|
| 46 | + |
|---|
| 47 | + if (msg->error_code) { |
|---|
| 48 | + nvkm_error(subdev, "ACR_BOOTSTRAP_FALCON failed for " |
|---|
| 49 | + "falcon %d [%s]: %08x\n", |
|---|
| 50 | + msg->falcon_id, name, msg->error_code); |
|---|
| 51 | + return -EINVAL; |
|---|
| 52 | + } |
|---|
| 53 | + |
|---|
| 54 | + nvkm_debug(subdev, "%s booted\n", name); |
|---|
| 55 | + return 0; |
|---|
| 56 | +} |
|---|
| 57 | + |
|---|
| 58 | +static int |
|---|
| 59 | +gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon, |
|---|
| 60 | + enum nvkm_acr_lsf_id id) |
|---|
| 61 | +{ |
|---|
| 62 | + struct nvkm_sec2 *sec2 = container_of(falcon, typeof(*sec2), falcon); |
|---|
| 63 | + struct nv_sec2_acr_bootstrap_falcon_cmd cmd = { |
|---|
| 64 | + .cmd.hdr.unit_id = sec2->func->unit_acr, |
|---|
| 65 | + .cmd.hdr.size = sizeof(cmd), |
|---|
| 66 | + .cmd.cmd_type = NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON, |
|---|
| 67 | + .flags = NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES, |
|---|
| 68 | + .falcon_id = id, |
|---|
| 69 | + }; |
|---|
| 70 | + |
|---|
| 71 | + return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.cmd.hdr, |
|---|
| 72 | + gp102_sec2_acr_bootstrap_falcon_callback, |
|---|
| 73 | + &sec2->engine.subdev, |
|---|
| 74 | + msecs_to_jiffies(1000)); |
|---|
| 75 | +} |
|---|
| 76 | + |
|---|
| 77 | +static int |
|---|
| 78 | +gp102_sec2_acr_boot(struct nvkm_falcon *falcon) |
|---|
| 79 | +{ |
|---|
| 80 | + struct nv_sec2_args args = {}; |
|---|
| 81 | + nvkm_falcon_load_dmem(falcon, &args, |
|---|
| 82 | + falcon->func->emem_addr, sizeof(args), 0); |
|---|
| 83 | + nvkm_falcon_start(falcon); |
|---|
| 84 | + return 0; |
|---|
| 85 | +} |
|---|
| 86 | + |
|---|
| 87 | +static void |
|---|
| 88 | +gp102_sec2_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust) |
|---|
| 89 | +{ |
|---|
| 90 | + struct loader_config_v1 hdr; |
|---|
| 91 | + nvkm_robj(acr->wpr, bld, &hdr, sizeof(hdr)); |
|---|
| 92 | + hdr.code_dma_base = hdr.code_dma_base + adjust; |
|---|
| 93 | + hdr.data_dma_base = hdr.data_dma_base + adjust; |
|---|
| 94 | + hdr.overlay_dma_base = hdr.overlay_dma_base + adjust; |
|---|
| 95 | + nvkm_wobj(acr->wpr, bld, &hdr, sizeof(hdr)); |
|---|
| 96 | + loader_config_v1_dump(&acr->subdev, &hdr); |
|---|
| 97 | +} |
|---|
| 98 | + |
|---|
| 99 | +static void |
|---|
| 100 | +gp102_sec2_acr_bld_write(struct nvkm_acr *acr, u32 bld, |
|---|
| 101 | + struct nvkm_acr_lsfw *lsfw) |
|---|
| 102 | +{ |
|---|
| 103 | + const struct loader_config_v1 hdr = { |
|---|
| 104 | + .dma_idx = FALCON_SEC2_DMAIDX_UCODE, |
|---|
| 105 | + .code_dma_base = lsfw->offset.img + lsfw->app_start_offset, |
|---|
| 106 | + .code_size_total = lsfw->app_size, |
|---|
| 107 | + .code_size_to_load = lsfw->app_resident_code_size, |
|---|
| 108 | + .code_entry_point = lsfw->app_imem_entry, |
|---|
| 109 | + .data_dma_base = lsfw->offset.img + lsfw->app_start_offset + |
|---|
| 110 | + lsfw->app_resident_data_offset, |
|---|
| 111 | + .data_size = lsfw->app_resident_data_size, |
|---|
| 112 | + .overlay_dma_base = lsfw->offset.img + lsfw->app_start_offset, |
|---|
| 113 | + .argc = 1, |
|---|
| 114 | + .argv = lsfw->falcon->func->emem_addr, |
|---|
| 115 | + }; |
|---|
| 116 | + |
|---|
| 117 | + nvkm_wobj(acr->wpr, bld, &hdr, sizeof(hdr)); |
|---|
| 118 | +} |
|---|
| 119 | + |
|---|
| 120 | +static const struct nvkm_acr_lsf_func |
|---|
| 121 | +gp102_sec2_acr_0 = { |
|---|
| 122 | + .bld_size = sizeof(struct loader_config_v1), |
|---|
| 123 | + .bld_write = gp102_sec2_acr_bld_write, |
|---|
| 124 | + .bld_patch = gp102_sec2_acr_bld_patch, |
|---|
| 125 | + .boot = gp102_sec2_acr_boot, |
|---|
| 126 | + .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) | |
|---|
| 127 | + BIT_ULL(NVKM_ACR_LSF_GPCCS) | |
|---|
| 128 | + BIT_ULL(NVKM_ACR_LSF_SEC2), |
|---|
| 129 | + .bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon, |
|---|
| 130 | +}; |
|---|
| 131 | + |
|---|
| 132 | +int |
|---|
| 133 | +gp102_sec2_initmsg(struct nvkm_sec2 *sec2) |
|---|
| 134 | +{ |
|---|
| 135 | + struct nv_sec2_init_msg msg; |
|---|
| 136 | + int ret, i; |
|---|
| 137 | + |
|---|
| 138 | + ret = nvkm_falcon_msgq_recv_initmsg(sec2->msgq, &msg, sizeof(msg)); |
|---|
| 139 | + if (ret) |
|---|
| 140 | + return ret; |
|---|
| 141 | + |
|---|
| 142 | + if (msg.hdr.unit_id != NV_SEC2_UNIT_INIT || |
|---|
| 143 | + msg.msg_type != NV_SEC2_INIT_MSG_INIT) |
|---|
| 144 | + return -EINVAL; |
|---|
| 145 | + |
|---|
| 146 | + for (i = 0; i < ARRAY_SIZE(msg.queue_info); i++) { |
|---|
| 147 | + if (msg.queue_info[i].id == NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ) { |
|---|
| 148 | + nvkm_falcon_msgq_init(sec2->msgq, |
|---|
| 149 | + msg.queue_info[i].index, |
|---|
| 150 | + msg.queue_info[i].offset, |
|---|
| 151 | + msg.queue_info[i].size); |
|---|
| 152 | + } else { |
|---|
| 153 | + nvkm_falcon_cmdq_init(sec2->cmdq, |
|---|
| 154 | + msg.queue_info[i].index, |
|---|
| 155 | + msg.queue_info[i].offset, |
|---|
| 156 | + msg.queue_info[i].size); |
|---|
| 157 | + } |
|---|
| 158 | + } |
|---|
| 159 | + |
|---|
| 160 | + return 0; |
|---|
| 161 | +} |
|---|
| 162 | + |
|---|
| 163 | +void |
|---|
| 164 | +gp102_sec2_intr(struct nvkm_sec2 *sec2) |
|---|
| 165 | +{ |
|---|
| 166 | + struct nvkm_subdev *subdev = &sec2->engine.subdev; |
|---|
| 167 | + struct nvkm_falcon *falcon = &sec2->falcon; |
|---|
| 168 | + u32 disp = nvkm_falcon_rd32(falcon, 0x01c); |
|---|
| 169 | + u32 intr = nvkm_falcon_rd32(falcon, 0x008) & disp & ~(disp >> 16); |
|---|
| 170 | + |
|---|
| 171 | + if (intr & 0x00000040) { |
|---|
| 172 | + schedule_work(&sec2->work); |
|---|
| 173 | + nvkm_falcon_wr32(falcon, 0x004, 0x00000040); |
|---|
| 174 | + intr &= ~0x00000040; |
|---|
| 175 | + } |
|---|
| 176 | + |
|---|
| 177 | + if (intr) { |
|---|
| 178 | + nvkm_error(subdev, "unhandled intr %08x\n", intr); |
|---|
| 179 | + nvkm_falcon_wr32(falcon, 0x004, intr); |
|---|
| 180 | + } |
|---|
| 181 | +} |
|---|
| 182 | + |
|---|
| 183 | +int |
|---|
| 184 | +gp102_sec2_flcn_enable(struct nvkm_falcon *falcon) |
|---|
| 185 | +{ |
|---|
| 186 | + nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000001); |
|---|
| 187 | + udelay(10); |
|---|
| 188 | + nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000000); |
|---|
| 189 | + return nvkm_falcon_v1_enable(falcon); |
|---|
| 190 | +} |
|---|
| 191 | + |
|---|
| 192 | +void |
|---|
| 193 | +gp102_sec2_flcn_bind_context(struct nvkm_falcon *falcon, |
|---|
| 194 | + struct nvkm_memory *ctx) |
|---|
| 195 | +{ |
|---|
| 196 | + struct nvkm_device *device = falcon->owner->device; |
|---|
| 197 | + |
|---|
| 198 | + nvkm_falcon_v1_bind_context(falcon, ctx); |
|---|
| 199 | + if (!ctx) |
|---|
| 200 | + return; |
|---|
| 201 | + |
|---|
| 202 | + /* Not sure if this is a WAR for a HW issue, or some additional |
|---|
| 203 | + * programming sequence that's needed to properly complete the |
|---|
| 204 | + * context switch we trigger above. |
|---|
| 205 | + * |
|---|
| 206 | + * Fixes unreliability of booting the SEC2 RTOS on Quadro P620, |
|---|
| 207 | + * particularly when resuming from suspend. |
|---|
| 208 | + * |
|---|
| 209 | + * Also removes the need for an odd workaround where we needed |
|---|
| 210 | + * to program SEC2's FALCON_CPUCTL_ALIAS_STARTCPU twice before |
|---|
| 211 | + * the SEC2 RTOS would begin executing. |
|---|
| 212 | + */ |
|---|
| 213 | + nvkm_msec(device, 10, |
|---|
| 214 | + u32 irqstat = nvkm_falcon_rd32(falcon, 0x008); |
|---|
| 215 | + u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc); |
|---|
| 216 | + if ((irqstat & 0x00000008) && |
|---|
| 217 | + (flcn0dc & 0x00007000) == 0x00005000) |
|---|
| 218 | + break; |
|---|
| 219 | + ); |
|---|
| 220 | + |
|---|
| 221 | + nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008); |
|---|
| 222 | + nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002); |
|---|
| 223 | + |
|---|
| 224 | + nvkm_msec(device, 10, |
|---|
| 225 | + u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc); |
|---|
| 226 | + if ((flcn0dc & 0x00007000) == 0x00000000) |
|---|
| 227 | + break; |
|---|
| 228 | + ); |
|---|
| 229 | +} |
|---|
| 230 | + |
|---|
| 231 | +static const struct nvkm_falcon_func |
|---|
| 232 | +gp102_sec2_flcn = { |
|---|
| 233 | + .debug = 0x408, |
|---|
| 234 | + .fbif = 0x600, |
|---|
| 235 | + .load_imem = nvkm_falcon_v1_load_imem, |
|---|
| 236 | + .load_dmem = nvkm_falcon_v1_load_dmem, |
|---|
| 237 | + .read_dmem = nvkm_falcon_v1_read_dmem, |
|---|
| 238 | + .emem_addr = 0x01000000, |
|---|
| 239 | + .bind_context = gp102_sec2_flcn_bind_context, |
|---|
| 240 | + .wait_for_halt = nvkm_falcon_v1_wait_for_halt, |
|---|
| 241 | + .clear_interrupt = nvkm_falcon_v1_clear_interrupt, |
|---|
| 242 | + .set_start_addr = nvkm_falcon_v1_set_start_addr, |
|---|
| 243 | + .start = nvkm_falcon_v1_start, |
|---|
| 244 | + .enable = gp102_sec2_flcn_enable, |
|---|
| 245 | + .disable = nvkm_falcon_v1_disable, |
|---|
| 246 | + .cmdq = { 0xa00, 0xa04, 8 }, |
|---|
| 247 | + .msgq = { 0xa30, 0xa34, 8 }, |
|---|
| 248 | +}; |
|---|
| 249 | + |
|---|
| 250 | +const struct nvkm_sec2_func |
|---|
| 251 | +gp102_sec2 = { |
|---|
| 252 | + .flcn = &gp102_sec2_flcn, |
|---|
| 253 | + .unit_acr = NV_SEC2_UNIT_ACR, |
|---|
| 254 | + .intr = gp102_sec2_intr, |
|---|
| 255 | + .initmsg = gp102_sec2_initmsg, |
|---|
| 256 | +}; |
|---|
| 257 | + |
|---|
| 258 | +MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin"); |
|---|
| 259 | +MODULE_FIRMWARE("nvidia/gp102/sec2/image.bin"); |
|---|
| 260 | +MODULE_FIRMWARE("nvidia/gp102/sec2/sig.bin"); |
|---|
| 261 | +MODULE_FIRMWARE("nvidia/gp104/sec2/desc.bin"); |
|---|
| 262 | +MODULE_FIRMWARE("nvidia/gp104/sec2/image.bin"); |
|---|
| 263 | +MODULE_FIRMWARE("nvidia/gp104/sec2/sig.bin"); |
|---|
| 264 | +MODULE_FIRMWARE("nvidia/gp106/sec2/desc.bin"); |
|---|
| 265 | +MODULE_FIRMWARE("nvidia/gp106/sec2/image.bin"); |
|---|
| 266 | +MODULE_FIRMWARE("nvidia/gp106/sec2/sig.bin"); |
|---|
| 267 | +MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin"); |
|---|
| 268 | +MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin"); |
|---|
| 269 | +MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin"); |
|---|
| 270 | + |
|---|
| 271 | +static void |
|---|
| 272 | +gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust) |
|---|
| 273 | +{ |
|---|
| 274 | + struct flcn_bl_dmem_desc_v2 hdr; |
|---|
| 275 | + nvkm_robj(acr->wpr, bld, &hdr, sizeof(hdr)); |
|---|
| 276 | + hdr.code_dma_base = hdr.code_dma_base + adjust; |
|---|
| 277 | + hdr.data_dma_base = hdr.data_dma_base + adjust; |
|---|
| 278 | + nvkm_wobj(acr->wpr, bld, &hdr, sizeof(hdr)); |
|---|
| 279 | + flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hdr); |
|---|
| 280 | +} |
|---|
| 281 | + |
|---|
| 282 | +static void |
|---|
| 283 | +gp102_sec2_acr_bld_write_1(struct nvkm_acr *acr, u32 bld, |
|---|
| 284 | + struct nvkm_acr_lsfw *lsfw) |
|---|
| 285 | +{ |
|---|
| 286 | + const struct flcn_bl_dmem_desc_v2 hdr = { |
|---|
| 287 | + .ctx_dma = FALCON_SEC2_DMAIDX_UCODE, |
|---|
| 288 | + .code_dma_base = lsfw->offset.img + lsfw->app_start_offset, |
|---|
| 289 | + .non_sec_code_off = lsfw->app_resident_code_offset, |
|---|
| 290 | + .non_sec_code_size = lsfw->app_resident_code_size, |
|---|
| 291 | + .code_entry_point = lsfw->app_imem_entry, |
|---|
| 292 | + .data_dma_base = lsfw->offset.img + lsfw->app_start_offset + |
|---|
| 293 | + lsfw->app_resident_data_offset, |
|---|
| 294 | + .data_size = lsfw->app_resident_data_size, |
|---|
| 295 | + .argc = 1, |
|---|
| 296 | + .argv = lsfw->falcon->func->emem_addr, |
|---|
| 297 | + }; |
|---|
| 298 | + |
|---|
| 299 | + nvkm_wobj(acr->wpr, bld, &hdr, sizeof(hdr)); |
|---|
| 300 | +} |
|---|
| 301 | + |
|---|
| 302 | +const struct nvkm_acr_lsf_func |
|---|
| 303 | +gp102_sec2_acr_1 = { |
|---|
| 304 | + .bld_size = sizeof(struct flcn_bl_dmem_desc_v2), |
|---|
| 305 | + .bld_write = gp102_sec2_acr_bld_write_1, |
|---|
| 306 | + .bld_patch = gp102_sec2_acr_bld_patch_1, |
|---|
| 307 | + .boot = gp102_sec2_acr_boot, |
|---|
| 308 | + .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) | |
|---|
| 309 | + BIT_ULL(NVKM_ACR_LSF_GPCCS) | |
|---|
| 310 | + BIT_ULL(NVKM_ACR_LSF_SEC2), |
|---|
| 311 | + .bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon, |
|---|
| 312 | +}; |
|---|
| 313 | + |
|---|
| 314 | +int |
|---|
| 315 | +gp102_sec2_load(struct nvkm_sec2 *sec2, int ver, |
|---|
| 316 | + const struct nvkm_sec2_fwif *fwif) |
|---|
| 317 | +{ |
|---|
| 318 | + return nvkm_acr_lsfw_load_sig_image_desc_v1(&sec2->engine.subdev, |
|---|
| 319 | + &sec2->falcon, |
|---|
| 320 | + NVKM_ACR_LSF_SEC2, "sec2/", |
|---|
| 321 | + ver, fwif->acr); |
|---|
| 322 | +} |
|---|
| 323 | + |
|---|
| 324 | +MODULE_FIRMWARE("nvidia/gp102/sec2/desc-1.bin"); |
|---|
| 325 | +MODULE_FIRMWARE("nvidia/gp102/sec2/image-1.bin"); |
|---|
| 326 | +MODULE_FIRMWARE("nvidia/gp102/sec2/sig-1.bin"); |
|---|
| 327 | +MODULE_FIRMWARE("nvidia/gp104/sec2/desc-1.bin"); |
|---|
| 328 | +MODULE_FIRMWARE("nvidia/gp104/sec2/image-1.bin"); |
|---|
| 329 | +MODULE_FIRMWARE("nvidia/gp104/sec2/sig-1.bin"); |
|---|
| 330 | +MODULE_FIRMWARE("nvidia/gp106/sec2/desc-1.bin"); |
|---|
| 331 | +MODULE_FIRMWARE("nvidia/gp106/sec2/image-1.bin"); |
|---|
| 332 | +MODULE_FIRMWARE("nvidia/gp106/sec2/sig-1.bin"); |
|---|
| 333 | +MODULE_FIRMWARE("nvidia/gp107/sec2/desc-1.bin"); |
|---|
| 334 | +MODULE_FIRMWARE("nvidia/gp107/sec2/image-1.bin"); |
|---|
| 335 | +MODULE_FIRMWARE("nvidia/gp107/sec2/sig-1.bin"); |
|---|
| 336 | + |
|---|
| 337 | +static const struct nvkm_sec2_fwif |
|---|
| 338 | +gp102_sec2_fwif[] = { |
|---|
| 339 | + { 1, gp102_sec2_load, &gp102_sec2, &gp102_sec2_acr_1 }, |
|---|
| 340 | + { 0, gp102_sec2_load, &gp102_sec2, &gp102_sec2_acr_0 }, |
|---|
| 341 | + { -1, gp102_sec2_nofw, &gp102_sec2 }, |
|---|
| 342 | + {} |
|---|
| 343 | +}; |
|---|
| 344 | + |
|---|
| 345 | +int |
|---|
| 346 | +gp102_sec2_new(struct nvkm_device *device, int index, struct nvkm_sec2 **psec2) |
|---|
| 347 | +{ |
|---|
| 348 | + return nvkm_sec2_new_(gp102_sec2_fwif, device, index, 0, psec2); |
|---|
| 30 | 349 | } |
|---|