diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/acr_gp106.c')
-rw-r--r-- | drivers/gpu/nvgpu/gp106/acr_gp106.c | 1169 |
1 files changed, 1169 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gp106/acr_gp106.c b/drivers/gpu/nvgpu/gp106/acr_gp106.c new file mode 100644 index 00000000..5ed6300c --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/acr_gp106.c | |||
@@ -0,0 +1,1169 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> /* for mdelay */ | ||
15 | #include <linux/firmware.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/debugfs.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/io.h> | ||
21 | |||
22 | #include "gk20a/gk20a.h" | ||
23 | #include "gk20a/pmu_gk20a.h" | ||
24 | #include "gk20a/semaphore_gk20a.h" | ||
25 | #include "gp106/hw_psec_gp106.h" | ||
26 | #include "gp106/hw_pwr_gp106.h" | ||
27 | #include "gm206/acr_gm206.h" | ||
28 | #include "gm20b/acr_gm20b.h" | ||
29 | #include "gm206/pmu_gm206.h" | ||
30 | #include "sec2_gp106.h" | ||
31 | #include "nvgpu_gpuid_t18x.h" | ||
32 | #include "nvgpu_common.h" | ||
33 | |||
34 | /*Defines*/ | ||
35 | #define gp106_dbg_pmu(fmt, arg...) \ | ||
36 | gk20a_dbg(gpu_dbg_pmu, fmt, ##arg) | ||
37 | |||
38 | typedef int (*get_ucode_details)(struct gk20a *g, | ||
39 | struct flcn_ucode_img_v1 *udata); | ||
40 | |||
41 | /* Both size and address of WPR need to be 128K-aligned */ | ||
42 | #define WPR_ALIGNMENT 0x20000 | ||
43 | #define GP106_DGPU_NONWPR NVGPU_VIDMEM_BOOTSTRAP_ALLOCATOR_BASE | ||
44 | #define GP106_DGPU_WPR_OFFSET 0x400000 | ||
45 | #define DGPU_WPR_SIZE 0x100000 | ||
46 | |||
47 | /*Externs*/ | ||
48 | |||
49 | /*Forwards*/ | ||
50 | static int pmu_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img); | ||
51 | static int fecs_ucode_details(struct gk20a *g, | ||
52 | struct flcn_ucode_img_v1 *p_img); | ||
53 | static int gpccs_ucode_details(struct gk20a *g, | ||
54 | struct flcn_ucode_img_v1 *p_img); | ||
55 | static int gp106_bootstrap_hs_flcn(struct gk20a *g); | ||
56 | |||
57 | static int lsfm_discover_ucode_images(struct gk20a *g, | ||
58 | struct ls_flcn_mgr_v1 *plsfm); | ||
59 | static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm, | ||
60 | struct flcn_ucode_img_v1 *ucode_image, u32 falcon_id); | ||
61 | static void lsfm_free_ucode_img_res(struct flcn_ucode_img_v1 *p_img); | ||
62 | static void lsfm_free_nonpmu_ucode_img_res(struct flcn_ucode_img_v1 *p_img); | ||
63 | static int lsf_gen_wpr_requirements(struct gk20a *g, | ||
64 | struct ls_flcn_mgr_v1 *plsfm); | ||
65 | static void lsfm_init_wpr_contents(struct gk20a *g, | ||
66 | struct ls_flcn_mgr_v1 *plsfm, struct mem_desc *nonwpr); | ||
67 | static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm); | ||
68 | static int gp106_pmu_populate_loader_cfg(struct gk20a *g, | ||
69 | void *lsfm, u32 *p_bl_gen_desc_size); | ||
70 | static int gp106_flcn_populate_bl_dmem_desc(struct gk20a *g, | ||
71 | void *lsfm, u32 *p_bl_gen_desc_size, u32 falconid); | ||
72 | static int gp106_prepare_ucode_blob(struct gk20a *g); | ||
73 | |||
74 | /*Globals*/ | ||
75 | static get_ucode_details pmu_acr_supp_ucode_list[] = { | ||
76 | pmu_ucode_details, | ||
77 | fecs_ucode_details, | ||
78 | gpccs_ucode_details, | ||
79 | }; | ||
80 | |||
81 | static void gp106_wpr_info(struct gk20a *g, struct wpr_carveout_info *inf) | ||
82 | { | ||
83 | inf->nonwpr_base = g->mm.vidmem.bootstrap_base; | ||
84 | inf->wpr_base = inf->nonwpr_base + GP106_DGPU_WPR_OFFSET; | ||
85 | inf->size = DGPU_WPR_SIZE; | ||
86 | } | ||
87 | |||
88 | static void flcn64_set_dma(struct falc_u64 *dma_addr, u64 value) | ||
89 | { | ||
90 | dma_addr->lo |= u64_lo32(value); | ||
91 | dma_addr->hi |= u64_hi32(value); | ||
92 | } | ||
93 | |||
94 | static int gp106_alloc_blob_space(struct gk20a *g, | ||
95 | size_t size, struct mem_desc *mem) | ||
96 | { | ||
97 | struct wpr_carveout_info wpr_inf; | ||
98 | int err; | ||
99 | |||
100 | if (mem->size) | ||
101 | return 0; | ||
102 | |||
103 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
104 | |||
105 | /* | ||
106 | * Even though this mem_desc wouldn't be used, the wpr region needs to | ||
107 | * be reserved in the allocator. | ||
108 | */ | ||
109 | err = gk20a_gmmu_alloc_attr_vid_at(g, 0, wpr_inf.size, | ||
110 | &g->acr.wpr_dummy, wpr_inf.wpr_base); | ||
111 | if (err) | ||
112 | return err; | ||
113 | |||
114 | return gk20a_gmmu_alloc_attr_vid_at(g, 0, wpr_inf.size, mem, | ||
115 | wpr_inf.nonwpr_base); | ||
116 | } | ||
117 | |||
118 | void gp106_init_secure_pmu(struct gpu_ops *gops) | ||
119 | { | ||
120 | gops->pmu.prepare_ucode = gp106_prepare_ucode_blob; | ||
121 | gops->pmu.pmu_setup_hw_and_bootstrap = gp106_bootstrap_hs_flcn; | ||
122 | gops->pmu.is_lazy_bootstrap = gm206_is_lazy_bootstrap; | ||
123 | gops->pmu.is_priv_load = gm206_is_priv_load; | ||
124 | gops->pmu.get_wpr = gp106_wpr_info; | ||
125 | gops->pmu.alloc_blob_space = gp106_alloc_blob_space; | ||
126 | gops->pmu.pmu_populate_loader_cfg = gp106_pmu_populate_loader_cfg; | ||
127 | gops->pmu.flcn_populate_bl_dmem_desc = gp106_flcn_populate_bl_dmem_desc; | ||
128 | gops->pmu.falcon_wait_for_halt = sec2_wait_for_halt; | ||
129 | gops->pmu.falcon_clear_halt_interrupt_status = | ||
130 | sec2_clear_halt_interrupt_status; | ||
131 | gops->pmu.init_falcon_setup_hw = init_sec2_setup_hw1; | ||
132 | } | ||
133 | /* TODO - check if any free blob res needed*/ | ||
134 | |||
135 | static int pmu_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img) | ||
136 | { | ||
137 | const struct firmware *pmu_fw, *pmu_desc, *pmu_sig; | ||
138 | struct pmu_gk20a *pmu = &g->pmu; | ||
139 | struct lsf_ucode_desc_v1 *lsf_desc; | ||
140 | int err; | ||
141 | |||
142 | gp106_dbg_pmu("requesting PMU ucode in gp106\n"); | ||
143 | pmu_fw = nvgpu_request_firmware(g, GM20B_PMU_UCODE_IMAGE, | ||
144 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
145 | if (!pmu_fw) { | ||
146 | gk20a_err(dev_from_gk20a(g), "failed to load pmu ucode!!"); | ||
147 | return -ENOENT; | ||
148 | } | ||
149 | g->acr.pmu_fw = pmu_fw; | ||
150 | gp106_dbg_pmu("Loaded PMU ucode in for blob preparation"); | ||
151 | |||
152 | gp106_dbg_pmu("requesting PMU ucode desc in GM20B\n"); | ||
153 | pmu_desc = nvgpu_request_firmware(g, GM20B_PMU_UCODE_DESC, | ||
154 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
155 | if (!pmu_desc) { | ||
156 | gk20a_err(dev_from_gk20a(g), "failed to load pmu ucode desc!!"); | ||
157 | err = -ENOENT; | ||
158 | goto release_img_fw; | ||
159 | } | ||
160 | pmu_sig = nvgpu_request_firmware(g, GM20B_PMU_UCODE_SIG, | ||
161 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
162 | if (!pmu_sig) { | ||
163 | gk20a_err(dev_from_gk20a(g), "failed to load pmu sig!!"); | ||
164 | err = -ENOENT; | ||
165 | goto release_desc; | ||
166 | } | ||
167 | pmu->desc_v1 = (struct pmu_ucode_desc_v1 *)pmu_desc->data; | ||
168 | pmu->ucode_image = (u32 *)pmu_fw->data; | ||
169 | g->acr.pmu_desc = pmu_desc; | ||
170 | |||
171 | err = gk20a_init_pmu(pmu); | ||
172 | if (err) { | ||
173 | gp106_dbg_pmu("failed to set function pointers\n"); | ||
174 | goto release_sig; | ||
175 | } | ||
176 | |||
177 | lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc_v1), GFP_KERNEL); | ||
178 | if (!lsf_desc) { | ||
179 | err = -ENOMEM; | ||
180 | goto release_sig; | ||
181 | } | ||
182 | memcpy(lsf_desc, (void *)pmu_sig->data, sizeof(struct lsf_ucode_desc_v1)); | ||
183 | lsf_desc->falcon_id = LSF_FALCON_ID_PMU; | ||
184 | |||
185 | p_img->desc = pmu->desc_v1; | ||
186 | p_img->data = pmu->ucode_image; | ||
187 | p_img->data_size = pmu->desc_v1->app_start_offset | ||
188 | + pmu->desc_v1->app_size; | ||
189 | p_img->fw_ver = NULL; | ||
190 | p_img->header = NULL; | ||
191 | p_img->lsf_desc = (struct lsf_ucode_desc_v1 *)lsf_desc; | ||
192 | gp106_dbg_pmu("requesting PMU ucode in GM20B exit\n"); | ||
193 | |||
194 | release_firmware(pmu_sig); | ||
195 | return 0; | ||
196 | release_sig: | ||
197 | release_firmware(pmu_sig); | ||
198 | release_desc: | ||
199 | release_firmware(pmu_desc); | ||
200 | release_img_fw: | ||
201 | release_firmware(pmu_fw); | ||
202 | return err; | ||
203 | } | ||
204 | |||
205 | static int fecs_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img) | ||
206 | { | ||
207 | u32 ver = g->gpu_characteristics.arch + g->gpu_characteristics.impl; | ||
208 | struct lsf_ucode_desc_v1 *lsf_desc; | ||
209 | const struct firmware *fecs_sig = NULL; | ||
210 | int err; | ||
211 | |||
212 | switch (ver) { | ||
213 | case NVGPU_GPUID_GP104: | ||
214 | fecs_sig = nvgpu_request_firmware(g, | ||
215 | GP104_FECS_UCODE_SIG, | ||
216 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
217 | break; | ||
218 | case NVGPU_GPUID_GP106: | ||
219 | fecs_sig = nvgpu_request_firmware(g, | ||
220 | GP106_FECS_UCODE_SIG, | ||
221 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
222 | break; | ||
223 | default: | ||
224 | gk20a_err(g->dev, "no support for GPUID %x", ver); | ||
225 | } | ||
226 | |||
227 | if (!fecs_sig) { | ||
228 | gk20a_err(dev_from_gk20a(g), "failed to load fecs sig"); | ||
229 | return -ENOENT; | ||
230 | } | ||
231 | lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc_v1), GFP_KERNEL); | ||
232 | if (!lsf_desc) { | ||
233 | err = -ENOMEM; | ||
234 | goto rel_sig; | ||
235 | } | ||
236 | memcpy(lsf_desc, (void *)fecs_sig->data, sizeof(struct lsf_ucode_desc_v1)); | ||
237 | lsf_desc->falcon_id = LSF_FALCON_ID_FECS; | ||
238 | |||
239 | p_img->desc = kzalloc(sizeof(struct pmu_ucode_desc_v1), GFP_KERNEL); | ||
240 | if (p_img->desc == NULL) { | ||
241 | err = -ENOMEM; | ||
242 | goto free_lsf_desc; | ||
243 | } | ||
244 | |||
245 | p_img->desc->bootloader_start_offset = | ||
246 | g->ctxsw_ucode_info.fecs.boot.offset; | ||
247 | p_img->desc->bootloader_size = | ||
248 | ALIGN(g->ctxsw_ucode_info.fecs.boot.size, 256); | ||
249 | p_img->desc->bootloader_imem_offset = | ||
250 | g->ctxsw_ucode_info.fecs.boot_imem_offset; | ||
251 | p_img->desc->bootloader_entry_point = | ||
252 | g->ctxsw_ucode_info.fecs.boot_entry; | ||
253 | |||
254 | p_img->desc->image_size = | ||
255 | ALIGN(g->ctxsw_ucode_info.fecs.boot.size, 256) + | ||
256 | ALIGN(g->ctxsw_ucode_info.fecs.code.size, 256) + | ||
257 | ALIGN(g->ctxsw_ucode_info.fecs.data.size, 256); | ||
258 | p_img->desc->app_size = ALIGN(g->ctxsw_ucode_info.fecs.code.size, 256) + | ||
259 | ALIGN(g->ctxsw_ucode_info.fecs.data.size, 256); | ||
260 | p_img->desc->app_start_offset = g->ctxsw_ucode_info.fecs.code.offset; | ||
261 | p_img->desc->app_imem_offset = 0; | ||
262 | p_img->desc->app_imem_entry = 0; | ||
263 | p_img->desc->app_dmem_offset = 0; | ||
264 | p_img->desc->app_resident_code_offset = 0; | ||
265 | p_img->desc->app_resident_code_size = | ||
266 | g->ctxsw_ucode_info.fecs.code.size; | ||
267 | p_img->desc->app_resident_data_offset = | ||
268 | g->ctxsw_ucode_info.fecs.data.offset - | ||
269 | g->ctxsw_ucode_info.fecs.code.offset; | ||
270 | p_img->desc->app_resident_data_size = | ||
271 | g->ctxsw_ucode_info.fecs.data.size; | ||
272 | p_img->data = g->ctxsw_ucode_info.surface_desc.cpu_va; | ||
273 | p_img->data_size = p_img->desc->image_size; | ||
274 | |||
275 | p_img->fw_ver = NULL; | ||
276 | p_img->header = NULL; | ||
277 | p_img->lsf_desc = (struct lsf_ucode_desc_v1 *)lsf_desc; | ||
278 | gp106_dbg_pmu("fecs fw loaded\n"); | ||
279 | release_firmware(fecs_sig); | ||
280 | return 0; | ||
281 | free_lsf_desc: | ||
282 | kfree(lsf_desc); | ||
283 | rel_sig: | ||
284 | release_firmware(fecs_sig); | ||
285 | return err; | ||
286 | } | ||
287 | |||
288 | static int gpccs_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img) | ||
289 | { | ||
290 | u32 ver = g->gpu_characteristics.arch + g->gpu_characteristics.impl; | ||
291 | struct lsf_ucode_desc_v1 *lsf_desc; | ||
292 | const struct firmware *gpccs_sig = NULL; | ||
293 | int err; | ||
294 | |||
295 | if (g->ops.securegpccs == false) | ||
296 | return -ENOENT; | ||
297 | |||
298 | switch (ver) { | ||
299 | case NVGPU_GPUID_GP104: | ||
300 | gpccs_sig = nvgpu_request_firmware(g, | ||
301 | GP104_GPCCS_UCODE_SIG, | ||
302 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
303 | break; | ||
304 | case NVGPU_GPUID_GP106: | ||
305 | gpccs_sig = nvgpu_request_firmware(g, | ||
306 | GP106_GPCCS_UCODE_SIG, | ||
307 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
308 | break; | ||
309 | default: | ||
310 | gk20a_err(g->dev, "no support for GPUID %x", ver); | ||
311 | } | ||
312 | |||
313 | if (!gpccs_sig) { | ||
314 | gk20a_err(dev_from_gk20a(g), "failed to load gpccs sig"); | ||
315 | return -ENOENT; | ||
316 | } | ||
317 | lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc_v1), GFP_KERNEL); | ||
318 | if (!lsf_desc) { | ||
319 | err = -ENOMEM; | ||
320 | goto rel_sig; | ||
321 | } | ||
322 | memcpy(lsf_desc, (void *)gpccs_sig->data, | ||
323 | sizeof(struct lsf_ucode_desc_v1)); | ||
324 | lsf_desc->falcon_id = LSF_FALCON_ID_GPCCS; | ||
325 | |||
326 | p_img->desc = kzalloc(sizeof(struct pmu_ucode_desc_v1), GFP_KERNEL); | ||
327 | if (p_img->desc == NULL) { | ||
328 | err = -ENOMEM; | ||
329 | goto free_lsf_desc; | ||
330 | } | ||
331 | |||
332 | p_img->desc->bootloader_start_offset = | ||
333 | 0; | ||
334 | p_img->desc->bootloader_size = | ||
335 | ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256); | ||
336 | p_img->desc->bootloader_imem_offset = | ||
337 | g->ctxsw_ucode_info.gpccs.boot_imem_offset; | ||
338 | p_img->desc->bootloader_entry_point = | ||
339 | g->ctxsw_ucode_info.gpccs.boot_entry; | ||
340 | |||
341 | p_img->desc->image_size = | ||
342 | ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256) + | ||
343 | ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) + | ||
344 | ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); | ||
345 | p_img->desc->app_size = ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) | ||
346 | + ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); | ||
347 | p_img->desc->app_start_offset = p_img->desc->bootloader_size; | ||
348 | p_img->desc->app_imem_offset = 0; | ||
349 | p_img->desc->app_imem_entry = 0; | ||
350 | p_img->desc->app_dmem_offset = 0; | ||
351 | p_img->desc->app_resident_code_offset = 0; | ||
352 | p_img->desc->app_resident_code_size = | ||
353 | ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256); | ||
354 | p_img->desc->app_resident_data_offset = | ||
355 | ALIGN(g->ctxsw_ucode_info.gpccs.data.offset, 256) - | ||
356 | ALIGN(g->ctxsw_ucode_info.gpccs.code.offset, 256); | ||
357 | p_img->desc->app_resident_data_size = | ||
358 | ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); | ||
359 | p_img->data = (u32 *)((u8 *)g->ctxsw_ucode_info.surface_desc.cpu_va + | ||
360 | g->ctxsw_ucode_info.gpccs.boot.offset); | ||
361 | p_img->data_size = ALIGN(p_img->desc->image_size, 256); | ||
362 | p_img->fw_ver = NULL; | ||
363 | p_img->header = NULL; | ||
364 | p_img->lsf_desc = (struct lsf_ucode_desc_v1 *)lsf_desc; | ||
365 | gp106_dbg_pmu("gpccs fw loaded\n"); | ||
366 | release_firmware(gpccs_sig); | ||
367 | return 0; | ||
368 | free_lsf_desc: | ||
369 | kfree(lsf_desc); | ||
370 | rel_sig: | ||
371 | release_firmware(gpccs_sig); | ||
372 | return err; | ||
373 | } | ||
374 | |||
375 | static int gp106_prepare_ucode_blob(struct gk20a *g) | ||
376 | { | ||
377 | |||
378 | int err; | ||
379 | struct ls_flcn_mgr_v1 lsfm_l, *plsfm; | ||
380 | struct pmu_gk20a *pmu = &g->pmu; | ||
381 | struct wpr_carveout_info wpr_inf; | ||
382 | |||
383 | if (g->acr.ucode_blob.cpu_va) { | ||
384 | /*Recovery case, we do not need to form | ||
385 | non WPR blob of ucodes*/ | ||
386 | err = gk20a_init_pmu(pmu); | ||
387 | if (err) { | ||
388 | gp106_dbg_pmu("failed to set function pointers\n"); | ||
389 | return err; | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | plsfm = &lsfm_l; | ||
394 | memset((void *)plsfm, 0, sizeof(struct ls_flcn_mgr_v1)); | ||
395 | gp106_dbg_pmu("fetching GMMU regs\n"); | ||
396 | gm20b_mm_mmu_vpr_info_fetch(g); | ||
397 | gr_gk20a_init_ctxsw_ucode(g); | ||
398 | |||
399 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
400 | gp106_dbg_pmu("wpr carveout base:%llx\n", (wpr_inf.wpr_base)); | ||
401 | gp106_dbg_pmu("wpr carveout size :%x\n", (u32)wpr_inf.size); | ||
402 | |||
403 | /* Discover all managed falcons*/ | ||
404 | err = lsfm_discover_ucode_images(g, plsfm); | ||
405 | gp106_dbg_pmu(" Managed Falcon cnt %d\n", plsfm->managed_flcn_cnt); | ||
406 | if (err) | ||
407 | goto exit_err; | ||
408 | |||
409 | if (plsfm->managed_flcn_cnt && !g->acr.ucode_blob.cpu_va) { | ||
410 | /* Generate WPR requirements*/ | ||
411 | err = lsf_gen_wpr_requirements(g, plsfm); | ||
412 | if (err) | ||
413 | goto exit_err; | ||
414 | |||
415 | /*Alloc memory to hold ucode blob contents*/ | ||
416 | err = g->ops.pmu.alloc_blob_space(g, plsfm->wpr_size | ||
417 | ,&g->acr.ucode_blob); | ||
418 | if (err) | ||
419 | goto exit_err; | ||
420 | |||
421 | gp106_dbg_pmu("managed LS falcon %d, WPR size %d bytes.\n", | ||
422 | plsfm->managed_flcn_cnt, plsfm->wpr_size); | ||
423 | |||
424 | lsfm_init_wpr_contents(g, plsfm, &g->acr.ucode_blob); | ||
425 | } else { | ||
426 | gp106_dbg_pmu("LSFM is managing no falcons.\n"); | ||
427 | } | ||
428 | gp106_dbg_pmu("prepare ucode blob return 0\n"); | ||
429 | free_acr_resources(g, plsfm); | ||
430 | |||
431 | exit_err: | ||
432 | return err; | ||
433 | } | ||
434 | |||
435 | static u8 lsfm_falcon_disabled(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm, | ||
436 | u32 falcon_id) | ||
437 | { | ||
438 | return (plsfm->disable_mask >> falcon_id) & 0x1; | ||
439 | } | ||
440 | |||
441 | /* Discover all managed falcon ucode images */ | ||
442 | static int lsfm_discover_ucode_images(struct gk20a *g, | ||
443 | struct ls_flcn_mgr_v1 *plsfm) | ||
444 | { | ||
445 | struct pmu_gk20a *pmu = &g->pmu; | ||
446 | struct flcn_ucode_img_v1 ucode_img; | ||
447 | u32 falcon_id; | ||
448 | u32 i; | ||
449 | int status; | ||
450 | |||
451 | /* LSFM requires a secure PMU, discover it first.*/ | ||
452 | /* Obtain the PMU ucode image and add it to the list if required*/ | ||
453 | memset(&ucode_img, 0, sizeof(ucode_img)); | ||
454 | status = pmu_ucode_details(g, &ucode_img); | ||
455 | if (status == 0) { | ||
456 | if (ucode_img.lsf_desc != NULL) { | ||
457 | /* The falon_id is formed by grabbing the static base | ||
458 | * falon_id from the image and adding the | ||
459 | * engine-designated falcon instance.*/ | ||
460 | pmu->pmu_mode |= PMU_SECURE_MODE; | ||
461 | falcon_id = ucode_img.lsf_desc->falcon_id + | ||
462 | ucode_img.flcn_inst; | ||
463 | |||
464 | if (!lsfm_falcon_disabled(g, plsfm, falcon_id)) { | ||
465 | pmu->falcon_id = falcon_id; | ||
466 | if (lsfm_add_ucode_img(g, plsfm, &ucode_img, | ||
467 | pmu->falcon_id) == 0) | ||
468 | pmu->pmu_mode |= PMU_LSFM_MANAGED; | ||
469 | |||
470 | plsfm->managed_flcn_cnt++; | ||
471 | } else { | ||
472 | gp106_dbg_pmu("id not managed %d\n", | ||
473 | ucode_img.lsf_desc->falcon_id); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /*Free any ucode image resources if not managing this falcon*/ | ||
478 | if (!(pmu->pmu_mode & PMU_LSFM_MANAGED)) { | ||
479 | gp106_dbg_pmu("pmu is not LSFM managed\n"); | ||
480 | lsfm_free_ucode_img_res(&ucode_img); | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /* Enumerate all constructed falcon objects, | ||
485 | as we need the ucode image info and total falcon count.*/ | ||
486 | |||
487 | /*0th index is always PMU which is already handled in earlier | ||
488 | if condition*/ | ||
489 | for (i = 1; i < (MAX_SUPPORTED_LSFM); i++) { | ||
490 | memset(&ucode_img, 0, sizeof(ucode_img)); | ||
491 | if (pmu_acr_supp_ucode_list[i](g, &ucode_img) == 0) { | ||
492 | if (ucode_img.lsf_desc != NULL) { | ||
493 | /* We have engine sigs, ensure that this falcon | ||
494 | is aware of the secure mode expectations | ||
495 | (ACR status)*/ | ||
496 | |||
497 | /* falon_id is formed by grabbing the static | ||
498 | base falonId from the image and adding the | ||
499 | engine-designated falcon instance. */ | ||
500 | falcon_id = ucode_img.lsf_desc->falcon_id + | ||
501 | ucode_img.flcn_inst; | ||
502 | |||
503 | if (!lsfm_falcon_disabled(g, plsfm, | ||
504 | falcon_id)) { | ||
505 | /* Do not manage non-FB ucode*/ | ||
506 | if (lsfm_add_ucode_img(g, | ||
507 | plsfm, &ucode_img, falcon_id) | ||
508 | == 0) | ||
509 | plsfm->managed_flcn_cnt++; | ||
510 | } else { | ||
511 | gp106_dbg_pmu("not managed %d\n", | ||
512 | ucode_img.lsf_desc->falcon_id); | ||
513 | lsfm_free_nonpmu_ucode_img_res( | ||
514 | &ucode_img); | ||
515 | } | ||
516 | } | ||
517 | } else { | ||
518 | /* Consumed all available falcon objects */ | ||
519 | gp106_dbg_pmu("Done checking for ucodes %d\n", i); | ||
520 | break; | ||
521 | } | ||
522 | } | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int gp106_pmu_populate_loader_cfg(struct gk20a *g, | ||
527 | void *lsfm, u32 *p_bl_gen_desc_size) | ||
528 | { | ||
529 | struct wpr_carveout_info wpr_inf; | ||
530 | struct pmu_gk20a *pmu = &g->pmu; | ||
531 | struct lsfm_managed_ucode_img_v2 *p_lsfm = | ||
532 | (struct lsfm_managed_ucode_img_v2 *)lsfm; | ||
533 | struct flcn_ucode_img_v1 *p_img = &(p_lsfm->ucode_img); | ||
534 | struct flcn_bl_dmem_desc_v1 *ldr_cfg = | ||
535 | &(p_lsfm->bl_gen_desc.bl_dmem_desc_v1); | ||
536 | u64 addr_base; | ||
537 | struct pmu_ucode_desc_v1 *desc; | ||
538 | u64 addr_code, addr_data; | ||
539 | u32 addr_args; | ||
540 | |||
541 | if (p_img->desc == NULL) /*This means its a header based ucode, | ||
542 | and so we do not fill BL gen desc structure*/ | ||
543 | return -EINVAL; | ||
544 | desc = p_img->desc; | ||
545 | /* | ||
546 | Calculate physical and virtual addresses for various portions of | ||
547 | the PMU ucode image | ||
548 | Calculate the 32-bit addresses for the application code, application | ||
549 | data, and bootloader code. These values are all based on IM_BASE. | ||
550 | The 32-bit addresses will be the upper 32-bits of the virtual or | ||
551 | physical addresses of each respective segment. | ||
552 | */ | ||
553 | addr_base = p_lsfm->lsb_header.ucode_off; | ||
554 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
555 | addr_base += (wpr_inf.wpr_base); | ||
556 | |||
557 | gp106_dbg_pmu("pmu loader cfg u32 addrbase %x\n", (u32)addr_base); | ||
558 | /*From linux*/ | ||
559 | addr_code = u64_lo32((addr_base + | ||
560 | desc->app_start_offset + | ||
561 | desc->app_resident_code_offset) ); | ||
562 | gp106_dbg_pmu("app start %d app res code off %d\n", | ||
563 | desc->app_start_offset, desc->app_resident_code_offset); | ||
564 | addr_data = u64_lo32((addr_base + | ||
565 | desc->app_start_offset + | ||
566 | desc->app_resident_data_offset) ); | ||
567 | gp106_dbg_pmu("app res data offset%d\n", | ||
568 | desc->app_resident_data_offset); | ||
569 | gp106_dbg_pmu("bl start off %d\n", desc->bootloader_start_offset); | ||
570 | |||
571 | addr_args = ((pwr_falcon_hwcfg_dmem_size_v( | ||
572 | gk20a_readl(g, pwr_falcon_hwcfg_r()))) | ||
573 | << GK20A_PMU_DMEM_BLKSIZE2); | ||
574 | |||
575 | addr_args -= g->ops.pmu_ver.get_pmu_cmdline_args_size(pmu); | ||
576 | |||
577 | gp106_dbg_pmu("addr_args %x\n", addr_args); | ||
578 | |||
579 | /* Populate the LOADER_CONFIG state */ | ||
580 | memset((void *) ldr_cfg, 0, sizeof(struct flcn_bl_dmem_desc_v1)); | ||
581 | ldr_cfg->ctx_dma = GK20A_PMU_DMAIDX_UCODE; | ||
582 | flcn64_set_dma(&ldr_cfg->code_dma_base, addr_code); | ||
583 | ldr_cfg->non_sec_code_off = desc->app_resident_code_offset; | ||
584 | ldr_cfg->non_sec_code_size = desc->app_resident_code_size; | ||
585 | flcn64_set_dma(&ldr_cfg->data_dma_base, addr_data); | ||
586 | ldr_cfg->data_size = desc->app_resident_data_size; | ||
587 | ldr_cfg->code_entry_point = desc->app_imem_entry; | ||
588 | |||
589 | /* Update the argc/argv members*/ | ||
590 | ldr_cfg->argc = 1; | ||
591 | ldr_cfg->argv = addr_args; | ||
592 | |||
593 | *p_bl_gen_desc_size = sizeof(struct flcn_bl_dmem_desc_v1); | ||
594 | |||
595 | g->acr.pmu_args = addr_args; | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int gp106_flcn_populate_bl_dmem_desc(struct gk20a *g, | ||
600 | void *lsfm, u32 *p_bl_gen_desc_size, u32 falconid) | ||
601 | { | ||
602 | struct wpr_carveout_info wpr_inf; | ||
603 | struct lsfm_managed_ucode_img_v2 *p_lsfm = | ||
604 | (struct lsfm_managed_ucode_img_v2 *)lsfm; | ||
605 | struct flcn_ucode_img_v1 *p_img = &(p_lsfm->ucode_img); | ||
606 | struct flcn_bl_dmem_desc_v1 *ldr_cfg = | ||
607 | &(p_lsfm->bl_gen_desc.bl_dmem_desc_v1); | ||
608 | u64 addr_base; | ||
609 | struct pmu_ucode_desc_v1 *desc; | ||
610 | u64 addr_code, addr_data; | ||
611 | |||
612 | if (p_img->desc == NULL) /*This means its a header based ucode, | ||
613 | and so we do not fill BL gen desc structure*/ | ||
614 | return -EINVAL; | ||
615 | desc = p_img->desc; | ||
616 | |||
617 | /* | ||
618 | Calculate physical and virtual addresses for various portions of | ||
619 | the PMU ucode image | ||
620 | Calculate the 32-bit addresses for the application code, application | ||
621 | data, and bootloader code. These values are all based on IM_BASE. | ||
622 | The 32-bit addresses will be the upper 32-bits of the virtual or | ||
623 | physical addresses of each respective segment. | ||
624 | */ | ||
625 | addr_base = p_lsfm->lsb_header.ucode_off; | ||
626 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
627 | addr_base += (wpr_inf.wpr_base); | ||
628 | |||
629 | gp106_dbg_pmu("gen loader cfg %x u32 addrbase %x ID\n", (u32)addr_base, | ||
630 | p_lsfm->wpr_header.falcon_id); | ||
631 | addr_code = u64_lo32((addr_base + | ||
632 | desc->app_start_offset + | ||
633 | desc->app_resident_code_offset) ); | ||
634 | addr_data = u64_lo32((addr_base + | ||
635 | desc->app_start_offset + | ||
636 | desc->app_resident_data_offset) ); | ||
637 | |||
638 | gp106_dbg_pmu("gen cfg %x u32 addrcode %x & data %x load offset %xID\n", | ||
639 | (u32)addr_code, (u32)addr_data, desc->bootloader_start_offset, | ||
640 | p_lsfm->wpr_header.falcon_id); | ||
641 | |||
642 | /* Populate the LOADER_CONFIG state */ | ||
643 | memset((void *) ldr_cfg, 0, sizeof(struct flcn_bl_dmem_desc_v1)); | ||
644 | ldr_cfg->ctx_dma = GK20A_PMU_DMAIDX_UCODE; | ||
645 | flcn64_set_dma(&ldr_cfg->code_dma_base, addr_code); | ||
646 | ldr_cfg->non_sec_code_size = desc->app_resident_code_size; | ||
647 | flcn64_set_dma(&ldr_cfg->data_dma_base, addr_data); | ||
648 | ldr_cfg->data_size = desc->app_resident_data_size; | ||
649 | ldr_cfg->code_entry_point = desc->app_imem_entry; | ||
650 | |||
651 | *p_bl_gen_desc_size = sizeof(struct flcn_bl_dmem_desc_v1); | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* Populate falcon boot loader generic desc.*/ | ||
656 | static int lsfm_fill_flcn_bl_gen_desc(struct gk20a *g, | ||
657 | struct lsfm_managed_ucode_img_v2 *pnode) | ||
658 | { | ||
659 | |||
660 | struct pmu_gk20a *pmu = &g->pmu; | ||
661 | if (pnode->wpr_header.falcon_id != pmu->falcon_id) { | ||
662 | gp106_dbg_pmu("non pmu. write flcn bl gen desc\n"); | ||
663 | g->ops.pmu.flcn_populate_bl_dmem_desc(g, | ||
664 | pnode, &pnode->bl_gen_desc_size, | ||
665 | pnode->wpr_header.falcon_id); | ||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | if (pmu->pmu_mode & PMU_LSFM_MANAGED) { | ||
670 | gp106_dbg_pmu("pmu write flcn bl gen desc\n"); | ||
671 | if (pnode->wpr_header.falcon_id == pmu->falcon_id) | ||
672 | return g->ops.pmu.pmu_populate_loader_cfg(g, pnode, | ||
673 | &pnode->bl_gen_desc_size); | ||
674 | } | ||
675 | |||
676 | /* Failed to find the falcon requested. */ | ||
677 | return -ENOENT; | ||
678 | } | ||
679 | |||
680 | /* Initialize WPR contents */ | ||
681 | static void lsfm_init_wpr_contents(struct gk20a *g, | ||
682 | struct ls_flcn_mgr_v1 *plsfm, struct mem_desc *ucode) | ||
683 | { | ||
684 | struct lsfm_managed_ucode_img_v2 *pnode = plsfm->ucode_img_list; | ||
685 | u32 i; | ||
686 | |||
687 | /* The WPR array is at the base of the WPR */ | ||
688 | pnode = plsfm->ucode_img_list; | ||
689 | i = 0; | ||
690 | |||
691 | /* | ||
692 | * Walk the managed falcons, flush WPR and LSB headers to FB. | ||
693 | * flush any bl args to the storage area relative to the | ||
694 | * ucode image (appended on the end as a DMEM area). | ||
695 | */ | ||
696 | while (pnode) { | ||
697 | /* Flush WPR header to memory*/ | ||
698 | gk20a_mem_wr_n(g, ucode, i * sizeof(pnode->wpr_header), | ||
699 | &pnode->wpr_header, sizeof(pnode->wpr_header)); | ||
700 | |||
701 | gp106_dbg_pmu("wpr header"); | ||
702 | gp106_dbg_pmu("falconid :%d", | ||
703 | pnode->wpr_header.falcon_id); | ||
704 | gp106_dbg_pmu("lsb_offset :%x", | ||
705 | pnode->wpr_header.lsb_offset); | ||
706 | gp106_dbg_pmu("bootstrap_owner :%d", | ||
707 | pnode->wpr_header.bootstrap_owner); | ||
708 | gp106_dbg_pmu("lazy_bootstrap :%d", | ||
709 | pnode->wpr_header.lazy_bootstrap); | ||
710 | gp106_dbg_pmu("status :%d", | ||
711 | pnode->wpr_header.status); | ||
712 | |||
713 | /*Flush LSB header to memory*/ | ||
714 | gk20a_mem_wr_n(g, ucode, pnode->wpr_header.lsb_offset, | ||
715 | &pnode->lsb_header, sizeof(pnode->lsb_header)); | ||
716 | |||
717 | gp106_dbg_pmu("lsb header"); | ||
718 | gp106_dbg_pmu("ucode_off :%x", | ||
719 | pnode->lsb_header.ucode_off); | ||
720 | gp106_dbg_pmu("ucode_size :%x", | ||
721 | pnode->lsb_header.ucode_size); | ||
722 | gp106_dbg_pmu("data_size :%x", | ||
723 | pnode->lsb_header.data_size); | ||
724 | gp106_dbg_pmu("bl_code_size :%x", | ||
725 | pnode->lsb_header.bl_code_size); | ||
726 | gp106_dbg_pmu("bl_imem_off :%x", | ||
727 | pnode->lsb_header.bl_imem_off); | ||
728 | gp106_dbg_pmu("bl_data_off :%x", | ||
729 | pnode->lsb_header.bl_data_off); | ||
730 | gp106_dbg_pmu("bl_data_size :%x", | ||
731 | pnode->lsb_header.bl_data_size); | ||
732 | gp106_dbg_pmu("app_code_off :%x", | ||
733 | pnode->lsb_header.app_code_off); | ||
734 | gp106_dbg_pmu("app_code_size :%x", | ||
735 | pnode->lsb_header.app_code_size); | ||
736 | gp106_dbg_pmu("app_data_off :%x", | ||
737 | pnode->lsb_header.app_data_off); | ||
738 | gp106_dbg_pmu("app_data_size :%x", | ||
739 | pnode->lsb_header.app_data_size); | ||
740 | gp106_dbg_pmu("flags :%x", | ||
741 | pnode->lsb_header.flags); | ||
742 | |||
743 | /*If this falcon has a boot loader and related args, | ||
744 | * flush them.*/ | ||
745 | if (!pnode->ucode_img.header) { | ||
746 | /*Populate gen bl and flush to memory*/ | ||
747 | lsfm_fill_flcn_bl_gen_desc(g, pnode); | ||
748 | gk20a_mem_wr_n(g, ucode, | ||
749 | pnode->lsb_header.bl_data_off, | ||
750 | &pnode->bl_gen_desc, | ||
751 | pnode->bl_gen_desc_size); | ||
752 | } | ||
753 | /*Copying of ucode*/ | ||
754 | gk20a_mem_wr_n(g, ucode, pnode->lsb_header.ucode_off, | ||
755 | pnode->ucode_img.data, | ||
756 | pnode->ucode_img.data_size); | ||
757 | pnode = pnode->next; | ||
758 | i++; | ||
759 | } | ||
760 | |||
761 | /* Tag the terminator WPR header with an invalid falcon ID. */ | ||
762 | gk20a_mem_wr32(g, ucode, | ||
763 | plsfm->managed_flcn_cnt * sizeof(struct lsf_wpr_header) + | ||
764 | offsetof(struct lsf_wpr_header, falcon_id), | ||
765 | LSF_FALCON_ID_INVALID); | ||
766 | } | ||
767 | |||
768 | /*! | ||
769 | * lsfm_parse_no_loader_ucode: parses UCODE header of falcon | ||
770 | * | ||
771 | * @param[in] p_ucodehdr : UCODE header | ||
772 | * @param[out] lsb_hdr : updates values in LSB header | ||
773 | * | ||
774 | * @return 0 | ||
775 | */ | ||
776 | static int lsfm_parse_no_loader_ucode(u32 *p_ucodehdr, | ||
777 | struct lsf_lsb_header_v1 *lsb_hdr) | ||
778 | { | ||
779 | |||
780 | u32 code_size = 0; | ||
781 | u32 data_size = 0; | ||
782 | u32 i = 0; | ||
783 | u32 total_apps = p_ucodehdr[FLCN_NL_UCODE_HDR_NUM_APPS_IND]; | ||
784 | |||
785 | /* Lets calculate code size*/ | ||
786 | code_size += p_ucodehdr[FLCN_NL_UCODE_HDR_OS_CODE_SIZE_IND]; | ||
787 | for (i = 0; i < total_apps; i++) { | ||
788 | code_size += p_ucodehdr[FLCN_NL_UCODE_HDR_APP_CODE_SIZE_IND | ||
789 | (total_apps, i)]; | ||
790 | } | ||
791 | code_size += p_ucodehdr[FLCN_NL_UCODE_HDR_OS_OVL_SIZE_IND(total_apps)]; | ||
792 | |||
793 | /* Calculate data size*/ | ||
794 | data_size += p_ucodehdr[FLCN_NL_UCODE_HDR_OS_DATA_SIZE_IND]; | ||
795 | for (i = 0; i < total_apps; i++) { | ||
796 | data_size += p_ucodehdr[FLCN_NL_UCODE_HDR_APP_DATA_SIZE_IND | ||
797 | (total_apps, i)]; | ||
798 | } | ||
799 | |||
800 | lsb_hdr->ucode_size = code_size; | ||
801 | lsb_hdr->data_size = data_size; | ||
802 | lsb_hdr->bl_code_size = p_ucodehdr[FLCN_NL_UCODE_HDR_OS_CODE_SIZE_IND]; | ||
803 | lsb_hdr->bl_imem_off = 0; | ||
804 | lsb_hdr->bl_data_off = p_ucodehdr[FLCN_NL_UCODE_HDR_OS_DATA_OFF_IND]; | ||
805 | lsb_hdr->bl_data_size = p_ucodehdr[FLCN_NL_UCODE_HDR_OS_DATA_SIZE_IND]; | ||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | /*! | ||
810 | * @brief lsfm_fill_static_lsb_hdr_info | ||
811 | * Populate static LSB header infomation using the provided ucode image | ||
812 | */ | ||
813 | static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g, | ||
814 | u32 falcon_id, struct lsfm_managed_ucode_img_v2 *pnode) | ||
815 | { | ||
816 | |||
817 | struct pmu_gk20a *pmu = &g->pmu; | ||
818 | u32 full_app_size = 0; | ||
819 | u32 data = 0; | ||
820 | |||
821 | if (pnode->ucode_img.lsf_desc) | ||
822 | memcpy(&pnode->lsb_header.signature, pnode->ucode_img.lsf_desc, | ||
823 | sizeof(struct lsf_ucode_desc_v1)); | ||
824 | pnode->lsb_header.ucode_size = pnode->ucode_img.data_size; | ||
825 | |||
826 | /* The remainder of the LSB depends on the loader usage */ | ||
827 | if (pnode->ucode_img.header) { | ||
828 | /* Does not use a loader */ | ||
829 | pnode->lsb_header.data_size = 0; | ||
830 | pnode->lsb_header.bl_code_size = 0; | ||
831 | pnode->lsb_header.bl_data_off = 0; | ||
832 | pnode->lsb_header.bl_data_size = 0; | ||
833 | |||
834 | lsfm_parse_no_loader_ucode(pnode->ucode_img.header, | ||
835 | &(pnode->lsb_header)); | ||
836 | |||
837 | /* Load the first 256 bytes of IMEM. */ | ||
838 | /* Set LOAD_CODE_AT_0 and DMACTL_REQ_CTX. | ||
839 | True for all method based falcons */ | ||
840 | data = NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0_TRUE | | ||
841 | NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE; | ||
842 | pnode->lsb_header.flags = data; | ||
843 | } else { | ||
844 | /* Uses a loader. that is has a desc */ | ||
845 | pnode->lsb_header.data_size = 0; | ||
846 | |||
847 | /* The loader code size is already aligned (padded) such that | ||
848 | the code following it is aligned, but the size in the image | ||
849 | desc is not, bloat it up to be on a 256 byte alignment. */ | ||
850 | pnode->lsb_header.bl_code_size = ALIGN( | ||
851 | pnode->ucode_img.desc->bootloader_size, | ||
852 | LSF_BL_CODE_SIZE_ALIGNMENT); | ||
853 | full_app_size = ALIGN(pnode->ucode_img.desc->app_size, | ||
854 | LSF_BL_CODE_SIZE_ALIGNMENT) + | ||
855 | pnode->lsb_header.bl_code_size; | ||
856 | pnode->lsb_header.ucode_size = ALIGN( | ||
857 | pnode->ucode_img.desc->app_resident_data_offset, | ||
858 | LSF_BL_CODE_SIZE_ALIGNMENT) + | ||
859 | pnode->lsb_header.bl_code_size; | ||
860 | pnode->lsb_header.data_size = full_app_size - | ||
861 | pnode->lsb_header.ucode_size; | ||
862 | /* Though the BL is located at 0th offset of the image, the VA | ||
863 | is different to make sure that it doesnt collide the actual OS | ||
864 | VA range */ | ||
865 | pnode->lsb_header.bl_imem_off = | ||
866 | pnode->ucode_img.desc->bootloader_imem_offset; | ||
867 | |||
868 | /* TODO: OBJFLCN should export properties using which the below | ||
869 | flags should be populated.*/ | ||
870 | pnode->lsb_header.flags = 0; | ||
871 | |||
872 | if (falcon_id == pmu->falcon_id) { | ||
873 | data = NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE; | ||
874 | pnode->lsb_header.flags = data; | ||
875 | } | ||
876 | |||
877 | if(g->ops.pmu.is_priv_load(falcon_id)) | ||
878 | pnode->lsb_header.flags |= | ||
879 | NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE; | ||
880 | } | ||
881 | } | ||
882 | |||
883 | /* Adds a ucode image to the list of managed ucode images managed. */ | ||
884 | static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm, | ||
885 | struct flcn_ucode_img_v1 *ucode_image, u32 falcon_id) | ||
886 | { | ||
887 | struct lsfm_managed_ucode_img_v2 *pnode; | ||
888 | |||
889 | pnode = kzalloc(sizeof(struct lsfm_managed_ucode_img_v2), GFP_KERNEL); | ||
890 | if (pnode == NULL) | ||
891 | return -ENOMEM; | ||
892 | |||
893 | /* Keep a copy of the ucode image info locally */ | ||
894 | memcpy(&pnode->ucode_img, ucode_image, sizeof(struct flcn_ucode_img_v1)); | ||
895 | |||
896 | /* Fill in static WPR header info*/ | ||
897 | pnode->wpr_header.falcon_id = falcon_id; | ||
898 | pnode->wpr_header.bootstrap_owner = 0x07; //LSF_BOOTSTRAP_OWNER_DEFAULT; | ||
899 | pnode->wpr_header.status = LSF_IMAGE_STATUS_COPY; | ||
900 | |||
901 | pnode->wpr_header.lazy_bootstrap = | ||
902 | g->ops.pmu.is_lazy_bootstrap(falcon_id); | ||
903 | |||
904 | /*TODO to check if PDB_PROP_FLCN_LAZY_BOOTSTRAP is to be supported by | ||
905 | Android */ | ||
906 | /* Fill in static LSB header info elsewhere */ | ||
907 | lsfm_fill_static_lsb_hdr_info(g, falcon_id, pnode); | ||
908 | pnode->wpr_header.bin_version = pnode->lsb_header.signature.version; | ||
909 | pnode->next = plsfm->ucode_img_list; | ||
910 | plsfm->ucode_img_list = pnode; | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | /* Free any ucode image structure resources*/ | ||
915 | static void lsfm_free_ucode_img_res(struct flcn_ucode_img_v1 *p_img) | ||
916 | { | ||
917 | if (p_img->lsf_desc != NULL) { | ||
918 | kfree(p_img->lsf_desc); | ||
919 | p_img->lsf_desc = NULL; | ||
920 | } | ||
921 | } | ||
922 | |||
923 | /* Free any ucode image structure resources*/ | ||
924 | static void lsfm_free_nonpmu_ucode_img_res(struct flcn_ucode_img_v1 *p_img) | ||
925 | { | ||
926 | if (p_img->lsf_desc != NULL) { | ||
927 | kfree(p_img->lsf_desc); | ||
928 | p_img->lsf_desc = NULL; | ||
929 | } | ||
930 | if (p_img->desc != NULL) { | ||
931 | kfree(p_img->desc); | ||
932 | p_img->desc = NULL; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm) | ||
937 | { | ||
938 | u32 cnt = plsfm->managed_flcn_cnt; | ||
939 | struct lsfm_managed_ucode_img_v2 *mg_ucode_img; | ||
940 | |||
941 | while (cnt) { | ||
942 | mg_ucode_img = plsfm->ucode_img_list; | ||
943 | if (mg_ucode_img->ucode_img.lsf_desc->falcon_id == | ||
944 | LSF_FALCON_ID_PMU) | ||
945 | lsfm_free_ucode_img_res(&mg_ucode_img->ucode_img); | ||
946 | else | ||
947 | lsfm_free_nonpmu_ucode_img_res( | ||
948 | &mg_ucode_img->ucode_img); | ||
949 | plsfm->ucode_img_list = mg_ucode_img->next; | ||
950 | kfree(mg_ucode_img); | ||
951 | cnt--; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | /* Generate WPR requirements for ACR allocation request */ | ||
956 | static int lsf_gen_wpr_requirements(struct gk20a *g, | ||
957 | struct ls_flcn_mgr_v1 *plsfm) | ||
958 | { | ||
959 | struct lsfm_managed_ucode_img_v2 *pnode = plsfm->ucode_img_list; | ||
960 | u32 wpr_offset; | ||
961 | |||
962 | /* Calculate WPR size required */ | ||
963 | |||
964 | /* Start with an array of WPR headers at the base of the WPR. | ||
965 | The expectation here is that the secure falcon will do a single DMA | ||
966 | read of this array and cache it internally so it's OK to pack these. | ||
967 | Also, we add 1 to the falcon count to indicate the end of the array.*/ | ||
968 | wpr_offset = sizeof(struct lsf_wpr_header_v1) * | ||
969 | (plsfm->managed_flcn_cnt+1); | ||
970 | |||
971 | /* Walk the managed falcons, accounting for the LSB structs | ||
972 | as well as the ucode images. */ | ||
973 | while (pnode) { | ||
974 | /* Align, save off, and include an LSB header size */ | ||
975 | wpr_offset = ALIGN(wpr_offset, | ||
976 | LSF_LSB_HEADER_ALIGNMENT); | ||
977 | pnode->wpr_header.lsb_offset = wpr_offset; | ||
978 | wpr_offset += sizeof(struct lsf_lsb_header_v1); | ||
979 | |||
980 | /* Align, save off, and include the original (static) | ||
981 | ucode image size */ | ||
982 | wpr_offset = ALIGN(wpr_offset, | ||
983 | LSF_UCODE_DATA_ALIGNMENT); | ||
984 | pnode->lsb_header.ucode_off = wpr_offset; | ||
985 | wpr_offset += pnode->ucode_img.data_size; | ||
986 | |||
987 | /* For falcons that use a boot loader (BL), we append a loader | ||
988 | desc structure on the end of the ucode image and consider this | ||
989 | the boot loader data. The host will then copy the loader desc | ||
990 | args to this space within the WPR region (before locking down) | ||
991 | and the HS bin will then copy them to DMEM 0 for the loader. */ | ||
992 | if (!pnode->ucode_img.header) { | ||
993 | /* Track the size for LSB details filled in later | ||
994 | Note that at this point we don't know what kind of i | ||
995 | boot loader desc, so we just take the size of the | ||
996 | generic one, which is the largest it will will ever be. | ||
997 | */ | ||
998 | /* Align (size bloat) and save off generic | ||
999 | descriptor size*/ | ||
1000 | pnode->lsb_header.bl_data_size = ALIGN( | ||
1001 | sizeof(pnode->bl_gen_desc), | ||
1002 | LSF_BL_DATA_SIZE_ALIGNMENT); | ||
1003 | |||
1004 | /*Align, save off, and include the additional BL data*/ | ||
1005 | wpr_offset = ALIGN(wpr_offset, | ||
1006 | LSF_BL_DATA_ALIGNMENT); | ||
1007 | pnode->lsb_header.bl_data_off = wpr_offset; | ||
1008 | wpr_offset += pnode->lsb_header.bl_data_size; | ||
1009 | } else { | ||
1010 | /* bl_data_off is already assigned in static | ||
1011 | information. But that is from start of the image */ | ||
1012 | pnode->lsb_header.bl_data_off += | ||
1013 | (wpr_offset - pnode->ucode_img.data_size); | ||
1014 | } | ||
1015 | |||
1016 | /* Finally, update ucode surface size to include updates */ | ||
1017 | pnode->full_ucode_size = wpr_offset - | ||
1018 | pnode->lsb_header.ucode_off; | ||
1019 | if (pnode->wpr_header.falcon_id != LSF_FALCON_ID_PMU) { | ||
1020 | pnode->lsb_header.app_code_off = | ||
1021 | pnode->lsb_header.bl_code_size; | ||
1022 | pnode->lsb_header.app_code_size = | ||
1023 | pnode->lsb_header.ucode_size - | ||
1024 | pnode->lsb_header.bl_code_size; | ||
1025 | pnode->lsb_header.app_data_off = | ||
1026 | pnode->lsb_header.ucode_size; | ||
1027 | pnode->lsb_header.app_data_size = | ||
1028 | pnode->lsb_header.data_size; | ||
1029 | } | ||
1030 | pnode = pnode->next; | ||
1031 | } | ||
1032 | plsfm->wpr_size = wpr_offset; | ||
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | /*Loads ACR bin to FB mem and bootstraps PMU with bootloader code | ||
1037 | * start and end are addresses of ucode blob in non-WPR region*/ | ||
1038 | static int gp106_bootstrap_hs_flcn(struct gk20a *g) | ||
1039 | { | ||
1040 | struct mm_gk20a *mm = &g->mm; | ||
1041 | struct vm_gk20a *vm = &mm->pmu.vm; | ||
1042 | int err = 0; | ||
1043 | u64 *acr_dmem; | ||
1044 | u32 img_size_in_bytes = 0; | ||
1045 | u32 status; | ||
1046 | struct acr_desc *acr = &g->acr; | ||
1047 | const struct firmware *acr_fw = acr->acr_fw; | ||
1048 | struct flcn_bl_dmem_desc_v1 *bl_dmem_desc = &acr->bl_dmem_desc_v1; | ||
1049 | u32 *acr_ucode_header_t210_load; | ||
1050 | u32 *acr_ucode_data_t210_load; | ||
1051 | struct wpr_carveout_info wpr_inf; | ||
1052 | |||
1053 | gp106_dbg_pmu(""); | ||
1054 | |||
1055 | if (!acr_fw) { | ||
1056 | /*First time init case*/ | ||
1057 | acr_fw = nvgpu_request_firmware(g, | ||
1058 | GM20B_HSBIN_PMU_UCODE_IMAGE, | ||
1059 | NVGPU_REQUEST_FIRMWARE_NO_SOC); | ||
1060 | if (!acr_fw) { | ||
1061 | gk20a_err(dev_from_gk20a(g), "pmu ucode get fail"); | ||
1062 | return -ENOENT; | ||
1063 | } | ||
1064 | acr->acr_fw = acr_fw; | ||
1065 | acr->hsbin_hdr = (struct bin_hdr *)acr_fw->data; | ||
1066 | acr->fw_hdr = (struct acr_fw_header *)(acr_fw->data + | ||
1067 | acr->hsbin_hdr->header_offset); | ||
1068 | acr_ucode_data_t210_load = (u32 *)(acr_fw->data + | ||
1069 | acr->hsbin_hdr->data_offset); | ||
1070 | acr_ucode_header_t210_load = (u32 *)(acr_fw->data + | ||
1071 | acr->fw_hdr->hdr_offset); | ||
1072 | img_size_in_bytes = ALIGN((acr->hsbin_hdr->data_size), 256); | ||
1073 | |||
1074 | /* Lets patch the signatures first.. */ | ||
1075 | if (acr_ucode_patch_sig(g, acr_ucode_data_t210_load, | ||
1076 | (u32 *)(acr_fw->data + | ||
1077 | acr->fw_hdr->sig_prod_offset), | ||
1078 | (u32 *)(acr_fw->data + | ||
1079 | acr->fw_hdr->sig_dbg_offset), | ||
1080 | (u32 *)(acr_fw->data + | ||
1081 | acr->fw_hdr->patch_loc), | ||
1082 | (u32 *)(acr_fw->data + | ||
1083 | acr->fw_hdr->patch_sig)) < 0) { | ||
1084 | gk20a_err(dev_from_gk20a(g), "patch signatures fail"); | ||
1085 | err = -1; | ||
1086 | goto err_release_acr_fw; | ||
1087 | } | ||
1088 | err = gk20a_gmmu_alloc_map_sys(vm, img_size_in_bytes, | ||
1089 | &acr->acr_ucode); | ||
1090 | if (err) { | ||
1091 | err = -ENOMEM; | ||
1092 | goto err_release_acr_fw; | ||
1093 | } | ||
1094 | |||
1095 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
1096 | |||
1097 | acr_dmem = (u64 *) | ||
1098 | &(((u8 *)acr_ucode_data_t210_load)[ | ||
1099 | acr_ucode_header_t210_load[2]]); | ||
1100 | acr->acr_dmem_desc_v1 = (struct flcn_acr_desc_v1 *)((u8 *)( | ||
1101 | acr->acr_ucode.cpu_va) + acr_ucode_header_t210_load[2]); | ||
1102 | ((struct flcn_acr_desc_v1 *)acr_dmem)->nonwpr_ucode_blob_start = | ||
1103 | wpr_inf.nonwpr_base; | ||
1104 | ((struct flcn_acr_desc_v1 *)acr_dmem)->nonwpr_ucode_blob_size = | ||
1105 | wpr_inf.size; | ||
1106 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.no_regions = 1; | ||
1107 | ((struct flcn_acr_desc_v1 *)acr_dmem)->wpr_offset = 0; | ||
1108 | |||
1109 | ((struct flcn_acr_desc_v1 *)acr_dmem)->wpr_region_id = 1; | ||
1110 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1111 | 0].region_id = 1; | ||
1112 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1113 | 0].start_addr = (wpr_inf.wpr_base ) >> 8; | ||
1114 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1115 | 0].end_addr = ((wpr_inf.wpr_base) + wpr_inf.size) >> 8; | ||
1116 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1117 | 0].shadowmMem_startaddress = wpr_inf.nonwpr_base >> 8; | ||
1118 | |||
1119 | gk20a_mem_wr_n(g, &acr->acr_ucode, 0, | ||
1120 | acr_ucode_data_t210_load, img_size_in_bytes); | ||
1121 | |||
1122 | /* | ||
1123 | * In order to execute this binary, we will be using | ||
1124 | * a bootloader which will load this image into PMU IMEM/DMEM. | ||
1125 | * Fill up the bootloader descriptor for PMU HAL to use.. | ||
1126 | * TODO: Use standard descriptor which the generic bootloader is | ||
1127 | * checked in. | ||
1128 | */ | ||
1129 | |||
1130 | bl_dmem_desc->signature[0] = 0; | ||
1131 | bl_dmem_desc->signature[1] = 0; | ||
1132 | bl_dmem_desc->signature[2] = 0; | ||
1133 | bl_dmem_desc->signature[3] = 0; | ||
1134 | bl_dmem_desc->ctx_dma = GK20A_PMU_DMAIDX_VIRT; | ||
1135 | flcn64_set_dma( &bl_dmem_desc->code_dma_base, | ||
1136 | acr->acr_ucode.gpu_va); | ||
1137 | bl_dmem_desc->non_sec_code_off = acr_ucode_header_t210_load[0]; | ||
1138 | bl_dmem_desc->non_sec_code_size = acr_ucode_header_t210_load[1]; | ||
1139 | bl_dmem_desc->sec_code_off = acr_ucode_header_t210_load[5]; | ||
1140 | bl_dmem_desc->sec_code_size = acr_ucode_header_t210_load[6]; | ||
1141 | bl_dmem_desc->code_entry_point = 0; /* Start at 0th offset */ | ||
1142 | flcn64_set_dma( &bl_dmem_desc->data_dma_base, | ||
1143 | acr->acr_ucode.gpu_va + | ||
1144 | (acr_ucode_header_t210_load[2])); | ||
1145 | bl_dmem_desc->data_size = acr_ucode_header_t210_load[3]; | ||
1146 | } else | ||
1147 | acr->acr_dmem_desc->nonwpr_ucode_blob_size = 0; | ||
1148 | |||
1149 | status = pmu_exec_gen_bl(g, bl_dmem_desc, 1); | ||
1150 | if (status != 0) { | ||
1151 | err = status; | ||
1152 | goto err_free_ucode_map; | ||
1153 | } | ||
1154 | |||
1155 | /* sec2 reset - to keep it idle */ | ||
1156 | gk20a_writel(g, psec_falcon_engine_r(), | ||
1157 | pwr_falcon_engine_reset_true_f()); | ||
1158 | udelay(10); | ||
1159 | gk20a_writel(g, psec_falcon_engine_r(), | ||
1160 | pwr_falcon_engine_reset_false_f()); | ||
1161 | |||
1162 | return 0; | ||
1163 | err_free_ucode_map: | ||
1164 | gk20a_gmmu_unmap_free(vm, &acr->acr_ucode); | ||
1165 | err_release_acr_fw: | ||
1166 | release_firmware(acr_fw); | ||
1167 | acr->acr_fw = NULL; | ||
1168 | return err; | ||
1169 | } | ||