summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h3
-rw-r--r--drivers/gpu/nvgpu/gk20a/gr_ctx_gk20a.c3
-rw-r--r--drivers/gpu/nvgpu/gk20a/gr_gk20a.c4
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.c1
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.h23
-rw-r--r--drivers/gpu/nvgpu/gm20b/acr_gm20b.c55
-rw-r--r--drivers/gpu/nvgpu/gm20b/acr_gm20b.h2
-rw-r--r--drivers/gpu/nvgpu/gm20b/gr_ctx_gm20b.c3
-rw-r--r--drivers/gpu/nvgpu/gm20b/gr_gm20b.c96
-rw-r--r--drivers/gpu/nvgpu/gm20b/pmu_gm20b.c63
-rw-r--r--drivers/gpu/nvgpu/gm20b/pmu_gm20b.h2
11 files changed, 175 insertions, 80 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index d8e3586f..9a183e44 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -333,6 +333,7 @@ struct gpu_ops {
333 struct { 333 struct {
334 int (*get_netlist_name)(int index, char *name); 334 int (*get_netlist_name)(int index, char *name);
335 bool (*is_fw_defined)(void); 335 bool (*is_fw_defined)(void);
336 bool use_dma_for_fw_bootstrap;
336 } gr_ctx; 337 } gr_ctx;
337 struct { 338 struct {
338 bool (*support_sparse)(struct gk20a *g); 339 bool (*support_sparse)(struct gk20a *g);
@@ -383,7 +384,9 @@ struct gpu_ops {
383 int (*pmu_setup_hw_and_bootstrap)(struct gk20a *g); 384 int (*pmu_setup_hw_and_bootstrap)(struct gk20a *g);
384 int (*pmu_setup_elpg)(struct gk20a *g); 385 int (*pmu_setup_elpg)(struct gk20a *g);
385 int (*init_wpr_region)(struct gk20a *g); 386 int (*init_wpr_region)(struct gk20a *g);
387 int (*load_lsfalcon_ucode)(struct gk20a *g, u32 falconidmask);
386 u32 lspmuwprinitdone; 388 u32 lspmuwprinitdone;
389 u32 lsfloadedfalconid;
387 bool fecsbootstrapdone; 390 bool fecsbootstrapdone;
388 } pmu; 391 } pmu;
389 struct { 392 struct {
diff --git a/drivers/gpu/nvgpu/gk20a/gr_ctx_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_ctx_gk20a.c
index cd9a9fca..94dba7b6 100644
--- a/drivers/gpu/nvgpu/gk20a/gr_ctx_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gr_ctx_gk20a.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * GK20A Graphics Context 4 * GK20A Graphics Context
5 * 5 *
6 * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. 6 * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved.
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License, 9 * under the terms and conditions of the GNU General Public License,
@@ -345,4 +345,5 @@ void gk20a_init_gr_ctx(struct gpu_ops *gops)
345{ 345{
346 gops->gr_ctx.get_netlist_name = gr_gk20a_get_netlist_name; 346 gops->gr_ctx.get_netlist_name = gr_gk20a_get_netlist_name;
347 gops->gr_ctx.is_fw_defined = gr_gk20a_is_firmware_defined; 347 gops->gr_ctx.is_fw_defined = gr_gk20a_is_firmware_defined;
348 gops->gr_ctx.use_dma_for_fw_bootstrap = true;
348} 349}
diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c
index edd4c6c8..e232bf17 100644
--- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c
@@ -2128,7 +2128,7 @@ int gr_gk20a_load_ctxsw_ucode(struct gk20a *g)
2128 * In case bootloader is not supported, revert to the old way of 2128 * In case bootloader is not supported, revert to the old way of
2129 * loading gr ucode, without the faster bootstrap routine. 2129 * loading gr ucode, without the faster bootstrap routine.
2130 */ 2130 */
2131 if (g->gpu_characteristics.arch > NVGPU_GPU_ARCH_GM200) { 2131 if (!g->ops.gr_ctx.use_dma_for_fw_bootstrap) {
2132 gr_gk20a_load_falcon_dmem(g); 2132 gr_gk20a_load_falcon_dmem(g);
2133 gr_gk20a_load_falcon_imem(g); 2133 gr_gk20a_load_falcon_imem(g);
2134 gr_gk20a_start_falcon_ucode(g); 2134 gr_gk20a_start_falcon_ucode(g);
@@ -2161,7 +2161,7 @@ static int gr_gk20a_wait_ctxsw_ready(struct gk20a *g)
2161 return ret; 2161 return ret;
2162 } 2162 }
2163 2163
2164 if (!(g->gpu_characteristics.arch > NVGPU_GPU_ARCH_GM200)) 2164 if (g->ops.gr_ctx.use_dma_for_fw_bootstrap || g->ops.securegpccs)
2165 gk20a_writel(g, gr_fecs_current_ctx_r(), 2165 gk20a_writel(g, gr_fecs_current_ctx_r(),
2166 gr_fecs_current_ctx_valid_false_f()); 2166 gr_fecs_current_ctx_valid_false_f());
2167 2167
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
index 11322293..1f21555c 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
@@ -2647,6 +2647,7 @@ void gk20a_init_pmu_ops(struct gpu_ops *gops)
2647 gops->pmu.pmu_setup_hw_and_bootstrap = gk20a_init_pmu_setup_hw1; 2647 gops->pmu.pmu_setup_hw_and_bootstrap = gk20a_init_pmu_setup_hw1;
2648 gops->pmu.pmu_setup_elpg = NULL; 2648 gops->pmu.pmu_setup_elpg = NULL;
2649 gops->pmu.init_wpr_region = NULL; 2649 gops->pmu.init_wpr_region = NULL;
2650 gops->pmu.load_lsfalcon_ucode = NULL;
2650} 2651}
2651 2652
2652int gk20a_init_pmu_support(struct gk20a *g) 2653int gk20a_init_pmu_support(struct gk20a *g)
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
index f29c810e..85403767 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
@@ -304,6 +304,11 @@ enum {
304 GK20A_PMU_DMAIDX_END = 7 304 GK20A_PMU_DMAIDX_END = 7
305}; 305};
306 306
307struct falc_u64 {
308 u32 lo;
309 u32 hi;
310};
311
307struct falc_dma_addr { 312struct falc_dma_addr {
308 u32 dma_base; 313 u32 dma_base;
309 /*dma_base1 is 9-bit MSB for FB Base 314 /*dma_base1 is 9-bit MSB for FB Base
@@ -708,6 +713,8 @@ struct pmu_pg_cmd {
708enum { 713enum {
709 PMU_ACR_CMD_ID_INIT_WPR_REGION = 0x0 , 714 PMU_ACR_CMD_ID_INIT_WPR_REGION = 0x0 ,
710 PMU_ACR_CMD_ID_BOOTSTRAP_FALCON, 715 PMU_ACR_CMD_ID_BOOTSTRAP_FALCON,
716 PMU_ACR_CMD_ID_RESERVED,
717 PMU_ACR_CMD_ID_BOOTSTRAP_MULTIPLE_FALCONS,
711}; 718};
712 719
713/* 720/*
@@ -729,14 +736,27 @@ struct pmu_acr_cmd_bootstrap_falcon {
729 u32 falconid; 736 u32 falconid;
730}; 737};
731 738
739/*
740 * falcon ID to bootstrap
741 */
742struct pmu_acr_cmd_bootstrap_multiple_falcons {
743 u8 cmd_type;
744 u32 flags;
745 u32 falconidmask;
746 u32 usevamask;
747 struct falc_u64 wprvirtualbase;
748};
749
732#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO 1 750#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO 1
733#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0 751#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0
734 752
753
735struct pmu_acr_cmd { 754struct pmu_acr_cmd {
736 union { 755 union {
737 u8 cmd_type; 756 u8 cmd_type;
738 struct pmu_acr_cmd_bootstrap_falcon bootstrap_falcon; 757 struct pmu_acr_cmd_bootstrap_falcon bootstrap_falcon;
739 struct pmu_acr_cmd_init_wpr_details init_wpr; 758 struct pmu_acr_cmd_init_wpr_details init_wpr;
759 struct pmu_acr_cmd_bootstrap_multiple_falcons boot_falcons;
740 }; 760 };
741}; 761};
742 762
@@ -1177,6 +1197,7 @@ struct pmu_gk20a {
1177 /* TBD: remove this if ZBC seq is fixed */ 1197 /* TBD: remove this if ZBC seq is fixed */
1178 struct mem_desc seq_buf; 1198 struct mem_desc seq_buf;
1179 struct mem_desc trace_buf; 1199 struct mem_desc trace_buf;
1200 struct mem_desc wpr_buf;
1180 bool buf_loaded; 1201 bool buf_loaded;
1181 1202
1182 struct pmu_sha1_gid gid_info; 1203 struct pmu_sha1_gid gid_info;
@@ -1294,4 +1315,6 @@ int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id);
1294void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable); 1315void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable);
1295int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, 1316int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout,
1296 u32 *var, u32 val); 1317 u32 *var, u32 val);
1318void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg,
1319 void *param, u32 handle, u32 status);
1297#endif /*__PMU_GK20A_H__*/ 1320#endif /*__PMU_GK20A_H__*/
diff --git a/drivers/gpu/nvgpu/gm20b/acr_gm20b.c b/drivers/gpu/nvgpu/gm20b/acr_gm20b.c
index ba47d235..a238c523 100644
--- a/drivers/gpu/nvgpu/gm20b/acr_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/acr_gm20b.c
@@ -284,9 +284,17 @@ rel_sig:
284 284
285int prepare_ucode_blob(struct gk20a *g) 285int prepare_ucode_blob(struct gk20a *g)
286{ 286{
287
287 int err; 288 int err;
288 struct ls_flcn_mgr lsfm_l, *plsfm; 289 struct ls_flcn_mgr lsfm_l, *plsfm;
289 struct pmu_gk20a *pmu = &g->pmu; 290 struct pmu_gk20a *pmu = &g->pmu;
291 phys_addr_t wpr_addr;
292 u32 wprsize;
293 struct mm_gk20a *mm = &g->mm;
294 struct vm_gk20a *vm = &mm->pmu.vm;
295 struct mc_carveout_info inf;
296 struct sg_table *sgt;
297 struct page *page;
290 298
291 if (g->acr.ucode_blob.cpu_va) { 299 if (g->acr.ucode_blob.cpu_va) {
292 /*Recovery case, we do not need to form 300 /*Recovery case, we do not need to form
@@ -304,22 +312,46 @@ int prepare_ucode_blob(struct gk20a *g)
304 gm20b_mm_mmu_vpr_info_fetch(g); 312 gm20b_mm_mmu_vpr_info_fetch(g);
305 gr_gk20a_init_ctxsw_ucode(g); 313 gr_gk20a_init_ctxsw_ucode(g);
306 314
315 mc_get_carveout_info(&inf, NULL, MC_SECURITY_CARVEOUT2);
316 gm20b_dbg_pmu("wpr carveout base:%llx\n", inf.base);
317 wpr_addr = (phys_addr_t)inf.base;
318 gm20b_dbg_pmu("wpr carveout size :%llx\n", inf.size);
319 wprsize = (u32)inf.size;
320 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
321 if (!sgt) {
322 gk20a_err(dev_from_gk20a(g), "failed to allocate memory\n");
323 return -ENOMEM;
324 }
325 err = sg_alloc_table(sgt, 1, GFP_KERNEL);
326 if (err) {
327 gk20a_err(dev_from_gk20a(g), "failed to allocate sg_table\n");
328 goto free_sgt;
329 }
330 page = phys_to_page(wpr_addr);
331 sg_set_page(sgt->sgl, page, wprsize, 0);
332 /* This bypasses SMMU for WPR during gmmu_map. */
333 sg_dma_address(sgt->sgl) = 0;
334
335 g->pmu.wpr_buf.gpu_va = gk20a_gmmu_map(vm, &sgt, wprsize,
336 0, gk20a_mem_flag_none);
337 gm20b_dbg_pmu("wpr mapped gpu va :%llx\n", g->pmu.wpr_buf.gpu_va);
338
307 /* Discover all managed falcons*/ 339 /* Discover all managed falcons*/
308 err = lsfm_discover_ucode_images(g, plsfm); 340 err = lsfm_discover_ucode_images(g, plsfm);
309 gm20b_dbg_pmu(" Managed Falcon cnt %d\n", plsfm->managed_flcn_cnt); 341 gm20b_dbg_pmu(" Managed Falcon cnt %d\n", plsfm->managed_flcn_cnt);
310 if (err) 342 if (err)
311 return err; 343 goto free_sgt;
312 344
313 if (plsfm->managed_flcn_cnt && !g->acr.ucode_blob.cpu_va) { 345 if (plsfm->managed_flcn_cnt && !g->acr.ucode_blob.cpu_va) {
314 /* Generate WPR requirements*/ 346 /* Generate WPR requirements*/
315 err = lsf_gen_wpr_requirements(g, plsfm); 347 err = lsf_gen_wpr_requirements(g, plsfm);
316 if (err) 348 if (err)
317 return err; 349 goto free_sgt;
318 350
319 /*Alloc memory to hold ucode blob contents*/ 351 /*Alloc memory to hold ucode blob contents*/
320 err = gk20a_gmmu_alloc(g, plsfm->wpr_size, &g->acr.ucode_blob); 352 err = gk20a_gmmu_alloc(g, plsfm->wpr_size, &g->acr.ucode_blob);
321 if (err) 353 if (err)
322 return err; 354 goto free_sgt;
323 355
324 gm20b_dbg_pmu("managed LS falcon %d, WPR size %d bytes.\n", 356 gm20b_dbg_pmu("managed LS falcon %d, WPR size %d bytes.\n",
325 plsfm->managed_flcn_cnt, plsfm->wpr_size); 357 plsfm->managed_flcn_cnt, plsfm->wpr_size);
@@ -329,7 +361,9 @@ int prepare_ucode_blob(struct gk20a *g)
329 } 361 }
330 gm20b_dbg_pmu("prepare ucode blob return 0\n"); 362 gm20b_dbg_pmu("prepare ucode blob return 0\n");
331 free_acr_resources(g, plsfm); 363 free_acr_resources(g, plsfm);
332 return 0; 364 free_sgt:
365 kfree(sgt);
366 return err;
333} 367}
334 368
335static u8 lsfm_falcon_disabled(struct gk20a *g, struct ls_flcn_mgr *plsfm, 369static u8 lsfm_falcon_disabled(struct gk20a *g, struct ls_flcn_mgr *plsfm,
@@ -495,7 +529,8 @@ static int pmu_populate_loader_cfg(struct gk20a *g,
495 529
496static int flcn_populate_bl_dmem_desc(struct gk20a *g, 530static int flcn_populate_bl_dmem_desc(struct gk20a *g,
497 struct lsfm_managed_ucode_img *lsfm, 531 struct lsfm_managed_ucode_img *lsfm,
498 union flcn_bl_generic_desc *p_bl_gen_desc, u32 *p_bl_gen_desc_size) 532 union flcn_bl_generic_desc *p_bl_gen_desc, u32 *p_bl_gen_desc_size,
533 u32 falconid)
499{ 534{
500 struct mc_carveout_info inf; 535 struct mc_carveout_info inf;
501 struct flcn_ucode_img *p_img = &(lsfm->ucode_img); 536 struct flcn_ucode_img *p_img = &(lsfm->ucode_img);
@@ -520,7 +555,10 @@ static int flcn_populate_bl_dmem_desc(struct gk20a *g,
520 */ 555 */
521 addr_base = lsfm->lsb_header.ucode_off; 556 addr_base = lsfm->lsb_header.ucode_off;
522 mc_get_carveout_info(&inf, NULL, MC_SECURITY_CARVEOUT2); 557 mc_get_carveout_info(&inf, NULL, MC_SECURITY_CARVEOUT2);
523 addr_base += inf.base; 558 if (falconid == LSF_FALCON_ID_GPCCS)
559 addr_base += g->pmu.wpr_buf.gpu_va;
560 else
561 addr_base += inf.base;
524 gm20b_dbg_pmu("gen loader cfg %x u32 addrbase %x ID\n", (u32)addr_base, 562 gm20b_dbg_pmu("gen loader cfg %x u32 addrbase %x ID\n", (u32)addr_base,
525 lsfm->wpr_header.falcon_id); 563 lsfm->wpr_header.falcon_id);
526 addr_code = u64_lo32((addr_base + 564 addr_code = u64_lo32((addr_base +
@@ -555,7 +593,8 @@ static int lsfm_fill_flcn_bl_gen_desc(struct gk20a *g,
555 if (pnode->wpr_header.falcon_id != pmu->falcon_id) { 593 if (pnode->wpr_header.falcon_id != pmu->falcon_id) {
556 gm20b_dbg_pmu("non pmu. write flcn bl gen desc\n"); 594 gm20b_dbg_pmu("non pmu. write flcn bl gen desc\n");
557 flcn_populate_bl_dmem_desc(g, pnode, &pnode->bl_gen_desc, 595 flcn_populate_bl_dmem_desc(g, pnode, &pnode->bl_gen_desc,
558 &pnode->bl_gen_desc_size); 596 &pnode->bl_gen_desc_size,
597 pnode->wpr_header.falcon_id);
559 return 0; 598 return 0;
560 } 599 }
561 600
@@ -797,7 +836,7 @@ static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g,
797 } 836 }
798 if (falcon_id == LSF_FALCON_ID_GPCCS) { 837 if (falcon_id == LSF_FALCON_ID_GPCCS) {
799 pnode->lsb_header.flags |= 838 pnode->lsb_header.flags |=
800 NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE; 839 NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_FALSE;
801 } 840 }
802 } 841 }
803} 842}
diff --git a/drivers/gpu/nvgpu/gm20b/acr_gm20b.h b/drivers/gpu/nvgpu/gm20b/acr_gm20b.h
index 3a5fa7d0..bd3b633a 100644
--- a/drivers/gpu/nvgpu/gm20b/acr_gm20b.h
+++ b/drivers/gpu/nvgpu/gm20b/acr_gm20b.h
@@ -50,8 +50,10 @@
50 * Defines a common Light Secure Falcon identifier. 50 * Defines a common Light Secure Falcon identifier.
51 */ 51 */
52#define LSF_FALCON_ID_PMU (0) 52#define LSF_FALCON_ID_PMU (0)
53#define LSF_FALCON_ID_RESERVED (1)
53#define LSF_FALCON_ID_FECS (2) 54#define LSF_FALCON_ID_FECS (2)
54#define LSF_FALCON_ID_GPCCS (3) 55#define LSF_FALCON_ID_GPCCS (3)
56#define LSF_FALCON_ID_END (4)
55#define LSF_FALCON_ID_INVALID (0xFFFFFFFF) 57#define LSF_FALCON_ID_INVALID (0xFFFFFFFF)
56 58
57/*! 59/*!
diff --git a/drivers/gpu/nvgpu/gm20b/gr_ctx_gm20b.c b/drivers/gpu/nvgpu/gm20b/gr_ctx_gm20b.c
index 2a654760..01cc1f16 100644
--- a/drivers/gpu/nvgpu/gm20b/gr_ctx_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/gr_ctx_gm20b.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * GM20B Graphics Context 4 * GM20B Graphics Context
5 * 5 *
6 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 6 * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License, 9 * under the terms and conditions of the GNU General Public License,
@@ -69,4 +69,5 @@ static bool gr_gm20b_is_firmware_defined(void)
69void gm20b_init_gr_ctx(struct gpu_ops *gops) { 69void gm20b_init_gr_ctx(struct gpu_ops *gops) {
70 gops->gr_ctx.get_netlist_name = gr_gm20b_get_netlist_name; 70 gops->gr_ctx.get_netlist_name = gr_gm20b_get_netlist_name;
71 gops->gr_ctx.is_fw_defined = gr_gm20b_is_firmware_defined; 71 gops->gr_ctx.is_fw_defined = gr_gm20b_is_firmware_defined;
72 gops->gr_ctx.use_dma_for_fw_bootstrap = true;
72} 73}
diff --git a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c
index e1204dad..6c7831d5 100644
--- a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c
@@ -688,29 +688,9 @@ static void gr_gm20b_load_gpccs_with_bootloader(struct gk20a *g)
688 gr_fecs_falcon_hwcfg_r()); 688 gr_fecs_falcon_hwcfg_r());
689} 689}
690 690
691static int gr_gm20b_ctx_wait_lsf_ready(struct gk20a *g, u32 timeout, u32 val)
692{
693 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
694 unsigned long delay = GR_FECS_POLL_INTERVAL;
695 u32 reg;
696
697 gk20a_dbg_fn("");
698 reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0));
699 do {
700 reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0));
701 if (reg == val)
702 return 0;
703 udelay(delay);
704 } while (time_before(jiffies, end_jiffies) ||
705 !tegra_platform_is_silicon());
706
707 return -ETIMEDOUT;
708}
709
710static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g) 691static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g)
711{ 692{
712 u32 err; 693 u32 err, flags;
713 unsigned long timeout = gk20a_get_gr_idle_timeout(g);
714 u32 reg_offset = gr_gpcs_gpccs_falcon_hwcfg_r() - 694 u32 reg_offset = gr_gpcs_gpccs_falcon_hwcfg_r() -
715 gr_fecs_falcon_hwcfg_r(); 695 gr_fecs_falcon_hwcfg_r();
716 696
@@ -723,63 +703,57 @@ static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g)
723 gr_gpccs_ctxsw_mailbox_value_f(0xc0de7777)); 703 gr_gpccs_ctxsw_mailbox_value_f(0xc0de7777));
724 } 704 }
725 705
706 flags = PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
707 g->ops.pmu.lsfloadedfalconid = 0;
726 if (g->ops.pmu.fecsbootstrapdone) { 708 if (g->ops.pmu.fecsbootstrapdone) {
727 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); 709 /* this must be recovery so bootstrap fecs and gpccs */
728 gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS); 710 if (!g->ops.securegpccs) {
729 err = gr_gm20b_ctx_wait_lsf_ready(g, timeout, 0x55AA55AA); 711 gr_gm20b_load_gpccs_with_bootloader(g);
712 err = g->ops.pmu.load_lsfalcon_ucode(g,
713 (1 << LSF_FALCON_ID_FECS));
714 } else {
715 /* bind WPR VA inst block */
716 gr_gk20a_load_falcon_bind_instblk(g);
717 err = g->ops.pmu.load_lsfalcon_ucode(g,
718 (1 << LSF_FALCON_ID_FECS) |
719 (1 << LSF_FALCON_ID_GPCCS));
720 }
730 if (err) { 721 if (err) {
731 gk20a_err(dev_from_gk20a(g), "Unable to recover FECS"); 722 gk20a_err(dev_from_gk20a(g),
723 "Unable to recover GR falcon");
732 return err; 724 return err;
733 } else {
734 if (!g->ops.securegpccs) {
735 gr_gm20b_load_gpccs_with_bootloader(g);
736 gk20a_writel(g, gr_gpccs_dmactl_r(),
737 gr_gpccs_dmactl_require_ctx_f(0));
738 gk20a_writel(g, gr_gpccs_cpuctl_r(),
739 gr_gpccs_cpuctl_startcpu_f(1));
740 } else {
741 gk20a_writel(g,
742 gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
743 gm20b_pmu_load_lsf(g, LSF_FALCON_ID_GPCCS);
744 err = gr_gm20b_ctx_wait_lsf_ready(g, timeout,
745 0x55AA55AA);
746 gk20a_writel(g, reg_offset +
747 gr_fecs_cpuctl_alias_r(),
748 gr_gpccs_cpuctl_startcpu_f(1));
749 }
750 } 725 }
726
751 } else { 727 } else {
728 /* cold boot or rg exit */
752 g->ops.pmu.fecsbootstrapdone = true; 729 g->ops.pmu.fecsbootstrapdone = true;
753 if (!g->ops.securegpccs) { 730 if (!g->ops.securegpccs) {
754 gr_gm20b_load_gpccs_with_bootloader(g); 731 gr_gm20b_load_gpccs_with_bootloader(g);
755 gk20a_writel(g, gr_gpccs_dmactl_r(),
756 gr_gpccs_dmactl_require_ctx_f(0));
757 gk20a_writel(g, gr_gpccs_cpuctl_r(),
758 gr_gpccs_cpuctl_startcpu_f(1));
759 } else { 732 } else {
760 pmu_wait_message_cond(&g->pmu, 733 /* bind WPR VA inst block */
761 gk20a_get_gr_idle_timeout(g), 734 gr_gk20a_load_falcon_bind_instblk(g);
762 &g->ops.pmu.lspmuwprinitdone, 1); 735 err = g->ops.pmu.load_lsfalcon_ucode(g,
763 if (!g->ops.pmu.lspmuwprinitdone) { 736 (1 << LSF_FALCON_ID_GPCCS));
764 gk20a_err(dev_from_gk20a(g),
765 "PMU WPR needed but not ready yet");
766 return -ETIMEDOUT;
767 }
768 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
769 gm20b_pmu_load_lsf(g, LSF_FALCON_ID_GPCCS);
770 err = gr_gm20b_ctx_wait_lsf_ready(g, timeout,
771 0x55AA55AA);
772 if (err) { 737 if (err) {
773 gk20a_err(dev_from_gk20a(g), 738 gk20a_err(dev_from_gk20a(g),
774 "Unable to boot GPCCS\n"); 739 "Unable to boot GPCCS\n");
775 return err; 740 return err;
776 } 741 }
777 gk20a_writel(g, reg_offset +
778 gr_fecs_cpuctl_alias_r(),
779 gr_gpccs_cpuctl_startcpu_f(1));
780 } 742 }
781 } 743 }
782 744
745 /*start gpccs */
746 if (g->ops.securegpccs) {
747 gk20a_writel(g, reg_offset +
748 gr_fecs_cpuctl_alias_r(),
749 gr_gpccs_cpuctl_startcpu_f(1));
750 } else {
751 gk20a_writel(g, gr_gpccs_dmactl_r(),
752 gr_gpccs_dmactl_require_ctx_f(0));
753 gk20a_writel(g, gr_gpccs_cpuctl_r(),
754 gr_gpccs_cpuctl_startcpu_f(1));
755 }
756 /* start fecs */
783 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); 757 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
784 gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1); 758 gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1);
785 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff); 759 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff);
diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c
index 28b40b1c..ac19e99c 100644
--- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c
@@ -18,6 +18,7 @@
18#include "gk20a/pmu_gk20a.h" 18#include "gk20a/pmu_gk20a.h"
19#include "acr_gm20b.h" 19#include "acr_gm20b.h"
20#include "pmu_gm20b.h" 20#include "pmu_gm20b.h"
21#include "hw_gr_gm20b.h"
21 22
22/*! 23/*!
23 * Structure/object which single register write need to be done during PG init 24 * Structure/object which single register write need to be done during PG init
@@ -190,21 +191,40 @@ int gm20b_pmu_init_acr(struct gk20a *g)
190 return 0; 191 return 0;
191} 192}
192 193
193static void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg, 194void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg,
194 void *param, u32 handle, u32 status) 195 void *param, u32 handle, u32 status)
195{ 196{
196 197
197 gk20a_dbg_fn(""); 198 gk20a_dbg_fn("");
198 199
199 200
200 if (msg->msg.acr.acrmsg.falconid == LSF_FALCON_ID_FECS) 201 gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_BOOTSTRAP_FALCON");
201 gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_BOOTSTRAP_FALCON");
202 202
203 gm20b_dbg_pmu("response code = %x\n", msg->msg.acr.acrmsg.falconid); 203 gm20b_dbg_pmu("response code = %x\n", msg->msg.acr.acrmsg.falconid);
204 g->ops.pmu.lsfloadedfalconid = msg->msg.acr.acrmsg.falconid;
204 gk20a_dbg_fn("done"); 205 gk20a_dbg_fn("done");
205} 206}
206 207
207void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id) 208static int pmu_gm20b_ctx_wait_lsf_ready(struct gk20a *g, u32 timeout, u32 val)
209{
210 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
211 unsigned long delay = GR_FECS_POLL_INTERVAL;
212 u32 reg;
213
214 gk20a_dbg_fn("");
215 reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0));
216 do {
217 reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0));
218 if (reg == val)
219 return 0;
220 udelay(delay);
221 } while (time_before(jiffies, end_jiffies) ||
222 !tegra_platform_is_silicon());
223
224 return -ETIMEDOUT;
225}
226
227void gm20b_pmu_load_lsf(struct gk20a *g, u32 falcon_id, u32 flags)
208{ 228{
209 struct pmu_gk20a *pmu = &g->pmu; 229 struct pmu_gk20a *pmu = &g->pmu;
210 struct pmu_cmd cmd; 230 struct pmu_cmd cmd;
@@ -221,8 +241,7 @@ void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id)
221 sizeof(struct pmu_acr_cmd_bootstrap_falcon); 241 sizeof(struct pmu_acr_cmd_bootstrap_falcon);
222 cmd.cmd.acr.bootstrap_falcon.cmd_type = 242 cmd.cmd.acr.bootstrap_falcon.cmd_type =
223 PMU_ACR_CMD_ID_BOOTSTRAP_FALCON; 243 PMU_ACR_CMD_ID_BOOTSTRAP_FALCON;
224 cmd.cmd.acr.bootstrap_falcon.flags = 244 cmd.cmd.acr.bootstrap_falcon.flags = flags;
225 PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
226 cmd.cmd.acr.bootstrap_falcon.falconid = falcon_id; 245 cmd.cmd.acr.bootstrap_falcon.falconid = falcon_id;
227 gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON: %x\n", 246 gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON: %x\n",
228 falcon_id); 247 falcon_id);
@@ -234,13 +253,45 @@ void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id)
234 return; 253 return;
235} 254}
236 255
256int gm20b_load_falcon_ucode(struct gk20a *g, u32 falconidmask)
257{
258 u32 err = 0;
259 u32 flags = PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
260 unsigned long timeout = gk20a_get_gr_idle_timeout(g);
261
262 /* GM20B PMU supports loading FECS only */
263 if (!(falconidmask == (1 << LSF_FALCON_ID_FECS)))
264 return -EINVAL;
265 /* check whether pmu is ready to bootstrap lsf if not wait for it */
266 if (!g->ops.pmu.lspmuwprinitdone) {
267 pmu_wait_message_cond(&g->pmu,
268 gk20a_get_gr_idle_timeout(g),
269 &g->ops.pmu.lspmuwprinitdone, 1);
270 /* check again if it still not ready indicate an error */
271 if (!g->ops.pmu.lspmuwprinitdone) {
272 gk20a_err(dev_from_gk20a(g),
273 "PMU not ready to load LSF");
274 return -ETIMEDOUT;
275 }
276 }
277 /* load FECS */
278 gk20a_writel(g,
279 gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
280 gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS, flags);
281 err = pmu_gm20b_ctx_wait_lsf_ready(g, timeout,
282 0x55AA55AA);
283 return err;
284}
285
237void gm20b_init_pmu_ops(struct gpu_ops *gops) 286void gm20b_init_pmu_ops(struct gpu_ops *gops)
238{ 287{
239 if (gops->privsecurity) { 288 if (gops->privsecurity) {
240 gm20b_init_secure_pmu(gops); 289 gm20b_init_secure_pmu(gops);
241 gops->pmu.init_wpr_region = gm20b_pmu_init_acr; 290 gops->pmu.init_wpr_region = gm20b_pmu_init_acr;
291 gops->pmu.load_lsfalcon_ucode = gm20b_load_falcon_ucode;
242 } else { 292 } else {
243 gk20a_init_pmu_ops(gops); 293 gk20a_init_pmu_ops(gops);
294 gops->pmu.load_lsfalcon_ucode = NULL;
244 gops->pmu.init_wpr_region = NULL; 295 gops->pmu.init_wpr_region = NULL;
245 } 296 }
246 gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg; 297 gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg;
diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h
index 93745498..68f342cc 100644
--- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h
+++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h
@@ -17,7 +17,7 @@
17#define __PMU_GM20B_H_ 17#define __PMU_GM20B_H_
18 18
19void gm20b_init_pmu_ops(struct gpu_ops *gops); 19void gm20b_init_pmu_ops(struct gpu_ops *gops);
20void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id); 20void gm20b_pmu_load_lsf(struct gk20a *g, u32 falcon_id, u32 flags);
21int gm20b_pmu_init_acr(struct gk20a *g); 21int gm20b_pmu_init_acr(struct gk20a *g);
22 22
23#endif /*__PMU_GM20B_H_*/ 23#endif /*__PMU_GM20B_H_*/