diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/nvgpu/gp106/acr_gp106.c | 1131 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gp106/acr_gp106.h | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gp106/hw_psec_gp106.h | 609 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gp106/sec2_gp106.c | 384 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gp106/sec2_gp106.h | 29 |
5 files changed, 2155 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..2ea2f817 --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/acr_gp106.c | |||
@@ -0,0 +1,1131 @@ | |||
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 "gm20b/hw_pwr_gm20b.h" | ||
26 | #include "gm206/acr_gm206.h" | ||
27 | #include "gm20b/acr_gm20b.h" | ||
28 | #include "gm206/pmu_gm206.h" | ||
29 | #include "sec2_gp106.h" | ||
30 | |||
31 | /*Defines*/ | ||
32 | #define gp106_dbg_pmu(fmt, arg...) \ | ||
33 | gk20a_dbg(gpu_dbg_pmu, fmt, ##arg) | ||
34 | |||
35 | typedef int (*get_ucode_details)(struct gk20a *g, | ||
36 | struct flcn_ucode_img_v1 *udata); | ||
37 | |||
38 | /* Both size and address of WPR need to be 128K-aligned */ | ||
39 | #define WPR_ALIGNMENT 0x20000 | ||
40 | #define GP106_DGPU_NONWPR 0x10000000 /* start from 256MB location at VIDMEM */ | ||
41 | #define GP106_DGPU_WPR 0x20000000 | ||
42 | #define DGPU_WPR_SIZE 0x100000 | ||
43 | |||
44 | /*Externs*/ | ||
45 | |||
46 | /*Forwards*/ | ||
47 | static int pmu_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img); | ||
48 | static int fecs_ucode_details(struct gk20a *g, | ||
49 | struct flcn_ucode_img_v1 *p_img); | ||
50 | static int gpccs_ucode_details(struct gk20a *g, | ||
51 | struct flcn_ucode_img_v1 *p_img); | ||
52 | static int gp106_bootstrap_hs_flcn(struct gk20a *g); | ||
53 | |||
54 | static int lsfm_discover_ucode_images(struct gk20a *g, | ||
55 | struct ls_flcn_mgr_v1 *plsfm); | ||
56 | static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm, | ||
57 | struct flcn_ucode_img_v1 *ucode_image, u32 falcon_id); | ||
58 | static void lsfm_free_ucode_img_res(struct flcn_ucode_img_v1 *p_img); | ||
59 | static void lsfm_free_nonpmu_ucode_img_res(struct flcn_ucode_img_v1 *p_img); | ||
60 | static int lsf_gen_wpr_requirements(struct gk20a *g, | ||
61 | struct ls_flcn_mgr_v1 *plsfm); | ||
62 | static void lsfm_init_wpr_contents(struct gk20a *g, | ||
63 | struct ls_flcn_mgr_v1 *plsfm, struct mem_desc *nonwpr); | ||
64 | static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm); | ||
65 | static int gp106_pmu_populate_loader_cfg(struct gk20a *g, | ||
66 | void *lsfm, u32 *p_bl_gen_desc_size); | ||
67 | static int gp106_flcn_populate_bl_dmem_desc(struct gk20a *g, | ||
68 | void *lsfm, u32 *p_bl_gen_desc_size, u32 falconid); | ||
69 | static int gp106_prepare_ucode_blob(struct gk20a *g); | ||
70 | |||
71 | /*Globals*/ | ||
72 | static get_ucode_details pmu_acr_supp_ucode_list[] = { | ||
73 | pmu_ucode_details, | ||
74 | fecs_ucode_details, | ||
75 | gpccs_ucode_details, | ||
76 | }; | ||
77 | |||
78 | void gp106_wpr_info(struct gk20a *g, struct wpr_carveout_info *inf) | ||
79 | { | ||
80 | inf->wpr_base = GP106_DGPU_WPR; | ||
81 | inf->nonwpr_base = GP106_DGPU_NONWPR; | ||
82 | inf->size = DGPU_WPR_SIZE; | ||
83 | } | ||
84 | |||
85 | static void flcn64_set_dma(struct falc_u64 *dma_addr, u64 value) | ||
86 | { | ||
87 | dma_addr->lo |= u64_lo32(value); | ||
88 | dma_addr->hi |= u64_hi32(value); | ||
89 | } | ||
90 | |||
91 | int gp106_alloc_blob_space(struct gk20a *g, | ||
92 | size_t size, struct mem_desc *mem) | ||
93 | { | ||
94 | int err = 0; | ||
95 | struct wpr_carveout_info wpr_inf; | ||
96 | |||
97 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
98 | |||
99 | mem->aperture = APERTURE_VIDMEM; | ||
100 | mem->sgt = kzalloc(sizeof(*mem->sgt), GFP_KERNEL); | ||
101 | if (!mem->sgt) { | ||
102 | gk20a_err(dev_from_gk20a(g), "failed to allocate memory\n"); | ||
103 | return -ENOMEM; | ||
104 | } | ||
105 | |||
106 | err = sg_alloc_table(mem->sgt, 1, GFP_KERNEL); | ||
107 | if (err) { | ||
108 | gk20a_err(dev_from_gk20a(g), "failed to allocate sg_table\n"); | ||
109 | goto free_sgt; | ||
110 | } | ||
111 | |||
112 | sg_dma_address(mem->sgt->sgl) = wpr_inf.nonwpr_base; | ||
113 | |||
114 | return err; | ||
115 | |||
116 | free_sgt: | ||
117 | gk20a_free_sgtable(&mem->sgt); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | void gp106_init_secure_pmu(struct gpu_ops *gops) | ||
122 | { | ||
123 | gops->pmu.prepare_ucode = gp106_prepare_ucode_blob; | ||
124 | gops->pmu.pmu_setup_hw_and_bootstrap = gp106_bootstrap_hs_flcn; | ||
125 | gops->pmu.is_lazy_bootstrap = gm206_is_lazy_bootstrap; | ||
126 | gops->pmu.is_priv_load = gm206_is_priv_load; | ||
127 | gops->pmu.get_wpr = gp106_wpr_info; | ||
128 | gops->pmu.alloc_blob_space = gp106_alloc_blob_space; | ||
129 | gops->pmu.pmu_populate_loader_cfg = gp106_pmu_populate_loader_cfg; | ||
130 | gops->pmu.flcn_populate_bl_dmem_desc = gp106_flcn_populate_bl_dmem_desc; | ||
131 | gops->pmu.falcon_wait_for_halt = sec2_wait_for_halt; | ||
132 | gops->pmu.falcon_clear_halt_interrupt_status = | ||
133 | sec2_clear_halt_interrupt_status; | ||
134 | gops->pmu.init_falcon_setup_hw = init_sec2_setup_hw1; | ||
135 | } | ||
136 | /* TODO - check if any free blob res needed*/ | ||
137 | |||
138 | int pmu_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img) | ||
139 | { | ||
140 | const struct firmware *pmu_fw, *pmu_desc, *pmu_sig; | ||
141 | struct pmu_gk20a *pmu = &g->pmu; | ||
142 | struct lsf_ucode_desc_v1 *lsf_desc; | ||
143 | int err; | ||
144 | |||
145 | gp106_dbg_pmu("requesting PMU ucode in gp106\n"); | ||
146 | pmu_fw = gk20a_request_firmware(g, GM20B_PMU_UCODE_IMAGE); | ||
147 | if (!pmu_fw) { | ||
148 | gk20a_err(dev_from_gk20a(g), "failed to load pmu ucode!!"); | ||
149 | return -ENOENT; | ||
150 | } | ||
151 | g->acr.pmu_fw = pmu_fw; | ||
152 | gp106_dbg_pmu("Loaded PMU ucode in for blob preparation"); | ||
153 | |||
154 | gp106_dbg_pmu("requesting PMU ucode desc in GM20B\n"); | ||
155 | pmu_desc = gk20a_request_firmware(g, GM20B_PMU_UCODE_DESC); | ||
156 | if (!pmu_desc) { | ||
157 | gk20a_err(dev_from_gk20a(g), "failed to load pmu ucode desc!!"); | ||
158 | err = -ENOENT; | ||
159 | goto release_img_fw; | ||
160 | } | ||
161 | pmu_sig = gk20a_request_firmware(g, GM20B_PMU_UCODE_SIG); | ||
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_desc; | ||
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 | int fecs_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img) | ||
206 | { | ||
207 | struct lsf_ucode_desc_v1 *lsf_desc; | ||
208 | const struct firmware *fecs_sig; | ||
209 | int err; | ||
210 | |||
211 | fecs_sig = gk20a_request_firmware(g, GM20B_FECS_UCODE_SIG); | ||
212 | if (!fecs_sig) { | ||
213 | gk20a_err(dev_from_gk20a(g), "failed to load fecs sig"); | ||
214 | return -ENOENT; | ||
215 | } | ||
216 | lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc_v1), GFP_KERNEL); | ||
217 | if (!lsf_desc) { | ||
218 | err = -ENOMEM; | ||
219 | goto rel_sig; | ||
220 | } | ||
221 | memcpy(lsf_desc, (void *)fecs_sig->data, sizeof(struct lsf_ucode_desc_v1)); | ||
222 | lsf_desc->falcon_id = LSF_FALCON_ID_FECS; | ||
223 | |||
224 | p_img->desc = kzalloc(sizeof(struct pmu_ucode_desc_v1), GFP_KERNEL); | ||
225 | if (p_img->desc == NULL) { | ||
226 | err = -ENOMEM; | ||
227 | goto free_lsf_desc; | ||
228 | } | ||
229 | |||
230 | p_img->desc->bootloader_start_offset = | ||
231 | g->ctxsw_ucode_info.fecs.boot.offset; | ||
232 | p_img->desc->bootloader_size = | ||
233 | ALIGN(g->ctxsw_ucode_info.fecs.boot.size, 256); | ||
234 | p_img->desc->bootloader_imem_offset = | ||
235 | g->ctxsw_ucode_info.fecs.boot_imem_offset; | ||
236 | p_img->desc->bootloader_entry_point = | ||
237 | g->ctxsw_ucode_info.fecs.boot_entry; | ||
238 | |||
239 | p_img->desc->image_size = | ||
240 | ALIGN(g->ctxsw_ucode_info.fecs.boot.size, 256) + | ||
241 | ALIGN(g->ctxsw_ucode_info.fecs.code.size, 256) + | ||
242 | ALIGN(g->ctxsw_ucode_info.fecs.data.size, 256); | ||
243 | p_img->desc->app_size = ALIGN(g->ctxsw_ucode_info.fecs.code.size, 256) + | ||
244 | ALIGN(g->ctxsw_ucode_info.fecs.data.size, 256); | ||
245 | p_img->desc->app_start_offset = g->ctxsw_ucode_info.fecs.code.offset; | ||
246 | p_img->desc->app_imem_offset = 0; | ||
247 | p_img->desc->app_imem_entry = 0; | ||
248 | p_img->desc->app_dmem_offset = 0; | ||
249 | p_img->desc->app_resident_code_offset = 0; | ||
250 | p_img->desc->app_resident_code_size = | ||
251 | g->ctxsw_ucode_info.fecs.code.size; | ||
252 | p_img->desc->app_resident_data_offset = | ||
253 | g->ctxsw_ucode_info.fecs.data.offset - | ||
254 | g->ctxsw_ucode_info.fecs.code.offset; | ||
255 | p_img->desc->app_resident_data_size = | ||
256 | g->ctxsw_ucode_info.fecs.data.size; | ||
257 | p_img->data = g->ctxsw_ucode_info.surface_desc.cpu_va; | ||
258 | p_img->data_size = p_img->desc->image_size; | ||
259 | |||
260 | p_img->fw_ver = NULL; | ||
261 | p_img->header = NULL; | ||
262 | p_img->lsf_desc = (struct lsf_ucode_desc_v1 *)lsf_desc; | ||
263 | gp106_dbg_pmu("fecs fw loaded\n"); | ||
264 | release_firmware(fecs_sig); | ||
265 | return 0; | ||
266 | free_lsf_desc: | ||
267 | kfree(lsf_desc); | ||
268 | rel_sig: | ||
269 | release_firmware(fecs_sig); | ||
270 | return err; | ||
271 | } | ||
272 | int gpccs_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img) | ||
273 | { | ||
274 | struct lsf_ucode_desc_v1 *lsf_desc; | ||
275 | const struct firmware *gpccs_sig; | ||
276 | int err; | ||
277 | |||
278 | if (g->ops.securegpccs == false) | ||
279 | return -ENOENT; | ||
280 | |||
281 | gpccs_sig = gk20a_request_firmware(g, T18x_GPCCS_UCODE_SIG); | ||
282 | if (!gpccs_sig) { | ||
283 | gk20a_err(dev_from_gk20a(g), "failed to load gpccs sig"); | ||
284 | return -ENOENT; | ||
285 | } | ||
286 | lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc_v1), GFP_KERNEL); | ||
287 | if (!lsf_desc) { | ||
288 | err = -ENOMEM; | ||
289 | goto rel_sig; | ||
290 | } | ||
291 | memcpy(lsf_desc, (void *)gpccs_sig->data, | ||
292 | sizeof(struct lsf_ucode_desc_v1)); | ||
293 | lsf_desc->falcon_id = LSF_FALCON_ID_GPCCS; | ||
294 | |||
295 | p_img->desc = kzalloc(sizeof(struct pmu_ucode_desc_v1), GFP_KERNEL); | ||
296 | if (p_img->desc == NULL) { | ||
297 | err = -ENOMEM; | ||
298 | goto free_lsf_desc; | ||
299 | } | ||
300 | |||
301 | p_img->desc->bootloader_start_offset = | ||
302 | 0; | ||
303 | p_img->desc->bootloader_size = | ||
304 | ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256); | ||
305 | p_img->desc->bootloader_imem_offset = | ||
306 | g->ctxsw_ucode_info.gpccs.boot_imem_offset; | ||
307 | p_img->desc->bootloader_entry_point = | ||
308 | g->ctxsw_ucode_info.gpccs.boot_entry; | ||
309 | |||
310 | p_img->desc->image_size = | ||
311 | ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256) + | ||
312 | ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) + | ||
313 | ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); | ||
314 | p_img->desc->app_size = ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) | ||
315 | + ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); | ||
316 | p_img->desc->app_start_offset = p_img->desc->bootloader_size; | ||
317 | p_img->desc->app_imem_offset = 0; | ||
318 | p_img->desc->app_imem_entry = 0; | ||
319 | p_img->desc->app_dmem_offset = 0; | ||
320 | p_img->desc->app_resident_code_offset = 0; | ||
321 | p_img->desc->app_resident_code_size = | ||
322 | ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256); | ||
323 | p_img->desc->app_resident_data_offset = | ||
324 | ALIGN(g->ctxsw_ucode_info.gpccs.data.offset, 256) - | ||
325 | ALIGN(g->ctxsw_ucode_info.gpccs.code.offset, 256); | ||
326 | p_img->desc->app_resident_data_size = | ||
327 | ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); | ||
328 | p_img->data = (u32 *)((u8 *)g->ctxsw_ucode_info.surface_desc.cpu_va + | ||
329 | g->ctxsw_ucode_info.gpccs.boot.offset); | ||
330 | p_img->data_size = ALIGN(p_img->desc->image_size, 256); | ||
331 | p_img->fw_ver = NULL; | ||
332 | p_img->header = NULL; | ||
333 | p_img->lsf_desc = (struct lsf_ucode_desc_v1 *)lsf_desc; | ||
334 | gp106_dbg_pmu("gpccs fw loaded\n"); | ||
335 | release_firmware(gpccs_sig); | ||
336 | return 0; | ||
337 | free_lsf_desc: | ||
338 | kfree(lsf_desc); | ||
339 | rel_sig: | ||
340 | release_firmware(gpccs_sig); | ||
341 | return err; | ||
342 | } | ||
343 | |||
344 | int gp106_prepare_ucode_blob(struct gk20a *g) | ||
345 | { | ||
346 | |||
347 | int err; | ||
348 | struct ls_flcn_mgr_v1 lsfm_l, *plsfm; | ||
349 | struct pmu_gk20a *pmu = &g->pmu; | ||
350 | struct wpr_carveout_info wpr_inf; | ||
351 | |||
352 | if (g->acr.ucode_blob.cpu_va) { | ||
353 | /*Recovery case, we do not need to form | ||
354 | non WPR blob of ucodes*/ | ||
355 | err = gk20a_init_pmu(pmu); | ||
356 | if (err) { | ||
357 | gp106_dbg_pmu("failed to set function pointers\n"); | ||
358 | return err; | ||
359 | } | ||
360 | return 0; | ||
361 | } | ||
362 | plsfm = &lsfm_l; | ||
363 | memset((void *)plsfm, 0, sizeof(struct ls_flcn_mgr_v1)); | ||
364 | gp106_dbg_pmu("fetching GMMU regs\n"); | ||
365 | gm20b_mm_mmu_vpr_info_fetch(g); | ||
366 | gr_gk20a_init_ctxsw_ucode(g); | ||
367 | |||
368 | if (g->ops.fb.dump_vpr_wpr_info) | ||
369 | g->ops.fb.dump_vpr_wpr_info(g); | ||
370 | |||
371 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
372 | gp106_dbg_pmu("wpr carveout base:%llx\n", (wpr_inf.wpr_base)); | ||
373 | gp106_dbg_pmu("wpr carveout size :%x\n", (u32)wpr_inf.size); | ||
374 | |||
375 | /* Discover all managed falcons*/ | ||
376 | err = lsfm_discover_ucode_images(g, plsfm); | ||
377 | gp106_dbg_pmu(" Managed Falcon cnt %d\n", plsfm->managed_flcn_cnt); | ||
378 | if (err) | ||
379 | goto exit_err; | ||
380 | |||
381 | if (plsfm->managed_flcn_cnt && !g->acr.ucode_blob.cpu_va) { | ||
382 | /* Generate WPR requirements*/ | ||
383 | err = lsf_gen_wpr_requirements(g, plsfm); | ||
384 | if (err) | ||
385 | goto exit_err; | ||
386 | |||
387 | /*Alloc memory to hold ucode blob contents*/ | ||
388 | err = g->ops.pmu.alloc_blob_space(g, plsfm->wpr_size | ||
389 | ,&g->acr.ucode_blob); | ||
390 | if (err) | ||
391 | goto exit_err; | ||
392 | |||
393 | gp106_dbg_pmu("managed LS falcon %d, WPR size %d bytes.\n", | ||
394 | plsfm->managed_flcn_cnt, plsfm->wpr_size); | ||
395 | |||
396 | lsfm_init_wpr_contents(g, plsfm, &g->acr.ucode_blob); | ||
397 | } else { | ||
398 | gp106_dbg_pmu("LSFM is managing no falcons.\n"); | ||
399 | } | ||
400 | gp106_dbg_pmu("prepare ucode blob return 0\n"); | ||
401 | free_acr_resources(g, plsfm); | ||
402 | |||
403 | exit_err: | ||
404 | return err; | ||
405 | } | ||
406 | |||
407 | static u8 lsfm_falcon_disabled(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm, | ||
408 | u32 falcon_id) | ||
409 | { | ||
410 | return (plsfm->disable_mask >> falcon_id) & 0x1; | ||
411 | } | ||
412 | |||
413 | /* Discover all managed falcon ucode images */ | ||
414 | static int lsfm_discover_ucode_images(struct gk20a *g, | ||
415 | struct ls_flcn_mgr_v1 *plsfm) | ||
416 | { | ||
417 | struct pmu_gk20a *pmu = &g->pmu; | ||
418 | struct flcn_ucode_img_v1 ucode_img; | ||
419 | u32 falcon_id; | ||
420 | u32 i; | ||
421 | int status; | ||
422 | |||
423 | /* LSFM requires a secure PMU, discover it first.*/ | ||
424 | /* Obtain the PMU ucode image and add it to the list if required*/ | ||
425 | memset(&ucode_img, 0, sizeof(ucode_img)); | ||
426 | status = pmu_ucode_details(g, &ucode_img); | ||
427 | if (status == 0) { | ||
428 | if (ucode_img.lsf_desc != NULL) { | ||
429 | /* The falon_id is formed by grabbing the static base | ||
430 | * falon_id from the image and adding the | ||
431 | * engine-designated falcon instance.*/ | ||
432 | pmu->pmu_mode |= PMU_SECURE_MODE; | ||
433 | falcon_id = ucode_img.lsf_desc->falcon_id + | ||
434 | ucode_img.flcn_inst; | ||
435 | |||
436 | if (!lsfm_falcon_disabled(g, plsfm, falcon_id)) { | ||
437 | pmu->falcon_id = falcon_id; | ||
438 | if (lsfm_add_ucode_img(g, plsfm, &ucode_img, | ||
439 | pmu->falcon_id) == 0) | ||
440 | pmu->pmu_mode |= PMU_LSFM_MANAGED; | ||
441 | |||
442 | plsfm->managed_flcn_cnt++; | ||
443 | } else { | ||
444 | gp106_dbg_pmu("id not managed %d\n", | ||
445 | ucode_img.lsf_desc->falcon_id); | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /*Free any ucode image resources if not managing this falcon*/ | ||
450 | if (!(pmu->pmu_mode & PMU_LSFM_MANAGED)) { | ||
451 | gp106_dbg_pmu("pmu is not LSFM managed\n"); | ||
452 | lsfm_free_ucode_img_res(&ucode_img); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /* Enumerate all constructed falcon objects, | ||
457 | as we need the ucode image info and total falcon count.*/ | ||
458 | |||
459 | /*0th index is always PMU which is already handled in earlier | ||
460 | if condition*/ | ||
461 | for (i = 1; i < (MAX_SUPPORTED_LSFM); i++) { | ||
462 | memset(&ucode_img, 0, sizeof(ucode_img)); | ||
463 | if (pmu_acr_supp_ucode_list[i](g, &ucode_img) == 0) { | ||
464 | if (ucode_img.lsf_desc != NULL) { | ||
465 | /* We have engine sigs, ensure that this falcon | ||
466 | is aware of the secure mode expectations | ||
467 | (ACR status)*/ | ||
468 | |||
469 | /* falon_id is formed by grabbing the static | ||
470 | base falonId from the image and adding the | ||
471 | engine-designated falcon instance. */ | ||
472 | falcon_id = ucode_img.lsf_desc->falcon_id + | ||
473 | ucode_img.flcn_inst; | ||
474 | |||
475 | if (!lsfm_falcon_disabled(g, plsfm, | ||
476 | falcon_id)) { | ||
477 | /* Do not manage non-FB ucode*/ | ||
478 | if (lsfm_add_ucode_img(g, | ||
479 | plsfm, &ucode_img, falcon_id) | ||
480 | == 0) | ||
481 | plsfm->managed_flcn_cnt++; | ||
482 | } else { | ||
483 | gp106_dbg_pmu("not managed %d\n", | ||
484 | ucode_img.lsf_desc->falcon_id); | ||
485 | lsfm_free_nonpmu_ucode_img_res( | ||
486 | &ucode_img); | ||
487 | } | ||
488 | } | ||
489 | } else { | ||
490 | /* Consumed all available falcon objects */ | ||
491 | gp106_dbg_pmu("Done checking for ucodes %d\n", i); | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | |||
499 | static int gp106_pmu_populate_loader_cfg(struct gk20a *g, | ||
500 | void *lsfm, u32 *p_bl_gen_desc_size) | ||
501 | { | ||
502 | struct wpr_carveout_info wpr_inf; | ||
503 | struct pmu_gk20a *pmu = &g->pmu; | ||
504 | struct lsfm_managed_ucode_img_v2 *p_lsfm = | ||
505 | (struct lsfm_managed_ucode_img_v2 *)lsfm; | ||
506 | struct flcn_ucode_img_v1 *p_img = &(p_lsfm->ucode_img); | ||
507 | struct loader_config_v1 *ldr_cfg = | ||
508 | &(p_lsfm->bl_gen_desc.loader_cfg_v1); | ||
509 | u64 addr_base; | ||
510 | struct pmu_ucode_desc_v1 *desc; | ||
511 | u64 addr_code, addr_data; | ||
512 | u32 addr_args; | ||
513 | |||
514 | if (p_img->desc == NULL) /*This means its a header based ucode, | ||
515 | and so we do not fill BL gen desc structure*/ | ||
516 | return -EINVAL; | ||
517 | desc = p_img->desc; | ||
518 | /* | ||
519 | Calculate physical and virtual addresses for various portions of | ||
520 | the PMU ucode image | ||
521 | Calculate the 32-bit addresses for the application code, application | ||
522 | data, and bootloader code. These values are all based on IM_BASE. | ||
523 | The 32-bit addresses will be the upper 32-bits of the virtual or | ||
524 | physical addresses of each respective segment. | ||
525 | */ | ||
526 | addr_base = p_lsfm->lsb_header.ucode_off; | ||
527 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
528 | addr_base += (wpr_inf.wpr_base); | ||
529 | |||
530 | gp106_dbg_pmu("pmu loader cfg u32 addrbase %x\n", (u32)addr_base); | ||
531 | /*From linux*/ | ||
532 | addr_code = u64_lo32((addr_base + | ||
533 | desc->app_start_offset + | ||
534 | desc->app_resident_code_offset) ); | ||
535 | gp106_dbg_pmu("app start %d app res code off %d\n", | ||
536 | desc->app_start_offset, desc->app_resident_code_offset); | ||
537 | addr_data = u64_lo32((addr_base + | ||
538 | desc->app_start_offset + | ||
539 | desc->app_resident_data_offset) ); | ||
540 | gp106_dbg_pmu("app res data offset%d\n", | ||
541 | desc->app_resident_data_offset); | ||
542 | gp106_dbg_pmu("bl start off %d\n", desc->bootloader_start_offset); | ||
543 | |||
544 | addr_args = ((pwr_falcon_hwcfg_dmem_size_v( | ||
545 | gk20a_readl(g, pwr_falcon_hwcfg_r()))) | ||
546 | << GK20A_PMU_DMEM_BLKSIZE2); | ||
547 | |||
548 | addr_args -= g->ops.pmu_ver.get_pmu_cmdline_args_size(pmu); | ||
549 | |||
550 | gp106_dbg_pmu("addr_args %x\n", addr_args); | ||
551 | |||
552 | /* Populate the loader_config state*/ | ||
553 | ldr_cfg->dma_idx = GK20A_PMU_DMAIDX_UCODE; | ||
554 | flcn64_set_dma(&ldr_cfg->code_dma_base, addr_code); | ||
555 | ldr_cfg->code_size_total = desc->app_size; | ||
556 | ldr_cfg->code_size_to_load = desc->app_resident_code_size; | ||
557 | ldr_cfg->code_entry_point = desc->app_imem_entry; | ||
558 | flcn64_set_dma(&ldr_cfg->data_dma_base, addr_data); | ||
559 | ldr_cfg->data_size = desc->app_resident_data_size; | ||
560 | flcn64_set_dma(&ldr_cfg->overlay_dma_base, addr_code); | ||
561 | |||
562 | /* Update the argc/argv members*/ | ||
563 | ldr_cfg->argc = 1; | ||
564 | ldr_cfg->argv = addr_args; | ||
565 | |||
566 | *p_bl_gen_desc_size = sizeof(struct loader_config_v1); | ||
567 | g->acr.pmu_args = addr_args; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int gp106_flcn_populate_bl_dmem_desc(struct gk20a *g, | ||
572 | void *lsfm, u32 *p_bl_gen_desc_size, u32 falconid) | ||
573 | { | ||
574 | struct wpr_carveout_info wpr_inf; | ||
575 | struct lsfm_managed_ucode_img_v2 *p_lsfm = | ||
576 | (struct lsfm_managed_ucode_img_v2 *)lsfm; | ||
577 | struct flcn_ucode_img_v1 *p_img = &(p_lsfm->ucode_img); | ||
578 | struct flcn_bl_dmem_desc_v1 *ldr_cfg = | ||
579 | &(p_lsfm->bl_gen_desc.bl_dmem_desc_v1); | ||
580 | u64 addr_base; | ||
581 | struct pmu_ucode_desc_v1 *desc; | ||
582 | u64 addr_code, addr_data; | ||
583 | |||
584 | if (p_img->desc == NULL) /*This means its a header based ucode, | ||
585 | and so we do not fill BL gen desc structure*/ | ||
586 | return -EINVAL; | ||
587 | desc = p_img->desc; | ||
588 | |||
589 | /* | ||
590 | Calculate physical and virtual addresses for various portions of | ||
591 | the PMU ucode image | ||
592 | Calculate the 32-bit addresses for the application code, application | ||
593 | data, and bootloader code. These values are all based on IM_BASE. | ||
594 | The 32-bit addresses will be the upper 32-bits of the virtual or | ||
595 | physical addresses of each respective segment. | ||
596 | */ | ||
597 | addr_base = p_lsfm->lsb_header.ucode_off; | ||
598 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
599 | addr_base += (wpr_inf.wpr_base); | ||
600 | |||
601 | gp106_dbg_pmu("gen loader cfg %x u32 addrbase %x ID\n", (u32)addr_base, | ||
602 | p_lsfm->wpr_header.falcon_id); | ||
603 | addr_code = u64_lo32((addr_base + | ||
604 | desc->app_start_offset + | ||
605 | desc->app_resident_code_offset) ); | ||
606 | addr_data = u64_lo32((addr_base + | ||
607 | desc->app_start_offset + | ||
608 | desc->app_resident_data_offset) ); | ||
609 | |||
610 | gp106_dbg_pmu("gen cfg %x u32 addrcode %x & data %x load offset %xID\n", | ||
611 | (u32)addr_code, (u32)addr_data, desc->bootloader_start_offset, | ||
612 | p_lsfm->wpr_header.falcon_id); | ||
613 | |||
614 | /* Populate the LOADER_CONFIG state */ | ||
615 | memset((void *) ldr_cfg, 0, sizeof(struct flcn_bl_dmem_desc_v1)); | ||
616 | ldr_cfg->ctx_dma = GK20A_PMU_DMAIDX_UCODE; | ||
617 | flcn64_set_dma(&ldr_cfg->code_dma_base, addr_code); | ||
618 | ldr_cfg->non_sec_code_size = desc->app_resident_code_size; | ||
619 | flcn64_set_dma(&ldr_cfg->data_dma_base, addr_data); | ||
620 | ldr_cfg->data_size = desc->app_resident_data_size; | ||
621 | ldr_cfg->code_entry_point = desc->app_imem_entry; | ||
622 | |||
623 | *p_bl_gen_desc_size = sizeof(struct flcn_bl_dmem_desc_v1); | ||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | /* Populate falcon boot loader generic desc.*/ | ||
628 | static int lsfm_fill_flcn_bl_gen_desc(struct gk20a *g, | ||
629 | struct lsfm_managed_ucode_img_v2 *pnode) | ||
630 | { | ||
631 | |||
632 | struct pmu_gk20a *pmu = &g->pmu; | ||
633 | if (pnode->wpr_header.falcon_id != pmu->falcon_id) { | ||
634 | gp106_dbg_pmu("non pmu. write flcn bl gen desc\n"); | ||
635 | g->ops.pmu.flcn_populate_bl_dmem_desc(g, | ||
636 | pnode, &pnode->bl_gen_desc_size, | ||
637 | pnode->wpr_header.falcon_id); | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | if (pmu->pmu_mode & PMU_LSFM_MANAGED) { | ||
642 | gp106_dbg_pmu("pmu write flcn bl gen desc\n"); | ||
643 | if (pnode->wpr_header.falcon_id == pmu->falcon_id) | ||
644 | return g->ops.pmu.pmu_populate_loader_cfg(g, pnode, | ||
645 | &pnode->bl_gen_desc_size); | ||
646 | } | ||
647 | |||
648 | /* Failed to find the falcon requested. */ | ||
649 | return -ENOENT; | ||
650 | } | ||
651 | |||
652 | /* Initialize WPR contents */ | ||
653 | static void lsfm_init_wpr_contents(struct gk20a *g, | ||
654 | struct ls_flcn_mgr_v1 *plsfm, struct mem_desc *ucode) | ||
655 | { | ||
656 | struct lsfm_managed_ucode_img_v2 *pnode = plsfm->ucode_img_list; | ||
657 | u32 i; | ||
658 | |||
659 | /* The WPR array is at the base of the WPR */ | ||
660 | pnode = plsfm->ucode_img_list; | ||
661 | i = 0; | ||
662 | |||
663 | /* | ||
664 | * Walk the managed falcons, flush WPR and LSB headers to FB. | ||
665 | * flush any bl args to the storage area relative to the | ||
666 | * ucode image (appended on the end as a DMEM area). | ||
667 | */ | ||
668 | while (pnode) { | ||
669 | /* Flush WPR header to memory*/ | ||
670 | gk20a_mem_wr_n(g, ucode, i * sizeof(pnode->wpr_header), | ||
671 | &pnode->wpr_header, sizeof(pnode->wpr_header)); | ||
672 | |||
673 | gp106_dbg_pmu("wpr header"); | ||
674 | gp106_dbg_pmu("falconid :%d", | ||
675 | pnode->wpr_header.falcon_id); | ||
676 | gp106_dbg_pmu("lsb_offset :%x", | ||
677 | pnode->wpr_header.lsb_offset); | ||
678 | gp106_dbg_pmu("bootstrap_owner :%d", | ||
679 | pnode->wpr_header.bootstrap_owner); | ||
680 | gp106_dbg_pmu("lazy_bootstrap :%d", | ||
681 | pnode->wpr_header.lazy_bootstrap); | ||
682 | gp106_dbg_pmu("status :%d", | ||
683 | pnode->wpr_header.status); | ||
684 | |||
685 | /*Flush LSB header to memory*/ | ||
686 | gk20a_mem_wr_n(g, ucode, pnode->wpr_header.lsb_offset, | ||
687 | &pnode->lsb_header, sizeof(pnode->lsb_header)); | ||
688 | |||
689 | gp106_dbg_pmu("lsb header"); | ||
690 | gp106_dbg_pmu("ucode_off :%x", | ||
691 | pnode->lsb_header.ucode_off); | ||
692 | gp106_dbg_pmu("ucode_size :%x", | ||
693 | pnode->lsb_header.ucode_size); | ||
694 | gp106_dbg_pmu("data_size :%x", | ||
695 | pnode->lsb_header.data_size); | ||
696 | gp106_dbg_pmu("bl_code_size :%x", | ||
697 | pnode->lsb_header.bl_code_size); | ||
698 | gp106_dbg_pmu("bl_imem_off :%x", | ||
699 | pnode->lsb_header.bl_imem_off); | ||
700 | gp106_dbg_pmu("bl_data_off :%x", | ||
701 | pnode->lsb_header.bl_data_off); | ||
702 | gp106_dbg_pmu("bl_data_size :%x", | ||
703 | pnode->lsb_header.bl_data_size); | ||
704 | gp106_dbg_pmu("app_code_off :%x", | ||
705 | pnode->lsb_header.app_code_off); | ||
706 | gp106_dbg_pmu("app_code_size :%x", | ||
707 | pnode->lsb_header.app_code_size); | ||
708 | gp106_dbg_pmu("app_data_off :%x", | ||
709 | pnode->lsb_header.app_data_off); | ||
710 | gp106_dbg_pmu("app_data_size :%x", | ||
711 | pnode->lsb_header.app_data_size); | ||
712 | gp106_dbg_pmu("flags :%x", | ||
713 | pnode->lsb_header.flags); | ||
714 | |||
715 | /*If this falcon has a boot loader and related args, | ||
716 | * flush them.*/ | ||
717 | if (!pnode->ucode_img.header) { | ||
718 | /*Populate gen bl and flush to memory*/ | ||
719 | lsfm_fill_flcn_bl_gen_desc(g, pnode); | ||
720 | gk20a_mem_wr_n(g, ucode, | ||
721 | pnode->lsb_header.bl_data_off, | ||
722 | &pnode->bl_gen_desc, | ||
723 | pnode->bl_gen_desc_size); | ||
724 | } | ||
725 | /*Copying of ucode*/ | ||
726 | gk20a_mem_wr_n(g, ucode, pnode->lsb_header.ucode_off, | ||
727 | pnode->ucode_img.data, | ||
728 | pnode->ucode_img.data_size); | ||
729 | pnode = pnode->next; | ||
730 | i++; | ||
731 | } | ||
732 | |||
733 | /* Tag the terminator WPR header with an invalid falcon ID. */ | ||
734 | gk20a_mem_wr32(g, ucode, | ||
735 | plsfm->managed_flcn_cnt * sizeof(struct lsf_wpr_header) + | ||
736 | offsetof(struct lsf_wpr_header, falcon_id), | ||
737 | LSF_FALCON_ID_INVALID); | ||
738 | } | ||
739 | |||
740 | /*! | ||
741 | * lsfm_parse_no_loader_ucode: parses UCODE header of falcon | ||
742 | * | ||
743 | * @param[in] p_ucodehdr : UCODE header | ||
744 | * @param[out] lsb_hdr : updates values in LSB header | ||
745 | * | ||
746 | * @return 0 | ||
747 | */ | ||
748 | static int lsfm_parse_no_loader_ucode(u32 *p_ucodehdr, | ||
749 | struct lsf_lsb_header_v1 *lsb_hdr) | ||
750 | { | ||
751 | |||
752 | u32 code_size = 0; | ||
753 | u32 data_size = 0; | ||
754 | u32 i = 0; | ||
755 | u32 total_apps = p_ucodehdr[FLCN_NL_UCODE_HDR_NUM_APPS_IND]; | ||
756 | |||
757 | /* Lets calculate code size*/ | ||
758 | code_size += p_ucodehdr[FLCN_NL_UCODE_HDR_OS_CODE_SIZE_IND]; | ||
759 | for (i = 0; i < total_apps; i++) { | ||
760 | code_size += p_ucodehdr[FLCN_NL_UCODE_HDR_APP_CODE_SIZE_IND | ||
761 | (total_apps, i)]; | ||
762 | } | ||
763 | code_size += p_ucodehdr[FLCN_NL_UCODE_HDR_OS_OVL_SIZE_IND(total_apps)]; | ||
764 | |||
765 | /* Calculate data size*/ | ||
766 | data_size += p_ucodehdr[FLCN_NL_UCODE_HDR_OS_DATA_SIZE_IND]; | ||
767 | for (i = 0; i < total_apps; i++) { | ||
768 | data_size += p_ucodehdr[FLCN_NL_UCODE_HDR_APP_DATA_SIZE_IND | ||
769 | (total_apps, i)]; | ||
770 | } | ||
771 | |||
772 | lsb_hdr->ucode_size = code_size; | ||
773 | lsb_hdr->data_size = data_size; | ||
774 | lsb_hdr->bl_code_size = p_ucodehdr[FLCN_NL_UCODE_HDR_OS_CODE_SIZE_IND]; | ||
775 | lsb_hdr->bl_imem_off = 0; | ||
776 | lsb_hdr->bl_data_off = p_ucodehdr[FLCN_NL_UCODE_HDR_OS_DATA_OFF_IND]; | ||
777 | lsb_hdr->bl_data_size = p_ucodehdr[FLCN_NL_UCODE_HDR_OS_DATA_SIZE_IND]; | ||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | /*! | ||
782 | * @brief lsfm_fill_static_lsb_hdr_info | ||
783 | * Populate static LSB header infomation using the provided ucode image | ||
784 | */ | ||
785 | static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g, | ||
786 | u32 falcon_id, struct lsfm_managed_ucode_img_v2 *pnode) | ||
787 | { | ||
788 | |||
789 | struct pmu_gk20a *pmu = &g->pmu; | ||
790 | u32 full_app_size = 0; | ||
791 | u32 data = 0; | ||
792 | |||
793 | if (pnode->ucode_img.lsf_desc) | ||
794 | memcpy(&pnode->lsb_header.signature, pnode->ucode_img.lsf_desc, | ||
795 | sizeof(struct lsf_ucode_desc_v1)); | ||
796 | pnode->lsb_header.ucode_size = pnode->ucode_img.data_size; | ||
797 | |||
798 | /* The remainder of the LSB depends on the loader usage */ | ||
799 | if (pnode->ucode_img.header) { | ||
800 | /* Does not use a loader */ | ||
801 | pnode->lsb_header.data_size = 0; | ||
802 | pnode->lsb_header.bl_code_size = 0; | ||
803 | pnode->lsb_header.bl_data_off = 0; | ||
804 | pnode->lsb_header.bl_data_size = 0; | ||
805 | |||
806 | lsfm_parse_no_loader_ucode(pnode->ucode_img.header, | ||
807 | &(pnode->lsb_header)); | ||
808 | |||
809 | /* Load the first 256 bytes of IMEM. */ | ||
810 | /* Set LOAD_CODE_AT_0 and DMACTL_REQ_CTX. | ||
811 | True for all method based falcons */ | ||
812 | data = NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0_TRUE | | ||
813 | NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE; | ||
814 | pnode->lsb_header.flags = data; | ||
815 | } else { | ||
816 | /* Uses a loader. that is has a desc */ | ||
817 | pnode->lsb_header.data_size = 0; | ||
818 | |||
819 | /* The loader code size is already aligned (padded) such that | ||
820 | the code following it is aligned, but the size in the image | ||
821 | desc is not, bloat it up to be on a 256 byte alignment. */ | ||
822 | pnode->lsb_header.bl_code_size = ALIGN( | ||
823 | pnode->ucode_img.desc->bootloader_size, | ||
824 | LSF_BL_CODE_SIZE_ALIGNMENT); | ||
825 | full_app_size = ALIGN(pnode->ucode_img.desc->app_size, | ||
826 | LSF_BL_CODE_SIZE_ALIGNMENT) + | ||
827 | pnode->lsb_header.bl_code_size; | ||
828 | pnode->lsb_header.ucode_size = ALIGN( | ||
829 | pnode->ucode_img.desc->app_resident_data_offset, | ||
830 | LSF_BL_CODE_SIZE_ALIGNMENT) + | ||
831 | pnode->lsb_header.bl_code_size; | ||
832 | pnode->lsb_header.data_size = full_app_size - | ||
833 | pnode->lsb_header.ucode_size; | ||
834 | /* Though the BL is located at 0th offset of the image, the VA | ||
835 | is different to make sure that it doesnt collide the actual OS | ||
836 | VA range */ | ||
837 | pnode->lsb_header.bl_imem_off = | ||
838 | pnode->ucode_img.desc->bootloader_imem_offset; | ||
839 | |||
840 | /* TODO: OBJFLCN should export properties using which the below | ||
841 | flags should be populated.*/ | ||
842 | pnode->lsb_header.flags = 0; | ||
843 | |||
844 | if (falcon_id == pmu->falcon_id) { | ||
845 | data = NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE; | ||
846 | pnode->lsb_header.flags = data; | ||
847 | } | ||
848 | |||
849 | if(g->ops.pmu.is_priv_load(falcon_id)) | ||
850 | pnode->lsb_header.flags |= | ||
851 | NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE; | ||
852 | } | ||
853 | } | ||
854 | |||
855 | /* Adds a ucode image to the list of managed ucode images managed. */ | ||
856 | static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm, | ||
857 | struct flcn_ucode_img_v1 *ucode_image, u32 falcon_id) | ||
858 | { | ||
859 | struct lsfm_managed_ucode_img_v2 *pnode; | ||
860 | |||
861 | pnode = kzalloc(sizeof(struct lsfm_managed_ucode_img_v2), GFP_KERNEL); | ||
862 | if (pnode == NULL) | ||
863 | return -ENOMEM; | ||
864 | |||
865 | /* Keep a copy of the ucode image info locally */ | ||
866 | memcpy(&pnode->ucode_img, ucode_image, sizeof(struct flcn_ucode_img_v1)); | ||
867 | |||
868 | /* Fill in static WPR header info*/ | ||
869 | pnode->wpr_header.falcon_id = falcon_id; | ||
870 | pnode->wpr_header.bootstrap_owner = 0x07; //LSF_BOOTSTRAP_OWNER_DEFAULT; | ||
871 | pnode->wpr_header.status = LSF_IMAGE_STATUS_COPY; | ||
872 | |||
873 | pnode->wpr_header.lazy_bootstrap = | ||
874 | g->ops.pmu.is_lazy_bootstrap(falcon_id); | ||
875 | |||
876 | /*TODO to check if PDB_PROP_FLCN_LAZY_BOOTSTRAP is to be supported by | ||
877 | Android */ | ||
878 | /* Fill in static LSB header info elsewhere */ | ||
879 | lsfm_fill_static_lsb_hdr_info(g, falcon_id, pnode); | ||
880 | pnode->wpr_header.bin_version = pnode->lsb_header.signature.version; | ||
881 | pnode->next = plsfm->ucode_img_list; | ||
882 | plsfm->ucode_img_list = pnode; | ||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | /* Free any ucode image structure resources*/ | ||
887 | static void lsfm_free_ucode_img_res(struct flcn_ucode_img_v1 *p_img) | ||
888 | { | ||
889 | if (p_img->lsf_desc != NULL) { | ||
890 | kfree(p_img->lsf_desc); | ||
891 | p_img->lsf_desc = NULL; | ||
892 | } | ||
893 | } | ||
894 | |||
895 | /* Free any ucode image structure resources*/ | ||
896 | static void lsfm_free_nonpmu_ucode_img_res(struct flcn_ucode_img_v1 *p_img) | ||
897 | { | ||
898 | if (p_img->lsf_desc != NULL) { | ||
899 | kfree(p_img->lsf_desc); | ||
900 | p_img->lsf_desc = NULL; | ||
901 | } | ||
902 | if (p_img->desc != NULL) { | ||
903 | kfree(p_img->desc); | ||
904 | p_img->desc = NULL; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm) | ||
909 | { | ||
910 | u32 cnt = plsfm->managed_flcn_cnt; | ||
911 | struct lsfm_managed_ucode_img_v2 *mg_ucode_img; | ||
912 | |||
913 | while (cnt) { | ||
914 | mg_ucode_img = plsfm->ucode_img_list; | ||
915 | if (mg_ucode_img->ucode_img.lsf_desc->falcon_id == | ||
916 | LSF_FALCON_ID_PMU) | ||
917 | lsfm_free_ucode_img_res(&mg_ucode_img->ucode_img); | ||
918 | else | ||
919 | lsfm_free_nonpmu_ucode_img_res( | ||
920 | &mg_ucode_img->ucode_img); | ||
921 | plsfm->ucode_img_list = mg_ucode_img->next; | ||
922 | kfree(mg_ucode_img); | ||
923 | cnt--; | ||
924 | } | ||
925 | } | ||
926 | |||
927 | /* Generate WPR requirements for ACR allocation request */ | ||
928 | static int lsf_gen_wpr_requirements(struct gk20a *g, | ||
929 | struct ls_flcn_mgr_v1 *plsfm) | ||
930 | { | ||
931 | struct lsfm_managed_ucode_img_v2 *pnode = plsfm->ucode_img_list; | ||
932 | u32 wpr_offset; | ||
933 | |||
934 | /* Calculate WPR size required */ | ||
935 | |||
936 | /* Start with an array of WPR headers at the base of the WPR. | ||
937 | The expectation here is that the secure falcon will do a single DMA | ||
938 | read of this array and cache it internally so it's OK to pack these. | ||
939 | Also, we add 1 to the falcon count to indicate the end of the array.*/ | ||
940 | wpr_offset = sizeof(struct lsf_wpr_header_v1) * | ||
941 | (plsfm->managed_flcn_cnt+1); | ||
942 | |||
943 | /* Walk the managed falcons, accounting for the LSB structs | ||
944 | as well as the ucode images. */ | ||
945 | while (pnode) { | ||
946 | /* Align, save off, and include an LSB header size */ | ||
947 | wpr_offset = ALIGN(wpr_offset, | ||
948 | LSF_LSB_HEADER_ALIGNMENT); | ||
949 | pnode->wpr_header.lsb_offset = wpr_offset; | ||
950 | wpr_offset += sizeof(struct lsf_lsb_header_v1); | ||
951 | |||
952 | /* Align, save off, and include the original (static) | ||
953 | ucode image size */ | ||
954 | wpr_offset = ALIGN(wpr_offset, | ||
955 | LSF_UCODE_DATA_ALIGNMENT); | ||
956 | pnode->lsb_header.ucode_off = wpr_offset; | ||
957 | wpr_offset += pnode->ucode_img.data_size; | ||
958 | |||
959 | /* For falcons that use a boot loader (BL), we append a loader | ||
960 | desc structure on the end of the ucode image and consider this | ||
961 | the boot loader data. The host will then copy the loader desc | ||
962 | args to this space within the WPR region (before locking down) | ||
963 | and the HS bin will then copy them to DMEM 0 for the loader. */ | ||
964 | if (!pnode->ucode_img.header) { | ||
965 | /* Track the size for LSB details filled in later | ||
966 | Note that at this point we don't know what kind of i | ||
967 | boot loader desc, so we just take the size of the | ||
968 | generic one, which is the largest it will will ever be. | ||
969 | */ | ||
970 | /* Align (size bloat) and save off generic | ||
971 | descriptor size*/ | ||
972 | pnode->lsb_header.bl_data_size = ALIGN( | ||
973 | sizeof(pnode->bl_gen_desc), | ||
974 | LSF_BL_DATA_SIZE_ALIGNMENT); | ||
975 | |||
976 | /*Align, save off, and include the additional BL data*/ | ||
977 | wpr_offset = ALIGN(wpr_offset, | ||
978 | LSF_BL_DATA_ALIGNMENT); | ||
979 | pnode->lsb_header.bl_data_off = wpr_offset; | ||
980 | wpr_offset += pnode->lsb_header.bl_data_size; | ||
981 | } else { | ||
982 | /* bl_data_off is already assigned in static | ||
983 | information. But that is from start of the image */ | ||
984 | pnode->lsb_header.bl_data_off += | ||
985 | (wpr_offset - pnode->ucode_img.data_size); | ||
986 | } | ||
987 | |||
988 | /* Finally, update ucode surface size to include updates */ | ||
989 | pnode->full_ucode_size = wpr_offset - | ||
990 | pnode->lsb_header.ucode_off; | ||
991 | if (pnode->wpr_header.falcon_id != LSF_FALCON_ID_PMU) { | ||
992 | pnode->lsb_header.app_code_off = | ||
993 | pnode->lsb_header.bl_code_size; | ||
994 | pnode->lsb_header.app_code_size = | ||
995 | pnode->lsb_header.ucode_size - | ||
996 | pnode->lsb_header.bl_code_size; | ||
997 | pnode->lsb_header.app_data_off = | ||
998 | pnode->lsb_header.ucode_size; | ||
999 | pnode->lsb_header.app_data_size = | ||
1000 | pnode->lsb_header.data_size; | ||
1001 | } | ||
1002 | pnode = pnode->next; | ||
1003 | } | ||
1004 | plsfm->wpr_size = wpr_offset; | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | /*Loads ACR bin to FB mem and bootstraps PMU with bootloader code | ||
1009 | * start and end are addresses of ucode blob in non-WPR region*/ | ||
1010 | int gp106_bootstrap_hs_flcn(struct gk20a *g) | ||
1011 | { | ||
1012 | struct mm_gk20a *mm = &g->mm; | ||
1013 | struct vm_gk20a *vm = &mm->pmu.vm; | ||
1014 | int err = 0; | ||
1015 | u64 *acr_dmem; | ||
1016 | u32 img_size_in_bytes = 0; | ||
1017 | u32 status; | ||
1018 | struct acr_desc *acr = &g->acr; | ||
1019 | const struct firmware *acr_fw = acr->acr_fw; | ||
1020 | struct flcn_bl_dmem_desc_v1 *bl_dmem_desc = &acr->bl_dmem_desc_v1; | ||
1021 | u32 *acr_ucode_header_t210_load; | ||
1022 | u32 *acr_ucode_data_t210_load; | ||
1023 | struct wpr_carveout_info wpr_inf; | ||
1024 | |||
1025 | gp106_dbg_pmu(""); | ||
1026 | |||
1027 | if (!acr_fw) { | ||
1028 | /*First time init case*/ | ||
1029 | acr_fw = gk20a_request_firmware(g, GM20B_HSBIN_PMU_UCODE_IMAGE); | ||
1030 | if (!acr_fw) { | ||
1031 | gk20a_err(dev_from_gk20a(g), "pmu ucode get fail"); | ||
1032 | return -ENOENT; | ||
1033 | } | ||
1034 | acr->acr_fw = acr_fw; | ||
1035 | acr->hsbin_hdr = (struct bin_hdr *)acr_fw->data; | ||
1036 | acr->fw_hdr = (struct acr_fw_header *)(acr_fw->data + | ||
1037 | acr->hsbin_hdr->header_offset); | ||
1038 | acr_ucode_data_t210_load = (u32 *)(acr_fw->data + | ||
1039 | acr->hsbin_hdr->data_offset); | ||
1040 | acr_ucode_header_t210_load = (u32 *)(acr_fw->data + | ||
1041 | acr->fw_hdr->hdr_offset); | ||
1042 | img_size_in_bytes = ALIGN((acr->hsbin_hdr->data_size), 256); | ||
1043 | |||
1044 | /* Lets patch the signatures first.. */ | ||
1045 | if (acr_ucode_patch_sig(g, acr_ucode_data_t210_load, | ||
1046 | (u32 *)(acr_fw->data + | ||
1047 | acr->fw_hdr->sig_prod_offset), | ||
1048 | (u32 *)(acr_fw->data + | ||
1049 | acr->fw_hdr->sig_dbg_offset), | ||
1050 | (u32 *)(acr_fw->data + | ||
1051 | acr->fw_hdr->patch_loc), | ||
1052 | (u32 *)(acr_fw->data + | ||
1053 | acr->fw_hdr->patch_sig)) < 0) { | ||
1054 | gk20a_err(dev_from_gk20a(g), "patch signatures fail"); | ||
1055 | err = -1; | ||
1056 | goto err_release_acr_fw; | ||
1057 | } | ||
1058 | err = gk20a_gmmu_alloc_map(vm, img_size_in_bytes, | ||
1059 | &acr->acr_ucode); | ||
1060 | if (err) { | ||
1061 | err = -ENOMEM; | ||
1062 | goto err_release_acr_fw; | ||
1063 | } | ||
1064 | |||
1065 | g->ops.pmu.get_wpr(g, &wpr_inf); | ||
1066 | |||
1067 | acr_dmem = (u64 *) | ||
1068 | &(((u8 *)acr_ucode_data_t210_load)[ | ||
1069 | acr_ucode_header_t210_load[2]]); | ||
1070 | acr->acr_dmem_desc_v1 = (struct flcn_acr_desc_v1 *)((u8 *)( | ||
1071 | acr->acr_ucode.cpu_va) + acr_ucode_header_t210_load[2]); | ||
1072 | ((struct flcn_acr_desc_v1 *)acr_dmem)->nonwpr_ucode_blob_start = | ||
1073 | wpr_inf.nonwpr_base; | ||
1074 | ((struct flcn_acr_desc_v1 *)acr_dmem)->nonwpr_ucode_blob_size = | ||
1075 | wpr_inf.size; | ||
1076 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.no_regions = 1; | ||
1077 | ((struct flcn_acr_desc_v1 *)acr_dmem)->wpr_offset = 0; | ||
1078 | |||
1079 | ((struct flcn_acr_desc_v1 *)acr_dmem)->wpr_region_id = 1; | ||
1080 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1081 | 0].region_id = 1; | ||
1082 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1083 | 0].start_addr = (wpr_inf.wpr_base ) >> 8; | ||
1084 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1085 | 0].end_addr = ((wpr_inf.wpr_base) + wpr_inf.size) >> 8; | ||
1086 | ((struct flcn_acr_desc_v1 *)acr_dmem)->regions.region_props[ | ||
1087 | 0].shadowmMem_startaddress = wpr_inf.nonwpr_base >> 8; | ||
1088 | |||
1089 | gk20a_mem_wr_n(g, &acr->acr_ucode, 0, | ||
1090 | acr_ucode_data_t210_load, img_size_in_bytes); | ||
1091 | |||
1092 | /* | ||
1093 | * In order to execute this binary, we will be using | ||
1094 | * a bootloader which will load this image into PMU IMEM/DMEM. | ||
1095 | * Fill up the bootloader descriptor for PMU HAL to use.. | ||
1096 | * TODO: Use standard descriptor which the generic bootloader is | ||
1097 | * checked in. | ||
1098 | */ | ||
1099 | |||
1100 | bl_dmem_desc->signature[0] = 0; | ||
1101 | bl_dmem_desc->signature[1] = 0; | ||
1102 | bl_dmem_desc->signature[2] = 0; | ||
1103 | bl_dmem_desc->signature[3] = 0; | ||
1104 | bl_dmem_desc->ctx_dma = GK20A_PMU_DMAIDX_VIRT; | ||
1105 | flcn64_set_dma( &bl_dmem_desc->code_dma_base, | ||
1106 | acr->acr_ucode.gpu_va); | ||
1107 | bl_dmem_desc->non_sec_code_off = acr_ucode_header_t210_load[0]; | ||
1108 | bl_dmem_desc->non_sec_code_size = acr_ucode_header_t210_load[1]; | ||
1109 | bl_dmem_desc->sec_code_off = acr_ucode_header_t210_load[5]; | ||
1110 | bl_dmem_desc->sec_code_size = acr_ucode_header_t210_load[6]; | ||
1111 | bl_dmem_desc->code_entry_point = 0; /* Start at 0th offset */ | ||
1112 | flcn64_set_dma( &bl_dmem_desc->data_dma_base, | ||
1113 | acr->acr_ucode.gpu_va + | ||
1114 | (acr_ucode_header_t210_load[2])); | ||
1115 | bl_dmem_desc->data_size = acr_ucode_header_t210_load[3]; | ||
1116 | } else | ||
1117 | acr->acr_dmem_desc->nonwpr_ucode_blob_size = 0; | ||
1118 | |||
1119 | status = pmu_exec_gen_bl(g, bl_dmem_desc, 1); | ||
1120 | if (status != 0) { | ||
1121 | err = status; | ||
1122 | goto err_free_ucode_map; | ||
1123 | } | ||
1124 | return 0; | ||
1125 | err_free_ucode_map: | ||
1126 | gk20a_gmmu_unmap_free(vm, &acr->acr_ucode); | ||
1127 | err_release_acr_fw: | ||
1128 | release_firmware(acr_fw); | ||
1129 | acr->acr_fw = NULL; | ||
1130 | return err; | ||
1131 | } | ||
diff --git a/drivers/gpu/nvgpu/gp106/acr_gp106.h b/drivers/gpu/nvgpu/gp106/acr_gp106.h index 26e68cd7..9afec529 100644 --- a/drivers/gpu/nvgpu/gp106/acr_gp106.h +++ b/drivers/gpu/nvgpu/gp106/acr_gp106.h | |||
@@ -118,4 +118,6 @@ struct flcn_acr_desc_v1 { | |||
118 | u32 dummy[4]; //ACR_BSI_VPR_DESC | 118 | u32 dummy[4]; //ACR_BSI_VPR_DESC |
119 | }; | 119 | }; |
120 | 120 | ||
121 | void gp106_init_secure_pmu(struct gpu_ops *gops); | ||
122 | |||
121 | #endif /*__PMU_GP106_H_*/ | 123 | #endif /*__PMU_GP106_H_*/ |
diff --git a/drivers/gpu/nvgpu/gp106/hw_psec_gp106.h b/drivers/gpu/nvgpu/gp106/hw_psec_gp106.h new file mode 100644 index 00000000..f9c9f69c --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/hw_psec_gp106.h | |||
@@ -0,0 +1,609 @@ | |||
1 | /* | ||
2 | * Copyright (c) 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 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | /* | ||
17 | * Function naming determines intended use: | ||
18 | * | ||
19 | * <x>_r(void) : Returns the offset for register <x>. | ||
20 | * | ||
21 | * <x>_o(void) : Returns the offset for element <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | #ifndef _hw_psec_gp106_h_ | ||
51 | #define _hw_psec_gp106_h_ | ||
52 | |||
53 | static inline u32 psec_falcon_irqsset_r(void) | ||
54 | { | ||
55 | return 0x00087000; | ||
56 | } | ||
57 | static inline u32 psec_falcon_irqsset_swgen0_set_f(void) | ||
58 | { | ||
59 | return 0x40; | ||
60 | } | ||
61 | static inline u32 psec_falcon_irqsclr_r(void) | ||
62 | { | ||
63 | return 0x00087004; | ||
64 | } | ||
65 | static inline u32 psec_falcon_irqstat_r(void) | ||
66 | { | ||
67 | return 0x00087008; | ||
68 | } | ||
69 | static inline u32 psec_falcon_irqstat_halt_true_f(void) | ||
70 | { | ||
71 | return 0x10; | ||
72 | } | ||
73 | static inline u32 psec_falcon_irqstat_exterr_true_f(void) | ||
74 | { | ||
75 | return 0x20; | ||
76 | } | ||
77 | static inline u32 psec_falcon_irqstat_swgen0_true_f(void) | ||
78 | { | ||
79 | return 0x40; | ||
80 | } | ||
81 | static inline u32 psec_falcon_irqmode_r(void) | ||
82 | { | ||
83 | return 0x0008700c; | ||
84 | } | ||
85 | static inline u32 psec_falcon_irqmset_r(void) | ||
86 | { | ||
87 | return 0x00087010; | ||
88 | } | ||
89 | static inline u32 psec_falcon_irqmset_gptmr_f(u32 v) | ||
90 | { | ||
91 | return (v & 0x1) << 0; | ||
92 | } | ||
93 | static inline u32 psec_falcon_irqmset_wdtmr_f(u32 v) | ||
94 | { | ||
95 | return (v & 0x1) << 1; | ||
96 | } | ||
97 | static inline u32 psec_falcon_irqmset_mthd_f(u32 v) | ||
98 | { | ||
99 | return (v & 0x1) << 2; | ||
100 | } | ||
101 | static inline u32 psec_falcon_irqmset_ctxsw_f(u32 v) | ||
102 | { | ||
103 | return (v & 0x1) << 3; | ||
104 | } | ||
105 | static inline u32 psec_falcon_irqmset_halt_f(u32 v) | ||
106 | { | ||
107 | return (v & 0x1) << 4; | ||
108 | } | ||
109 | static inline u32 psec_falcon_irqmset_exterr_f(u32 v) | ||
110 | { | ||
111 | return (v & 0x1) << 5; | ||
112 | } | ||
113 | static inline u32 psec_falcon_irqmset_swgen0_f(u32 v) | ||
114 | { | ||
115 | return (v & 0x1) << 6; | ||
116 | } | ||
117 | static inline u32 psec_falcon_irqmset_swgen1_f(u32 v) | ||
118 | { | ||
119 | return (v & 0x1) << 7; | ||
120 | } | ||
121 | static inline u32 psec_falcon_irqmclr_r(void) | ||
122 | { | ||
123 | return 0x00087014; | ||
124 | } | ||
125 | static inline u32 psec_falcon_irqmclr_gptmr_f(u32 v) | ||
126 | { | ||
127 | return (v & 0x1) << 0; | ||
128 | } | ||
129 | static inline u32 psec_falcon_irqmclr_wdtmr_f(u32 v) | ||
130 | { | ||
131 | return (v & 0x1) << 1; | ||
132 | } | ||
133 | static inline u32 psec_falcon_irqmclr_mthd_f(u32 v) | ||
134 | { | ||
135 | return (v & 0x1) << 2; | ||
136 | } | ||
137 | static inline u32 psec_falcon_irqmclr_ctxsw_f(u32 v) | ||
138 | { | ||
139 | return (v & 0x1) << 3; | ||
140 | } | ||
141 | static inline u32 psec_falcon_irqmclr_halt_f(u32 v) | ||
142 | { | ||
143 | return (v & 0x1) << 4; | ||
144 | } | ||
145 | static inline u32 psec_falcon_irqmclr_exterr_f(u32 v) | ||
146 | { | ||
147 | return (v & 0x1) << 5; | ||
148 | } | ||
149 | static inline u32 psec_falcon_irqmclr_swgen0_f(u32 v) | ||
150 | { | ||
151 | return (v & 0x1) << 6; | ||
152 | } | ||
153 | static inline u32 psec_falcon_irqmclr_swgen1_f(u32 v) | ||
154 | { | ||
155 | return (v & 0x1) << 7; | ||
156 | } | ||
157 | static inline u32 psec_falcon_irqmclr_ext_f(u32 v) | ||
158 | { | ||
159 | return (v & 0xff) << 8; | ||
160 | } | ||
161 | static inline u32 psec_falcon_irqmask_r(void) | ||
162 | { | ||
163 | return 0x00087018; | ||
164 | } | ||
165 | static inline u32 psec_falcon_irqdest_r(void) | ||
166 | { | ||
167 | return 0x0008701c; | ||
168 | } | ||
169 | static inline u32 psec_falcon_irqdest_host_gptmr_f(u32 v) | ||
170 | { | ||
171 | return (v & 0x1) << 0; | ||
172 | } | ||
173 | static inline u32 psec_falcon_irqdest_host_wdtmr_f(u32 v) | ||
174 | { | ||
175 | return (v & 0x1) << 1; | ||
176 | } | ||
177 | static inline u32 psec_falcon_irqdest_host_mthd_f(u32 v) | ||
178 | { | ||
179 | return (v & 0x1) << 2; | ||
180 | } | ||
181 | static inline u32 psec_falcon_irqdest_host_ctxsw_f(u32 v) | ||
182 | { | ||
183 | return (v & 0x1) << 3; | ||
184 | } | ||
185 | static inline u32 psec_falcon_irqdest_host_halt_f(u32 v) | ||
186 | { | ||
187 | return (v & 0x1) << 4; | ||
188 | } | ||
189 | static inline u32 psec_falcon_irqdest_host_exterr_f(u32 v) | ||
190 | { | ||
191 | return (v & 0x1) << 5; | ||
192 | } | ||
193 | static inline u32 psec_falcon_irqdest_host_swgen0_f(u32 v) | ||
194 | { | ||
195 | return (v & 0x1) << 6; | ||
196 | } | ||
197 | static inline u32 psec_falcon_irqdest_host_swgen1_f(u32 v) | ||
198 | { | ||
199 | return (v & 0x1) << 7; | ||
200 | } | ||
201 | static inline u32 psec_falcon_irqdest_host_ext_f(u32 v) | ||
202 | { | ||
203 | return (v & 0xff) << 8; | ||
204 | } | ||
205 | static inline u32 psec_falcon_irqdest_target_gptmr_f(u32 v) | ||
206 | { | ||
207 | return (v & 0x1) << 16; | ||
208 | } | ||
209 | static inline u32 psec_falcon_irqdest_target_wdtmr_f(u32 v) | ||
210 | { | ||
211 | return (v & 0x1) << 17; | ||
212 | } | ||
213 | static inline u32 psec_falcon_irqdest_target_mthd_f(u32 v) | ||
214 | { | ||
215 | return (v & 0x1) << 18; | ||
216 | } | ||
217 | static inline u32 psec_falcon_irqdest_target_ctxsw_f(u32 v) | ||
218 | { | ||
219 | return (v & 0x1) << 19; | ||
220 | } | ||
221 | static inline u32 psec_falcon_irqdest_target_halt_f(u32 v) | ||
222 | { | ||
223 | return (v & 0x1) << 20; | ||
224 | } | ||
225 | static inline u32 psec_falcon_irqdest_target_exterr_f(u32 v) | ||
226 | { | ||
227 | return (v & 0x1) << 21; | ||
228 | } | ||
229 | static inline u32 psec_falcon_irqdest_target_swgen0_f(u32 v) | ||
230 | { | ||
231 | return (v & 0x1) << 22; | ||
232 | } | ||
233 | static inline u32 psec_falcon_irqdest_target_swgen1_f(u32 v) | ||
234 | { | ||
235 | return (v & 0x1) << 23; | ||
236 | } | ||
237 | static inline u32 psec_falcon_irqdest_target_ext_f(u32 v) | ||
238 | { | ||
239 | return (v & 0xff) << 24; | ||
240 | } | ||
241 | static inline u32 psec_falcon_curctx_r(void) | ||
242 | { | ||
243 | return 0x00087050; | ||
244 | } | ||
245 | static inline u32 psec_falcon_nxtctx_r(void) | ||
246 | { | ||
247 | return 0x00087054; | ||
248 | } | ||
249 | static inline u32 psec_falcon_mailbox0_r(void) | ||
250 | { | ||
251 | return 0x00087040; | ||
252 | } | ||
253 | static inline u32 psec_falcon_mailbox1_r(void) | ||
254 | { | ||
255 | return 0x00087044; | ||
256 | } | ||
257 | static inline u32 psec_falcon_itfen_r(void) | ||
258 | { | ||
259 | return 0x00087048; | ||
260 | } | ||
261 | static inline u32 psec_falcon_itfen_ctxen_enable_f(void) | ||
262 | { | ||
263 | return 0x1; | ||
264 | } | ||
265 | static inline u32 psec_falcon_idlestate_r(void) | ||
266 | { | ||
267 | return 0x0008704c; | ||
268 | } | ||
269 | static inline u32 psec_falcon_idlestate_falcon_busy_v(u32 r) | ||
270 | { | ||
271 | return (r >> 0) & 0x1; | ||
272 | } | ||
273 | static inline u32 psec_falcon_idlestate_ext_busy_v(u32 r) | ||
274 | { | ||
275 | return (r >> 1) & 0x7fff; | ||
276 | } | ||
277 | static inline u32 psec_falcon_os_r(void) | ||
278 | { | ||
279 | return 0x00087080; | ||
280 | } | ||
281 | static inline u32 psec_falcon_engctl_r(void) | ||
282 | { | ||
283 | return 0x000870a4; | ||
284 | } | ||
285 | static inline u32 psec_falcon_cpuctl_r(void) | ||
286 | { | ||
287 | return 0x00087100; | ||
288 | } | ||
289 | static inline u32 psec_falcon_cpuctl_startcpu_f(u32 v) | ||
290 | { | ||
291 | return (v & 0x1) << 1; | ||
292 | } | ||
293 | static inline u32 psec_falcon_cpuctl_halt_intr_f(u32 v) | ||
294 | { | ||
295 | return (v & 0x1) << 4; | ||
296 | } | ||
297 | static inline u32 psec_falcon_cpuctl_halt_intr_m(void) | ||
298 | { | ||
299 | return 0x1 << 4; | ||
300 | } | ||
301 | static inline u32 psec_falcon_cpuctl_halt_intr_v(u32 r) | ||
302 | { | ||
303 | return (r >> 4) & 0x1; | ||
304 | } | ||
305 | static inline u32 psec_falcon_cpuctl_cpuctl_alias_en_f(u32 v) | ||
306 | { | ||
307 | return (v & 0x1) << 6; | ||
308 | } | ||
309 | static inline u32 psec_falcon_cpuctl_cpuctl_alias_en_m(void) | ||
310 | { | ||
311 | return 0x1 << 6; | ||
312 | } | ||
313 | static inline u32 psec_falcon_cpuctl_cpuctl_alias_en_v(u32 r) | ||
314 | { | ||
315 | return (r >> 6) & 0x1; | ||
316 | } | ||
317 | static inline u32 psec_falcon_cpuctl_alias_r(void) | ||
318 | { | ||
319 | return 0x00087130; | ||
320 | } | ||
321 | static inline u32 psec_falcon_cpuctl_alias_startcpu_f(u32 v) | ||
322 | { | ||
323 | return (v & 0x1) << 1; | ||
324 | } | ||
325 | static inline u32 psec_falcon_imemc_r(u32 i) | ||
326 | { | ||
327 | return 0x00087180 + i*16; | ||
328 | } | ||
329 | static inline u32 psec_falcon_imemc_offs_f(u32 v) | ||
330 | { | ||
331 | return (v & 0x3f) << 2; | ||
332 | } | ||
333 | static inline u32 psec_falcon_imemc_blk_f(u32 v) | ||
334 | { | ||
335 | return (v & 0xff) << 8; | ||
336 | } | ||
337 | static inline u32 psec_falcon_imemc_aincw_f(u32 v) | ||
338 | { | ||
339 | return (v & 0x1) << 24; | ||
340 | } | ||
341 | static inline u32 psec_falcon_imemd_r(u32 i) | ||
342 | { | ||
343 | return 0x00087184 + i*16; | ||
344 | } | ||
345 | static inline u32 psec_falcon_imemt_r(u32 i) | ||
346 | { | ||
347 | return 0x00087188 + i*16; | ||
348 | } | ||
349 | static inline u32 psec_falcon_sctl_r(void) | ||
350 | { | ||
351 | return 0x00087240; | ||
352 | } | ||
353 | static inline u32 psec_falcon_mmu_phys_sec_r(void) | ||
354 | { | ||
355 | return 0x00100ce4; | ||
356 | } | ||
357 | static inline u32 psec_falcon_bootvec_r(void) | ||
358 | { | ||
359 | return 0x00087104; | ||
360 | } | ||
361 | static inline u32 psec_falcon_bootvec_vec_f(u32 v) | ||
362 | { | ||
363 | return (v & 0xffffffff) << 0; | ||
364 | } | ||
365 | static inline u32 psec_falcon_dmactl_r(void) | ||
366 | { | ||
367 | return 0x0008710c; | ||
368 | } | ||
369 | static inline u32 psec_falcon_dmactl_dmem_scrubbing_m(void) | ||
370 | { | ||
371 | return 0x1 << 1; | ||
372 | } | ||
373 | static inline u32 psec_falcon_dmactl_imem_scrubbing_m(void) | ||
374 | { | ||
375 | return 0x1 << 2; | ||
376 | } | ||
377 | static inline u32 psec_falcon_dmactl_require_ctx_f(u32 v) | ||
378 | { | ||
379 | return (v & 0x1) << 0; | ||
380 | } | ||
381 | static inline u32 psec_falcon_hwcfg_r(void) | ||
382 | { | ||
383 | return 0x00087108; | ||
384 | } | ||
385 | static inline u32 psec_falcon_hwcfg_imem_size_v(u32 r) | ||
386 | { | ||
387 | return (r >> 0) & 0x1ff; | ||
388 | } | ||
389 | static inline u32 psec_falcon_hwcfg_dmem_size_v(u32 r) | ||
390 | { | ||
391 | return (r >> 9) & 0x1ff; | ||
392 | } | ||
393 | static inline u32 psec_falcon_dmatrfbase_r(void) | ||
394 | { | ||
395 | return 0x00087110; | ||
396 | } | ||
397 | static inline u32 psec_falcon_dmatrfbase1_r(void) | ||
398 | { | ||
399 | return 0x00087128; | ||
400 | } | ||
401 | static inline u32 psec_falcon_dmatrfmoffs_r(void) | ||
402 | { | ||
403 | return 0x00087114; | ||
404 | } | ||
405 | static inline u32 psec_falcon_dmatrfcmd_r(void) | ||
406 | { | ||
407 | return 0x00087118; | ||
408 | } | ||
409 | static inline u32 psec_falcon_dmatrfcmd_imem_f(u32 v) | ||
410 | { | ||
411 | return (v & 0x1) << 4; | ||
412 | } | ||
413 | static inline u32 psec_falcon_dmatrfcmd_write_f(u32 v) | ||
414 | { | ||
415 | return (v & 0x1) << 5; | ||
416 | } | ||
417 | static inline u32 psec_falcon_dmatrfcmd_size_f(u32 v) | ||
418 | { | ||
419 | return (v & 0x7) << 8; | ||
420 | } | ||
421 | static inline u32 psec_falcon_dmatrfcmd_ctxdma_f(u32 v) | ||
422 | { | ||
423 | return (v & 0x7) << 12; | ||
424 | } | ||
425 | static inline u32 psec_falcon_dmatrffboffs_r(void) | ||
426 | { | ||
427 | return 0x0008711c; | ||
428 | } | ||
429 | static inline u32 psec_falcon_exterraddr_r(void) | ||
430 | { | ||
431 | return 0x00087168; | ||
432 | } | ||
433 | static inline u32 psec_falcon_exterrstat_r(void) | ||
434 | { | ||
435 | return 0x0008716c; | ||
436 | } | ||
437 | static inline u32 psec_falcon_exterrstat_valid_m(void) | ||
438 | { | ||
439 | return 0x1 << 31; | ||
440 | } | ||
441 | static inline u32 psec_falcon_exterrstat_valid_v(u32 r) | ||
442 | { | ||
443 | return (r >> 31) & 0x1; | ||
444 | } | ||
445 | static inline u32 psec_falcon_exterrstat_valid_true_v(void) | ||
446 | { | ||
447 | return 0x00000001; | ||
448 | } | ||
449 | static inline u32 psec_sec2_falcon_icd_cmd_r(void) | ||
450 | { | ||
451 | return 0x00087200; | ||
452 | } | ||
453 | static inline u32 psec_sec2_falcon_icd_cmd_opc_s(void) | ||
454 | { | ||
455 | return 4; | ||
456 | } | ||
457 | static inline u32 psec_sec2_falcon_icd_cmd_opc_f(u32 v) | ||
458 | { | ||
459 | return (v & 0xf) << 0; | ||
460 | } | ||
461 | static inline u32 psec_sec2_falcon_icd_cmd_opc_m(void) | ||
462 | { | ||
463 | return 0xf << 0; | ||
464 | } | ||
465 | static inline u32 psec_sec2_falcon_icd_cmd_opc_v(u32 r) | ||
466 | { | ||
467 | return (r >> 0) & 0xf; | ||
468 | } | ||
469 | static inline u32 psec_sec2_falcon_icd_cmd_opc_rreg_f(void) | ||
470 | { | ||
471 | return 0x8; | ||
472 | } | ||
473 | static inline u32 psec_sec2_falcon_icd_cmd_opc_rstat_f(void) | ||
474 | { | ||
475 | return 0xe; | ||
476 | } | ||
477 | static inline u32 psec_sec2_falcon_icd_cmd_idx_f(u32 v) | ||
478 | { | ||
479 | return (v & 0x1f) << 8; | ||
480 | } | ||
481 | static inline u32 psec_sec2_falcon_icd_rdata_r(void) | ||
482 | { | ||
483 | return 0x0008720c; | ||
484 | } | ||
485 | static inline u32 psec_falcon_dmemc_r(u32 i) | ||
486 | { | ||
487 | return 0x000871c0 + i*8; | ||
488 | } | ||
489 | static inline u32 psec_falcon_dmemc_offs_f(u32 v) | ||
490 | { | ||
491 | return (v & 0x3f) << 2; | ||
492 | } | ||
493 | static inline u32 psec_falcon_dmemc_offs_m(void) | ||
494 | { | ||
495 | return 0x3f << 2; | ||
496 | } | ||
497 | static inline u32 psec_falcon_dmemc_blk_f(u32 v) | ||
498 | { | ||
499 | return (v & 0xff) << 8; | ||
500 | } | ||
501 | static inline u32 psec_falcon_dmemc_blk_m(void) | ||
502 | { | ||
503 | return 0xff << 8; | ||
504 | } | ||
505 | static inline u32 psec_falcon_dmemc_aincw_f(u32 v) | ||
506 | { | ||
507 | return (v & 0x1) << 24; | ||
508 | } | ||
509 | static inline u32 psec_falcon_dmemc_aincr_f(u32 v) | ||
510 | { | ||
511 | return (v & 0x1) << 25; | ||
512 | } | ||
513 | static inline u32 psec_falcon_dmemd_r(u32 i) | ||
514 | { | ||
515 | return 0x000871c4 + i*8; | ||
516 | } | ||
517 | static inline u32 psec_falcon_debug1_r(void) | ||
518 | { | ||
519 | return 0x00087090; | ||
520 | } | ||
521 | static inline u32 psec_falcon_debug1_ctxsw_mode_s(void) | ||
522 | { | ||
523 | return 1; | ||
524 | } | ||
525 | static inline u32 psec_falcon_debug1_ctxsw_mode_f(u32 v) | ||
526 | { | ||
527 | return (v & 0x1) << 16; | ||
528 | } | ||
529 | static inline u32 psec_falcon_debug1_ctxsw_mode_m(void) | ||
530 | { | ||
531 | return 0x1 << 16; | ||
532 | } | ||
533 | static inline u32 psec_falcon_debug1_ctxsw_mode_v(u32 r) | ||
534 | { | ||
535 | return (r >> 16) & 0x1; | ||
536 | } | ||
537 | static inline u32 psec_falcon_debug1_ctxsw_mode_init_f(void) | ||
538 | { | ||
539 | return 0x0; | ||
540 | } | ||
541 | static inline u32 psec_fbif_transcfg_r(u32 i) | ||
542 | { | ||
543 | return 0x00087600 + i*4; | ||
544 | } | ||
545 | static inline u32 psec_fbif_transcfg_target_local_fb_f(void) | ||
546 | { | ||
547 | return 0x0; | ||
548 | } | ||
549 | static inline u32 psec_fbif_transcfg_target_coherent_sysmem_f(void) | ||
550 | { | ||
551 | return 0x1; | ||
552 | } | ||
553 | static inline u32 psec_fbif_transcfg_target_noncoherent_sysmem_f(void) | ||
554 | { | ||
555 | return 0x2; | ||
556 | } | ||
557 | static inline u32 psec_fbif_transcfg_mem_type_s(void) | ||
558 | { | ||
559 | return 1; | ||
560 | } | ||
561 | static inline u32 psec_fbif_transcfg_mem_type_f(u32 v) | ||
562 | { | ||
563 | return (v & 0x1) << 2; | ||
564 | } | ||
565 | static inline u32 psec_fbif_transcfg_mem_type_m(void) | ||
566 | { | ||
567 | return 0x1 << 2; | ||
568 | } | ||
569 | static inline u32 psec_fbif_transcfg_mem_type_v(u32 r) | ||
570 | { | ||
571 | return (r >> 2) & 0x1; | ||
572 | } | ||
573 | static inline u32 psec_fbif_transcfg_mem_type_virtual_f(void) | ||
574 | { | ||
575 | return 0x0; | ||
576 | } | ||
577 | static inline u32 psec_fbif_transcfg_mem_type_physical_f(void) | ||
578 | { | ||
579 | return 0x4; | ||
580 | } | ||
581 | static inline u32 psec_falcon_engine_r(void) | ||
582 | { | ||
583 | return 0x000873c0; | ||
584 | } | ||
585 | static inline u32 psec_falcon_engine_reset_true_f(void) | ||
586 | { | ||
587 | return 0x1; | ||
588 | } | ||
589 | static inline u32 psec_falcon_engine_reset_false_f(void) | ||
590 | { | ||
591 | return 0x0; | ||
592 | } | ||
593 | static inline u32 psec_fbif_ctl_r(void) | ||
594 | { | ||
595 | return 0x00087624; | ||
596 | } | ||
597 | static inline u32 psec_fbif_ctl_allow_phys_no_ctx_init_f(void) | ||
598 | { | ||
599 | return 0x0; | ||
600 | } | ||
601 | static inline u32 psec_fbif_ctl_allow_phys_no_ctx_disallow_f(void) | ||
602 | { | ||
603 | return 0x0; | ||
604 | } | ||
605 | static inline u32 psec_fbif_ctl_allow_phys_no_ctx_allow_f(void) | ||
606 | { | ||
607 | return 0x80; | ||
608 | } | ||
609 | #endif | ||
diff --git a/drivers/gpu/nvgpu/gp106/sec2_gp106.c b/drivers/gpu/nvgpu/gp106/sec2_gp106.c new file mode 100644 index 00000000..f8b32f8f --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/sec2_gp106.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * Copyright (c) 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 udelay */ | ||
15 | #include <linux/clk.h> | ||
16 | #include "gk20a/gk20a.h" | ||
17 | #include "gk20a/pmu_gk20a.h" | ||
18 | |||
19 | #include "gm206/pmu_gm206.h" | ||
20 | #include "gm20b/pmu_gm20b.h" | ||
21 | #include "gp10b/pmu_gp10b.h" | ||
22 | #include "gp106/pmu_gp106.h" | ||
23 | #include "gp106/acr_gp106.h" | ||
24 | #include "gp106/hw_mc_gp106.h" | ||
25 | #include "gp106/hw_pwr_gp106.h" | ||
26 | #include "gp106/hw_psec_gp106.h" | ||
27 | #include "sec2_gp106.h" | ||
28 | #include "acr.h" | ||
29 | |||
30 | /*Defines*/ | ||
31 | #define gm20b_dbg_pmu(fmt, arg...) \ | ||
32 | gk20a_dbg(gpu_dbg_pmu, fmt, ##arg) | ||
33 | |||
34 | int sec2_clear_halt_interrupt_status(struct gk20a *g, unsigned int timeout) | ||
35 | { | ||
36 | u32 data = 0; | ||
37 | unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); | ||
38 | |||
39 | while (time_before(jiffies, end_jiffies) || | ||
40 | !tegra_platform_is_silicon()) { | ||
41 | gk20a_writel(g, psec_falcon_irqsclr_r(), | ||
42 | gk20a_readl(g, psec_falcon_irqsclr_r()) | (0x10)); | ||
43 | data = gk20a_readl(g, psec_falcon_irqstat_r()); | ||
44 | if ((data & psec_falcon_irqstat_halt_true_f()) != | ||
45 | psec_falcon_irqstat_halt_true_f()) | ||
46 | /*halt irq is clear*/ | ||
47 | break; | ||
48 | timeout--; | ||
49 | udelay(1); | ||
50 | } | ||
51 | if (timeout == 0) | ||
52 | return -EBUSY; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | int sec2_wait_for_halt(struct gk20a *g, unsigned int timeout) | ||
57 | { | ||
58 | u32 data = 0; | ||
59 | int completion = -EBUSY; | ||
60 | unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); | ||
61 | |||
62 | while (time_before(jiffies, end_jiffies) || | ||
63 | !tegra_platform_is_silicon()) { | ||
64 | data = gk20a_readl(g, psec_falcon_cpuctl_r()); | ||
65 | if (data & psec_falcon_cpuctl_halt_intr_m()) { | ||
66 | /*CPU is halted break*/ | ||
67 | completion = 0; | ||
68 | break; | ||
69 | } | ||
70 | udelay(1); | ||
71 | } | ||
72 | if (completion){ | ||
73 | gk20a_err(dev_from_gk20a(g), "ACR boot timed out"); | ||
74 | } | ||
75 | else { | ||
76 | |||
77 | g->acr.capabilities = gk20a_readl(g, psec_falcon_mailbox1_r()); | ||
78 | gm20b_dbg_pmu("ACR capabilities %x\n", g->acr.capabilities); | ||
79 | data = gk20a_readl(g, psec_falcon_mailbox0_r()); | ||
80 | if (data) { | ||
81 | |||
82 | gk20a_err(dev_from_gk20a(g), | ||
83 | "ACR boot failed, err %x", data); | ||
84 | completion = -EAGAIN; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | init_pmu_setup_hw1(g); | ||
89 | |||
90 | return completion; | ||
91 | } | ||
92 | |||
93 | void sec2_copy_to_dmem(struct pmu_gk20a *pmu, | ||
94 | u32 dst, u8 *src, u32 size, u8 port) | ||
95 | { | ||
96 | struct gk20a *g = gk20a_from_pmu(pmu); | ||
97 | u32 i, words, bytes; | ||
98 | u32 data, addr_mask; | ||
99 | u32 *src_u32 = (u32*)src; | ||
100 | |||
101 | if (size == 0) { | ||
102 | gk20a_err(dev_from_gk20a(g), | ||
103 | "size is zero"); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | if (dst & 0x3) { | ||
108 | gk20a_err(dev_from_gk20a(g), | ||
109 | "dst (0x%08x) not 4-byte aligned", dst); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | mutex_lock(&pmu->pmu_copy_lock); | ||
114 | |||
115 | words = size >> 2; | ||
116 | bytes = size & 0x3; | ||
117 | |||
118 | addr_mask = psec_falcon_dmemc_offs_m() | | ||
119 | psec_falcon_dmemc_blk_m(); | ||
120 | |||
121 | dst &= addr_mask; | ||
122 | |||
123 | gk20a_writel(g, psec_falcon_dmemc_r(port), | ||
124 | dst | psec_falcon_dmemc_aincw_f(1)); | ||
125 | |||
126 | for (i = 0; i < words; i++) | ||
127 | gk20a_writel(g, psec_falcon_dmemd_r(port), src_u32[i]); | ||
128 | |||
129 | if (bytes > 0) { | ||
130 | data = 0; | ||
131 | for (i = 0; i < bytes; i++) | ||
132 | ((u8 *)&data)[i] = src[(words << 2) + i]; | ||
133 | gk20a_writel(g, psec_falcon_dmemd_r(port), data); | ||
134 | } | ||
135 | |||
136 | data = gk20a_readl(g, psec_falcon_dmemc_r(port)) & addr_mask; | ||
137 | size = ALIGN(size, 4); | ||
138 | if (data != dst + size) { | ||
139 | gk20a_err(dev_from_gk20a(g), | ||
140 | "copy failed. bytes written %d, expected %d", | ||
141 | data - dst, size); | ||
142 | } | ||
143 | mutex_unlock(&pmu->pmu_copy_lock); | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | int bl_bootstrap_sec2(struct pmu_gk20a *pmu, | ||
148 | void *desc, u32 bl_sz) | ||
149 | { | ||
150 | struct gk20a *g = gk20a_from_pmu(pmu); | ||
151 | struct acr_desc *acr = &g->acr; | ||
152 | struct mm_gk20a *mm = &g->mm; | ||
153 | u32 imem_dst_blk = 0; | ||
154 | u32 virt_addr = 0; | ||
155 | u32 tag = 0; | ||
156 | u32 index = 0; | ||
157 | struct hsflcn_bl_desc *pmu_bl_gm10x_desc = g->acr.pmu_hsbl_desc; | ||
158 | u32 *bl_ucode; | ||
159 | u32 data = 0; | ||
160 | |||
161 | gk20a_dbg_fn(""); | ||
162 | |||
163 | /* SEC2 Config */ | ||
164 | gk20a_writel(g, psec_falcon_itfen_r(), | ||
165 | gk20a_readl(g, psec_falcon_itfen_r()) | | ||
166 | psec_falcon_itfen_ctxen_enable_f()); | ||
167 | |||
168 | gk20a_writel(g, psec_falcon_nxtctx_r(), | ||
169 | pwr_pmu_new_instblk_ptr_f( | ||
170 | gk20a_mm_inst_block_addr(g, &mm->pmu.inst_block) >> 12) | | ||
171 | pwr_pmu_new_instblk_valid_f(1) | | ||
172 | pwr_pmu_new_instblk_target_sys_coh_f()); | ||
173 | |||
174 | data = gk20a_readl(g, psec_falcon_debug1_r()); | ||
175 | data |= psec_falcon_debug1_ctxsw_mode_m(); | ||
176 | gk20a_writel(g, psec_falcon_debug1_r(), data); | ||
177 | |||
178 | data = gk20a_readl(g, psec_falcon_engctl_r()); | ||
179 | data |= (1 << 3); | ||
180 | gk20a_writel(g, psec_falcon_engctl_r(), data); | ||
181 | |||
182 | /* TBD: load all other surfaces */ | ||
183 | /*copy bootloader interface structure to dmem*/ | ||
184 | gk20a_writel(g, psec_falcon_dmemc_r(0), | ||
185 | psec_falcon_dmemc_offs_f(0) | | ||
186 | psec_falcon_dmemc_blk_f(0) | | ||
187 | psec_falcon_dmemc_aincw_f(1)); | ||
188 | sec2_copy_to_dmem(pmu, 0, (u8 *)desc, | ||
189 | sizeof(struct flcn_bl_dmem_desc), 0); | ||
190 | /*TODO This had to be copied to bl_desc_dmem_load_off, but since | ||
191 | * this is 0, so ok for now*/ | ||
192 | |||
193 | /* Now copy bootloader to TOP of IMEM */ | ||
194 | imem_dst_blk = (psec_falcon_hwcfg_imem_size_v( | ||
195 | gk20a_readl(g, psec_falcon_hwcfg_r()))) - bl_sz/256; | ||
196 | |||
197 | /* Set Auto-Increment on write */ | ||
198 | gk20a_writel(g, psec_falcon_imemc_r(0), | ||
199 | psec_falcon_imemc_offs_f(0) | | ||
200 | psec_falcon_imemc_blk_f(imem_dst_blk) | | ||
201 | psec_falcon_imemc_aincw_f(1)); | ||
202 | virt_addr = pmu_bl_gm10x_desc->bl_start_tag << 8; | ||
203 | tag = virt_addr >> 8; /* tag is always 256B aligned */ | ||
204 | bl_ucode = (u32 *)(acr->hsbl_ucode.cpu_va); | ||
205 | for (index = 0; index < bl_sz/4; index++) { | ||
206 | if ((index % 64) == 0) { | ||
207 | gk20a_writel(g, psec_falcon_imemt_r(0), | ||
208 | (tag & 0xffff) << 0); | ||
209 | tag++; | ||
210 | } | ||
211 | gk20a_writel(g, psec_falcon_imemd_r(0), | ||
212 | bl_ucode[index] & 0xffffffff); | ||
213 | } | ||
214 | gk20a_writel(g, psec_falcon_imemt_r(0), (0 & 0xffff) << 0); | ||
215 | |||
216 | gm20b_dbg_pmu("Before starting falcon with BL\n"); | ||
217 | |||
218 | gk20a_writel(g, psec_falcon_mailbox0_r(), 0xDEADA5A5); | ||
219 | |||
220 | gk20a_writel(g, psec_falcon_bootvec_r(), | ||
221 | psec_falcon_bootvec_vec_f(virt_addr)); | ||
222 | |||
223 | gk20a_writel(g, psec_falcon_cpuctl_r(), | ||
224 | psec_falcon_cpuctl_startcpu_f(1)); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | void sec_enable_irq(struct pmu_gk20a *pmu, bool enable) | ||
230 | { | ||
231 | struct gk20a *g = gk20a_from_pmu(pmu); | ||
232 | |||
233 | gk20a_dbg_fn(""); | ||
234 | |||
235 | gk20a_writel(g, psec_falcon_irqmclr_r(), | ||
236 | psec_falcon_irqmclr_gptmr_f(1) | | ||
237 | psec_falcon_irqmclr_wdtmr_f(1) | | ||
238 | psec_falcon_irqmclr_mthd_f(1) | | ||
239 | psec_falcon_irqmclr_ctxsw_f(1) | | ||
240 | psec_falcon_irqmclr_halt_f(1) | | ||
241 | psec_falcon_irqmclr_exterr_f(1) | | ||
242 | psec_falcon_irqmclr_swgen0_f(1) | | ||
243 | psec_falcon_irqmclr_swgen1_f(1) | | ||
244 | psec_falcon_irqmclr_ext_f(0xff)); | ||
245 | |||
246 | if (enable) { | ||
247 | /* dest 0=falcon, 1=host; level 0=irq0, 1=irq1 */ | ||
248 | gk20a_writel(g, psec_falcon_irqdest_r(), | ||
249 | psec_falcon_irqdest_host_gptmr_f(0) | | ||
250 | psec_falcon_irqdest_host_wdtmr_f(1) | | ||
251 | psec_falcon_irqdest_host_mthd_f(0) | | ||
252 | psec_falcon_irqdest_host_ctxsw_f(0) | | ||
253 | psec_falcon_irqdest_host_halt_f(1) | | ||
254 | psec_falcon_irqdest_host_exterr_f(0) | | ||
255 | psec_falcon_irqdest_host_swgen0_f(1) | | ||
256 | psec_falcon_irqdest_host_swgen1_f(0) | | ||
257 | psec_falcon_irqdest_host_ext_f(0xff) | | ||
258 | psec_falcon_irqdest_target_gptmr_f(1) | | ||
259 | psec_falcon_irqdest_target_wdtmr_f(0) | | ||
260 | psec_falcon_irqdest_target_mthd_f(0) | | ||
261 | psec_falcon_irqdest_target_ctxsw_f(0) | | ||
262 | psec_falcon_irqdest_target_halt_f(0) | | ||
263 | psec_falcon_irqdest_target_exterr_f(0) | | ||
264 | psec_falcon_irqdest_target_swgen0_f(0) | | ||
265 | psec_falcon_irqdest_target_swgen1_f(1) | | ||
266 | psec_falcon_irqdest_target_ext_f(0xff)); | ||
267 | |||
268 | /* 0=disable, 1=enable */ | ||
269 | gk20a_writel(g, psec_falcon_irqmset_r(), | ||
270 | psec_falcon_irqmset_gptmr_f(1) | | ||
271 | psec_falcon_irqmset_wdtmr_f(1) | | ||
272 | psec_falcon_irqmset_mthd_f(0) | | ||
273 | psec_falcon_irqmset_ctxsw_f(0) | | ||
274 | psec_falcon_irqmset_halt_f(1) | | ||
275 | psec_falcon_irqmset_exterr_f(1) | | ||
276 | psec_falcon_irqmset_swgen0_f(1) | | ||
277 | psec_falcon_irqmset_swgen1_f(1)); | ||
278 | |||
279 | } | ||
280 | |||
281 | gk20a_dbg_fn("done"); | ||
282 | } | ||
283 | |||
284 | void init_pmu_setup_hw1(struct gk20a *g) | ||
285 | { | ||
286 | struct mm_gk20a *mm = &g->mm; | ||
287 | struct pmu_gk20a *pmu = &g->pmu; | ||
288 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | ||
289 | |||
290 | /* PMU TRANSCFG */ | ||
291 | /* setup apertures - virtual */ | ||
292 | gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_UCODE), | ||
293 | pwr_fbif_transcfg_mem_type_physical_f() | | ||
294 | pwr_fbif_transcfg_target_local_fb_f()); | ||
295 | gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_VIRT), | ||
296 | pwr_fbif_transcfg_mem_type_virtual_f()); | ||
297 | /* setup apertures - physical */ | ||
298 | gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_VID), | ||
299 | pwr_fbif_transcfg_mem_type_physical_f() | | ||
300 | pwr_fbif_transcfg_target_local_fb_f()); | ||
301 | gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_COH), | ||
302 | pwr_fbif_transcfg_mem_type_physical_f() | | ||
303 | pwr_fbif_transcfg_target_coherent_sysmem_f()); | ||
304 | gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_NCOH), | ||
305 | pwr_fbif_transcfg_mem_type_physical_f() | | ||
306 | pwr_fbif_transcfg_target_noncoherent_sysmem_f()); | ||
307 | |||
308 | /* PMU Config */ | ||
309 | gk20a_writel(g, pwr_falcon_itfen_r(), | ||
310 | gk20a_readl(g, pwr_falcon_itfen_r()) | | ||
311 | pwr_falcon_itfen_ctxen_enable_f()); | ||
312 | gk20a_writel(g, pwr_pmu_new_instblk_r(), | ||
313 | pwr_pmu_new_instblk_ptr_f( | ||
314 | gk20a_mm_inst_block_addr(g, &mm->pmu.inst_block) >> 12) | | ||
315 | pwr_pmu_new_instblk_valid_f(1) | | ||
316 | pwr_pmu_new_instblk_target_sys_coh_f()); | ||
317 | |||
318 | /*Copying pmu cmdline args*/ | ||
319 | g->ops.pmu_ver.set_pmu_cmdline_args_cpu_freq(pmu, | ||
320 | clk_get_rate(platform->clk[1])); | ||
321 | g->ops.pmu_ver.set_pmu_cmdline_args_secure_mode(pmu, 1); | ||
322 | g->ops.pmu_ver.set_pmu_cmdline_args_trace_size( | ||
323 | pmu, GK20A_PMU_TRACE_BUFSIZE); | ||
324 | g->ops.pmu_ver.set_pmu_cmdline_args_trace_dma_base(pmu); | ||
325 | g->ops.pmu_ver.set_pmu_cmdline_args_trace_dma_idx( | ||
326 | pmu, GK20A_PMU_DMAIDX_VIRT); | ||
327 | |||
328 | pmu_copy_to_dmem(pmu, g->acr.pmu_args, | ||
329 | (u8 *)(g->ops.pmu_ver.get_pmu_cmdline_args_ptr(pmu)), | ||
330 | g->ops.pmu_ver.get_pmu_cmdline_args_size(pmu), 0); | ||
331 | |||
332 | } | ||
333 | |||
334 | int init_sec2_setup_hw1(struct gk20a *g, | ||
335 | void *desc, u32 bl_sz) | ||
336 | { | ||
337 | struct pmu_gk20a *pmu = &g->pmu; | ||
338 | int err; | ||
339 | u32 data = 0; | ||
340 | |||
341 | gk20a_dbg_fn(""); | ||
342 | |||
343 | mutex_lock(&pmu->isr_mutex); | ||
344 | g->ops.pmu.reset(g); | ||
345 | pmu->isr_enabled = true; | ||
346 | mutex_unlock(&pmu->isr_mutex); | ||
347 | |||
348 | data = gk20a_readl(g, psec_fbif_ctl_r()); | ||
349 | data |= psec_fbif_ctl_allow_phys_no_ctx_allow_f(); | ||
350 | gk20a_writel(g, psec_fbif_ctl_r(), data); | ||
351 | |||
352 | data = gk20a_readl(g, psec_falcon_dmactl_r()); | ||
353 | data &= ~(psec_falcon_dmactl_require_ctx_f(1)); | ||
354 | gk20a_writel(g, psec_falcon_dmactl_r(), data); | ||
355 | |||
356 | /* setup apertures - virtual */ | ||
357 | gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_UCODE), | ||
358 | psec_fbif_transcfg_mem_type_physical_f() | | ||
359 | psec_fbif_transcfg_target_local_fb_f()); | ||
360 | gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_VIRT), | ||
361 | psec_fbif_transcfg_mem_type_virtual_f()); | ||
362 | /* setup apertures - physical */ | ||
363 | gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_VID), | ||
364 | psec_fbif_transcfg_mem_type_physical_f() | | ||
365 | psec_fbif_transcfg_target_local_fb_f()); | ||
366 | gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_COH), | ||
367 | psec_fbif_transcfg_mem_type_physical_f() | | ||
368 | psec_fbif_transcfg_target_coherent_sysmem_f()); | ||
369 | gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_NCOH), | ||
370 | psec_fbif_transcfg_mem_type_physical_f() | | ||
371 | psec_fbif_transcfg_target_noncoherent_sysmem_f()); | ||
372 | |||
373 | /*disable irqs for hs falcon booting as we will poll for halt*/ | ||
374 | mutex_lock(&pmu->isr_mutex); | ||
375 | pmu_enable_irq(pmu, false); | ||
376 | sec_enable_irq(pmu, false); | ||
377 | pmu->isr_enabled = false; | ||
378 | mutex_unlock(&pmu->isr_mutex); | ||
379 | err = bl_bootstrap_sec2(pmu, desc, bl_sz); | ||
380 | if (err) | ||
381 | return err; | ||
382 | |||
383 | return 0; | ||
384 | } | ||
diff --git a/drivers/gpu/nvgpu/gp106/sec2_gp106.h b/drivers/gpu/nvgpu/gp106/sec2_gp106.h new file mode 100644 index 00000000..336bb0f0 --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/sec2_gp106.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (c) 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 | #ifndef __SEC2_H_ | ||
15 | #define __SEC2_H_ | ||
16 | |||
17 | int sec2_clear_halt_interrupt_status(struct gk20a *g, unsigned int timeout); | ||
18 | int sec2_wait_for_halt(struct gk20a *g, unsigned int timeout); | ||
19 | void sec2_copy_to_dmem(struct pmu_gk20a *pmu, | ||
20 | u32 dst, u8 *src, u32 size, u8 port); | ||
21 | void sec2_dump_falcon_stats(struct pmu_gk20a *pmu); | ||
22 | int bl_bootstrap_sec2(struct pmu_gk20a *pmu, | ||
23 | void *desc, u32 bl_sz); | ||
24 | void sec_enable_irq(struct pmu_gk20a *pmu, bool enable); | ||
25 | void init_pmu_setup_hw1(struct gk20a *g); | ||
26 | int init_sec2_setup_hw1(struct gk20a *g, | ||
27 | void *desc, u32 bl_sz); | ||
28 | |||
29 | #endif /*__SEC2_H_*/ | ||