1 /*
2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22 #include "priv.h"
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
31 int
gp102_sec2_nofw(struct nvkm_sec2 * sec2,int ver,const struct nvkm_sec2_fwif * fwif)32 gp102_sec2_nofw(struct nvkm_sec2 *sec2, int ver,
33 const struct nvkm_sec2_fwif *fwif)
34 {
35 nvkm_warn(&sec2->engine.subdev, "firmware unavailable\n");
36 return 0;
37 }
38
39 static int
gp102_sec2_acr_bootstrap_falcon_callback(void * priv,struct nvfw_falcon_msg * hdr)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
gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon * falcon,enum nvkm_acr_lsf_id id)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
gp102_sec2_acr_boot(struct nvkm_falcon * falcon)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
gp102_sec2_acr_bld_patch(struct nvkm_acr * acr,u32 bld,s64 adjust)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
gp102_sec2_acr_bld_write(struct nvkm_acr * acr,u32 bld,struct nvkm_acr_lsfw * lsfw)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
gp102_sec2_initmsg(struct nvkm_sec2 * sec2)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
gp102_sec2_intr(struct nvkm_sec2 * sec2)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
gp102_sec2_flcn_enable(struct nvkm_falcon * falcon)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
gp102_sec2_flcn_bind_context(struct nvkm_falcon * falcon,struct nvkm_memory * ctx)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
gp102_sec2_acr_bld_patch_1(struct nvkm_acr * acr,u32 bld,s64 adjust)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
gp102_sec2_acr_bld_write_1(struct nvkm_acr * acr,u32 bld,struct nvkm_acr_lsfw * lsfw)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
gp102_sec2_load(struct nvkm_sec2 * sec2,int ver,const struct nvkm_sec2_fwif * fwif)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
gp102_sec2_new(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_sec2 ** psec2)346 gp102_sec2_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
347 struct nvkm_sec2 **psec2)
348 {
349 return nvkm_sec2_new_(gp102_sec2_fwif, device, type, inst, 0, psec2);
350 }
351