summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2016-06-08 07:57:49 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:17 -0500
commit6ed3cffb73488b22d671c88d30061cd045417378 (patch)
tree8993140fd548fa76ad6f634985de91790ffdf15c
parent7b43eac2bc1e9e5946f1c721686f841af0550aef (diff)
gpu: nvgpu: ACR boot on SEC2
ACR/SEC2 methods to support ACR boot SEC2 falcon JIRA DNVGPU-34 Change-Id: I917be1d6c61a1c1ae61a918f50228ea00492cd50 Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1161122 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/gp106/acr_gp106.c1131
-rw-r--r--drivers/gpu/nvgpu/gp106/acr_gp106.h2
-rw-r--r--drivers/gpu/nvgpu/gp106/hw_psec_gp106.h609
-rw-r--r--drivers/gpu/nvgpu/gp106/sec2_gp106.c384
-rw-r--r--drivers/gpu/nvgpu/gp106/sec2_gp106.h29
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
35typedef 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*/
47static int pmu_ucode_details(struct gk20a *g, struct flcn_ucode_img_v1 *p_img);
48static int fecs_ucode_details(struct gk20a *g,
49 struct flcn_ucode_img_v1 *p_img);
50static int gpccs_ucode_details(struct gk20a *g,
51 struct flcn_ucode_img_v1 *p_img);
52static int gp106_bootstrap_hs_flcn(struct gk20a *g);
53
54static int lsfm_discover_ucode_images(struct gk20a *g,
55 struct ls_flcn_mgr_v1 *plsfm);
56static 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);
58static void lsfm_free_ucode_img_res(struct flcn_ucode_img_v1 *p_img);
59static void lsfm_free_nonpmu_ucode_img_res(struct flcn_ucode_img_v1 *p_img);
60static int lsf_gen_wpr_requirements(struct gk20a *g,
61 struct ls_flcn_mgr_v1 *plsfm);
62static void lsfm_init_wpr_contents(struct gk20a *g,
63 struct ls_flcn_mgr_v1 *plsfm, struct mem_desc *nonwpr);
64static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr_v1 *plsfm);
65static int gp106_pmu_populate_loader_cfg(struct gk20a *g,
66 void *lsfm, u32 *p_bl_gen_desc_size);
67static int gp106_flcn_populate_bl_dmem_desc(struct gk20a *g,
68 void *lsfm, u32 *p_bl_gen_desc_size, u32 falconid);
69static int gp106_prepare_ucode_blob(struct gk20a *g);
70
71/*Globals*/
72static get_ucode_details pmu_acr_supp_ucode_list[] = {
73 pmu_ucode_details,
74 fecs_ucode_details,
75 gpccs_ucode_details,
76};
77
78void 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
85static 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
91int 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
116free_sgt:
117 gk20a_free_sgtable(&mem->sgt);
118 return err;
119}
120
121void 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
138int 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;
196release_sig:
197 release_firmware(pmu_sig);
198release_desc:
199 release_firmware(pmu_desc);
200release_img_fw:
201 release_firmware(pmu_fw);
202 return err;
203}
204
205int 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;
266free_lsf_desc:
267 kfree(lsf_desc);
268rel_sig:
269 release_firmware(fecs_sig);
270 return err;
271}
272int 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;
337free_lsf_desc:
338 kfree(lsf_desc);
339rel_sig:
340 release_firmware(gpccs_sig);
341 return err;
342}
343
344int 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
407static 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 */
414static 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
499static 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
571static 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.*/
628static 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 */
653static 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 */
748static 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 */
785static 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. */
856static 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*/
887static 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*/
896static 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
908static 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 */
928static 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*/
1010int 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;
1125err_free_ucode_map:
1126 gk20a_gmmu_unmap_free(vm, &acr->acr_ucode);
1127err_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
121void 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
53static inline u32 psec_falcon_irqsset_r(void)
54{
55 return 0x00087000;
56}
57static inline u32 psec_falcon_irqsset_swgen0_set_f(void)
58{
59 return 0x40;
60}
61static inline u32 psec_falcon_irqsclr_r(void)
62{
63 return 0x00087004;
64}
65static inline u32 psec_falcon_irqstat_r(void)
66{
67 return 0x00087008;
68}
69static inline u32 psec_falcon_irqstat_halt_true_f(void)
70{
71 return 0x10;
72}
73static inline u32 psec_falcon_irqstat_exterr_true_f(void)
74{
75 return 0x20;
76}
77static inline u32 psec_falcon_irqstat_swgen0_true_f(void)
78{
79 return 0x40;
80}
81static inline u32 psec_falcon_irqmode_r(void)
82{
83 return 0x0008700c;
84}
85static inline u32 psec_falcon_irqmset_r(void)
86{
87 return 0x00087010;
88}
89static inline u32 psec_falcon_irqmset_gptmr_f(u32 v)
90{
91 return (v & 0x1) << 0;
92}
93static inline u32 psec_falcon_irqmset_wdtmr_f(u32 v)
94{
95 return (v & 0x1) << 1;
96}
97static inline u32 psec_falcon_irqmset_mthd_f(u32 v)
98{
99 return (v & 0x1) << 2;
100}
101static inline u32 psec_falcon_irqmset_ctxsw_f(u32 v)
102{
103 return (v & 0x1) << 3;
104}
105static inline u32 psec_falcon_irqmset_halt_f(u32 v)
106{
107 return (v & 0x1) << 4;
108}
109static inline u32 psec_falcon_irqmset_exterr_f(u32 v)
110{
111 return (v & 0x1) << 5;
112}
113static inline u32 psec_falcon_irqmset_swgen0_f(u32 v)
114{
115 return (v & 0x1) << 6;
116}
117static inline u32 psec_falcon_irqmset_swgen1_f(u32 v)
118{
119 return (v & 0x1) << 7;
120}
121static inline u32 psec_falcon_irqmclr_r(void)
122{
123 return 0x00087014;
124}
125static inline u32 psec_falcon_irqmclr_gptmr_f(u32 v)
126{
127 return (v & 0x1) << 0;
128}
129static inline u32 psec_falcon_irqmclr_wdtmr_f(u32 v)
130{
131 return (v & 0x1) << 1;
132}
133static inline u32 psec_falcon_irqmclr_mthd_f(u32 v)
134{
135 return (v & 0x1) << 2;
136}
137static inline u32 psec_falcon_irqmclr_ctxsw_f(u32 v)
138{
139 return (v & 0x1) << 3;
140}
141static inline u32 psec_falcon_irqmclr_halt_f(u32 v)
142{
143 return (v & 0x1) << 4;
144}
145static inline u32 psec_falcon_irqmclr_exterr_f(u32 v)
146{
147 return (v & 0x1) << 5;
148}
149static inline u32 psec_falcon_irqmclr_swgen0_f(u32 v)
150{
151 return (v & 0x1) << 6;
152}
153static inline u32 psec_falcon_irqmclr_swgen1_f(u32 v)
154{
155 return (v & 0x1) << 7;
156}
157static inline u32 psec_falcon_irqmclr_ext_f(u32 v)
158{
159 return (v & 0xff) << 8;
160}
161static inline u32 psec_falcon_irqmask_r(void)
162{
163 return 0x00087018;
164}
165static inline u32 psec_falcon_irqdest_r(void)
166{
167 return 0x0008701c;
168}
169static inline u32 psec_falcon_irqdest_host_gptmr_f(u32 v)
170{
171 return (v & 0x1) << 0;
172}
173static inline u32 psec_falcon_irqdest_host_wdtmr_f(u32 v)
174{
175 return (v & 0x1) << 1;
176}
177static inline u32 psec_falcon_irqdest_host_mthd_f(u32 v)
178{
179 return (v & 0x1) << 2;
180}
181static inline u32 psec_falcon_irqdest_host_ctxsw_f(u32 v)
182{
183 return (v & 0x1) << 3;
184}
185static inline u32 psec_falcon_irqdest_host_halt_f(u32 v)
186{
187 return (v & 0x1) << 4;
188}
189static inline u32 psec_falcon_irqdest_host_exterr_f(u32 v)
190{
191 return (v & 0x1) << 5;
192}
193static inline u32 psec_falcon_irqdest_host_swgen0_f(u32 v)
194{
195 return (v & 0x1) << 6;
196}
197static inline u32 psec_falcon_irqdest_host_swgen1_f(u32 v)
198{
199 return (v & 0x1) << 7;
200}
201static inline u32 psec_falcon_irqdest_host_ext_f(u32 v)
202{
203 return (v & 0xff) << 8;
204}
205static inline u32 psec_falcon_irqdest_target_gptmr_f(u32 v)
206{
207 return (v & 0x1) << 16;
208}
209static inline u32 psec_falcon_irqdest_target_wdtmr_f(u32 v)
210{
211 return (v & 0x1) << 17;
212}
213static inline u32 psec_falcon_irqdest_target_mthd_f(u32 v)
214{
215 return (v & 0x1) << 18;
216}
217static inline u32 psec_falcon_irqdest_target_ctxsw_f(u32 v)
218{
219 return (v & 0x1) << 19;
220}
221static inline u32 psec_falcon_irqdest_target_halt_f(u32 v)
222{
223 return (v & 0x1) << 20;
224}
225static inline u32 psec_falcon_irqdest_target_exterr_f(u32 v)
226{
227 return (v & 0x1) << 21;
228}
229static inline u32 psec_falcon_irqdest_target_swgen0_f(u32 v)
230{
231 return (v & 0x1) << 22;
232}
233static inline u32 psec_falcon_irqdest_target_swgen1_f(u32 v)
234{
235 return (v & 0x1) << 23;
236}
237static inline u32 psec_falcon_irqdest_target_ext_f(u32 v)
238{
239 return (v & 0xff) << 24;
240}
241static inline u32 psec_falcon_curctx_r(void)
242{
243 return 0x00087050;
244}
245static inline u32 psec_falcon_nxtctx_r(void)
246{
247 return 0x00087054;
248}
249static inline u32 psec_falcon_mailbox0_r(void)
250{
251 return 0x00087040;
252}
253static inline u32 psec_falcon_mailbox1_r(void)
254{
255 return 0x00087044;
256}
257static inline u32 psec_falcon_itfen_r(void)
258{
259 return 0x00087048;
260}
261static inline u32 psec_falcon_itfen_ctxen_enable_f(void)
262{
263 return 0x1;
264}
265static inline u32 psec_falcon_idlestate_r(void)
266{
267 return 0x0008704c;
268}
269static inline u32 psec_falcon_idlestate_falcon_busy_v(u32 r)
270{
271 return (r >> 0) & 0x1;
272}
273static inline u32 psec_falcon_idlestate_ext_busy_v(u32 r)
274{
275 return (r >> 1) & 0x7fff;
276}
277static inline u32 psec_falcon_os_r(void)
278{
279 return 0x00087080;
280}
281static inline u32 psec_falcon_engctl_r(void)
282{
283 return 0x000870a4;
284}
285static inline u32 psec_falcon_cpuctl_r(void)
286{
287 return 0x00087100;
288}
289static inline u32 psec_falcon_cpuctl_startcpu_f(u32 v)
290{
291 return (v & 0x1) << 1;
292}
293static inline u32 psec_falcon_cpuctl_halt_intr_f(u32 v)
294{
295 return (v & 0x1) << 4;
296}
297static inline u32 psec_falcon_cpuctl_halt_intr_m(void)
298{
299 return 0x1 << 4;
300}
301static inline u32 psec_falcon_cpuctl_halt_intr_v(u32 r)
302{
303 return (r >> 4) & 0x1;
304}
305static inline u32 psec_falcon_cpuctl_cpuctl_alias_en_f(u32 v)
306{
307 return (v & 0x1) << 6;
308}
309static inline u32 psec_falcon_cpuctl_cpuctl_alias_en_m(void)
310{
311 return 0x1 << 6;
312}
313static inline u32 psec_falcon_cpuctl_cpuctl_alias_en_v(u32 r)
314{
315 return (r >> 6) & 0x1;
316}
317static inline u32 psec_falcon_cpuctl_alias_r(void)
318{
319 return 0x00087130;
320}
321static inline u32 psec_falcon_cpuctl_alias_startcpu_f(u32 v)
322{
323 return (v & 0x1) << 1;
324}
325static inline u32 psec_falcon_imemc_r(u32 i)
326{
327 return 0x00087180 + i*16;
328}
329static inline u32 psec_falcon_imemc_offs_f(u32 v)
330{
331 return (v & 0x3f) << 2;
332}
333static inline u32 psec_falcon_imemc_blk_f(u32 v)
334{
335 return (v & 0xff) << 8;
336}
337static inline u32 psec_falcon_imemc_aincw_f(u32 v)
338{
339 return (v & 0x1) << 24;
340}
341static inline u32 psec_falcon_imemd_r(u32 i)
342{
343 return 0x00087184 + i*16;
344}
345static inline u32 psec_falcon_imemt_r(u32 i)
346{
347 return 0x00087188 + i*16;
348}
349static inline u32 psec_falcon_sctl_r(void)
350{
351 return 0x00087240;
352}
353static inline u32 psec_falcon_mmu_phys_sec_r(void)
354{
355 return 0x00100ce4;
356}
357static inline u32 psec_falcon_bootvec_r(void)
358{
359 return 0x00087104;
360}
361static inline u32 psec_falcon_bootvec_vec_f(u32 v)
362{
363 return (v & 0xffffffff) << 0;
364}
365static inline u32 psec_falcon_dmactl_r(void)
366{
367 return 0x0008710c;
368}
369static inline u32 psec_falcon_dmactl_dmem_scrubbing_m(void)
370{
371 return 0x1 << 1;
372}
373static inline u32 psec_falcon_dmactl_imem_scrubbing_m(void)
374{
375 return 0x1 << 2;
376}
377static inline u32 psec_falcon_dmactl_require_ctx_f(u32 v)
378{
379 return (v & 0x1) << 0;
380}
381static inline u32 psec_falcon_hwcfg_r(void)
382{
383 return 0x00087108;
384}
385static inline u32 psec_falcon_hwcfg_imem_size_v(u32 r)
386{
387 return (r >> 0) & 0x1ff;
388}
389static inline u32 psec_falcon_hwcfg_dmem_size_v(u32 r)
390{
391 return (r >> 9) & 0x1ff;
392}
393static inline u32 psec_falcon_dmatrfbase_r(void)
394{
395 return 0x00087110;
396}
397static inline u32 psec_falcon_dmatrfbase1_r(void)
398{
399 return 0x00087128;
400}
401static inline u32 psec_falcon_dmatrfmoffs_r(void)
402{
403 return 0x00087114;
404}
405static inline u32 psec_falcon_dmatrfcmd_r(void)
406{
407 return 0x00087118;
408}
409static inline u32 psec_falcon_dmatrfcmd_imem_f(u32 v)
410{
411 return (v & 0x1) << 4;
412}
413static inline u32 psec_falcon_dmatrfcmd_write_f(u32 v)
414{
415 return (v & 0x1) << 5;
416}
417static inline u32 psec_falcon_dmatrfcmd_size_f(u32 v)
418{
419 return (v & 0x7) << 8;
420}
421static inline u32 psec_falcon_dmatrfcmd_ctxdma_f(u32 v)
422{
423 return (v & 0x7) << 12;
424}
425static inline u32 psec_falcon_dmatrffboffs_r(void)
426{
427 return 0x0008711c;
428}
429static inline u32 psec_falcon_exterraddr_r(void)
430{
431 return 0x00087168;
432}
433static inline u32 psec_falcon_exterrstat_r(void)
434{
435 return 0x0008716c;
436}
437static inline u32 psec_falcon_exterrstat_valid_m(void)
438{
439 return 0x1 << 31;
440}
441static inline u32 psec_falcon_exterrstat_valid_v(u32 r)
442{
443 return (r >> 31) & 0x1;
444}
445static inline u32 psec_falcon_exterrstat_valid_true_v(void)
446{
447 return 0x00000001;
448}
449static inline u32 psec_sec2_falcon_icd_cmd_r(void)
450{
451 return 0x00087200;
452}
453static inline u32 psec_sec2_falcon_icd_cmd_opc_s(void)
454{
455 return 4;
456}
457static inline u32 psec_sec2_falcon_icd_cmd_opc_f(u32 v)
458{
459 return (v & 0xf) << 0;
460}
461static inline u32 psec_sec2_falcon_icd_cmd_opc_m(void)
462{
463 return 0xf << 0;
464}
465static inline u32 psec_sec2_falcon_icd_cmd_opc_v(u32 r)
466{
467 return (r >> 0) & 0xf;
468}
469static inline u32 psec_sec2_falcon_icd_cmd_opc_rreg_f(void)
470{
471 return 0x8;
472}
473static inline u32 psec_sec2_falcon_icd_cmd_opc_rstat_f(void)
474{
475 return 0xe;
476}
477static inline u32 psec_sec2_falcon_icd_cmd_idx_f(u32 v)
478{
479 return (v & 0x1f) << 8;
480}
481static inline u32 psec_sec2_falcon_icd_rdata_r(void)
482{
483 return 0x0008720c;
484}
485static inline u32 psec_falcon_dmemc_r(u32 i)
486{
487 return 0x000871c0 + i*8;
488}
489static inline u32 psec_falcon_dmemc_offs_f(u32 v)
490{
491 return (v & 0x3f) << 2;
492}
493static inline u32 psec_falcon_dmemc_offs_m(void)
494{
495 return 0x3f << 2;
496}
497static inline u32 psec_falcon_dmemc_blk_f(u32 v)
498{
499 return (v & 0xff) << 8;
500}
501static inline u32 psec_falcon_dmemc_blk_m(void)
502{
503 return 0xff << 8;
504}
505static inline u32 psec_falcon_dmemc_aincw_f(u32 v)
506{
507 return (v & 0x1) << 24;
508}
509static inline u32 psec_falcon_dmemc_aincr_f(u32 v)
510{
511 return (v & 0x1) << 25;
512}
513static inline u32 psec_falcon_dmemd_r(u32 i)
514{
515 return 0x000871c4 + i*8;
516}
517static inline u32 psec_falcon_debug1_r(void)
518{
519 return 0x00087090;
520}
521static inline u32 psec_falcon_debug1_ctxsw_mode_s(void)
522{
523 return 1;
524}
525static inline u32 psec_falcon_debug1_ctxsw_mode_f(u32 v)
526{
527 return (v & 0x1) << 16;
528}
529static inline u32 psec_falcon_debug1_ctxsw_mode_m(void)
530{
531 return 0x1 << 16;
532}
533static inline u32 psec_falcon_debug1_ctxsw_mode_v(u32 r)
534{
535 return (r >> 16) & 0x1;
536}
537static inline u32 psec_falcon_debug1_ctxsw_mode_init_f(void)
538{
539 return 0x0;
540}
541static inline u32 psec_fbif_transcfg_r(u32 i)
542{
543 return 0x00087600 + i*4;
544}
545static inline u32 psec_fbif_transcfg_target_local_fb_f(void)
546{
547 return 0x0;
548}
549static inline u32 psec_fbif_transcfg_target_coherent_sysmem_f(void)
550{
551 return 0x1;
552}
553static inline u32 psec_fbif_transcfg_target_noncoherent_sysmem_f(void)
554{
555 return 0x2;
556}
557static inline u32 psec_fbif_transcfg_mem_type_s(void)
558{
559 return 1;
560}
561static inline u32 psec_fbif_transcfg_mem_type_f(u32 v)
562{
563 return (v & 0x1) << 2;
564}
565static inline u32 psec_fbif_transcfg_mem_type_m(void)
566{
567 return 0x1 << 2;
568}
569static inline u32 psec_fbif_transcfg_mem_type_v(u32 r)
570{
571 return (r >> 2) & 0x1;
572}
573static inline u32 psec_fbif_transcfg_mem_type_virtual_f(void)
574{
575 return 0x0;
576}
577static inline u32 psec_fbif_transcfg_mem_type_physical_f(void)
578{
579 return 0x4;
580}
581static inline u32 psec_falcon_engine_r(void)
582{
583 return 0x000873c0;
584}
585static inline u32 psec_falcon_engine_reset_true_f(void)
586{
587 return 0x1;
588}
589static inline u32 psec_falcon_engine_reset_false_f(void)
590{
591 return 0x0;
592}
593static inline u32 psec_fbif_ctl_r(void)
594{
595 return 0x00087624;
596}
597static inline u32 psec_fbif_ctl_allow_phys_no_ctx_init_f(void)
598{
599 return 0x0;
600}
601static inline u32 psec_fbif_ctl_allow_phys_no_ctx_disallow_f(void)
602{
603 return 0x0;
604}
605static 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
34int 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
56int 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
93void 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
147int 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
229void 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
284void 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
334int 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
17int sec2_clear_halt_interrupt_status(struct gk20a *g, unsigned int timeout);
18int sec2_wait_for_halt(struct gk20a *g, unsigned int timeout);
19void sec2_copy_to_dmem(struct pmu_gk20a *pmu,
20 u32 dst, u8 *src, u32 size, u8 port);
21void sec2_dump_falcon_stats(struct pmu_gk20a *pmu);
22int bl_bootstrap_sec2(struct pmu_gk20a *pmu,
23 void *desc, u32 bl_sz);
24void sec_enable_irq(struct pmu_gk20a *pmu, bool enable);
25void init_pmu_setup_hw1(struct gk20a *g);
26int init_sec2_setup_hw1(struct gk20a *g,
27 void *desc, u32 bl_sz);
28
29#endif /*__SEC2_H_*/