diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index ce8d1d62e..67a6123e8 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -377,15 +377,15 @@ struct gpu_ops { int (*pmu_setup_hw_and_bootstrap)(struct gk20a *g); int (*pmu_setup_elpg)(struct gk20a *g); int (*init_wpr_region)(struct gk20a *g); - bool lspmuwprinitdone; + u32 lspmuwprinitdone; bool fecsbootstrapdone; - u32 fecsrecoveryinprogress; } pmu; struct { int (*init_clk_support)(struct gk20a *g); int (*suspend_clk_support)(struct gk20a *g); } clk; bool privsecurity; + bool securegpccs; struct { const struct regop_offset_range* ( *get_global_whitelist_ranges)(void); diff --git a/drivers/gpu/nvgpu/gk20a/hal_gk20a.c b/drivers/gpu/nvgpu/gk20a/hal_gk20a.c index 5a9c38eaf..b8268e1fd 100644 --- a/drivers/gpu/nvgpu/gk20a/hal_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/hal_gk20a.c @@ -52,6 +52,7 @@ int gk20a_init_hal(struct gk20a *g) *gops = gk20a_ops; gops->privsecurity = 0; + gops->securegpccs = 0; gk20a_init_mc(gops); gk20a_init_ltc(gops); gk20a_init_gr_ops(gops); diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c index 6313b9d58..2456c784e 100644 --- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c @@ -3333,12 +3333,16 @@ int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, struct gk20a *g = gk20a_from_pmu(pmu); unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); unsigned long delay = GR_IDLE_CHECK_DEFAULT; + u32 servicedpmuint; + servicedpmuint = pwr_falcon_irqstat_halt_true_f() | + pwr_falcon_irqstat_exterr_true_f() | + pwr_falcon_irqstat_swgen0_true_f(); do { if (*var == val) return 0; - if (gk20a_readl(g, pwr_falcon_irqstat_r())) + if (gk20a_readl(g, pwr_falcon_irqstat_r()) & servicedpmuint) gk20a_pmu_isr(g); usleep_range(delay, delay * 2); @@ -4042,8 +4046,6 @@ int gk20a_pmu_destroy(struct gk20a *g) pmu->zbc_ready = false; g->ops.pmu.lspmuwprinitdone = false; g->ops.pmu.fecsbootstrapdone = false; - g->ops.pmu.fecsrecoveryinprogress = 0; - gk20a_dbg_fn("done"); return 0; diff --git a/drivers/gpu/nvgpu/gm20b/acr_gm20b.c b/drivers/gpu/nvgpu/gm20b/acr_gm20b.c index 2e33c3f00..ba47d235c 100644 --- a/drivers/gpu/nvgpu/gm20b/acr_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/acr_gm20b.c @@ -57,6 +57,7 @@ static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr *plsfm); static get_ucode_details pmu_acr_supp_ucode_list[] = { pmu_ucode_details, fecs_ucode_details, + gpccs_ucode_details, }; /*Once is LS mode, cpuctl_alias is only accessible*/ @@ -209,6 +210,77 @@ rel_sig: release_firmware(fecs_sig); return err; } +int gpccs_ucode_details(struct gk20a *g, struct flcn_ucode_img *p_img) +{ + struct lsf_ucode_desc *lsf_desc; + const struct firmware *gpccs_sig; + int err; + + if (g->ops.securegpccs == false) + return -ENOENT; + + gpccs_sig = gk20a_request_firmware(g, GM20B_FECS_UCODE_SIG); + if (!gpccs_sig) { + gk20a_err(dev_from_gk20a(g), "failed to load gpccs sig"); + return -ENOENT; + } + lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc), GFP_KERNEL); + if (!lsf_desc) { + err = -ENOMEM; + goto rel_sig; + } + memcpy(lsf_desc, (void *)gpccs_sig->data, + sizeof(struct lsf_ucode_desc)); + lsf_desc->falcon_id = LSF_FALCON_ID_GPCCS; + + p_img->desc = kzalloc(sizeof(struct pmu_ucode_desc), GFP_KERNEL); + if (p_img->desc == NULL) { + err = -ENOMEM; + goto free_lsf_desc; + } + + p_img->desc->bootloader_start_offset = + 0; + p_img->desc->bootloader_size = + ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256); + p_img->desc->bootloader_imem_offset = + g->ctxsw_ucode_info.gpccs.boot_imem_offset; + p_img->desc->bootloader_entry_point = + g->ctxsw_ucode_info.gpccs.boot_entry; + + p_img->desc->image_size = + ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256) + + ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) + + ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); + p_img->desc->app_size = ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) + + ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); + p_img->desc->app_start_offset = p_img->desc->bootloader_size; + p_img->desc->app_imem_offset = 0; + p_img->desc->app_imem_entry = 0; + p_img->desc->app_dmem_offset = 0; + p_img->desc->app_resident_code_offset = 0; + p_img->desc->app_resident_code_size = + ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256); + p_img->desc->app_resident_data_offset = + ALIGN(g->ctxsw_ucode_info.gpccs.data.offset, 256) - + ALIGN(g->ctxsw_ucode_info.gpccs.code.offset, 256); + p_img->desc->app_resident_data_size = + ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256); + p_img->data = (u32 *)((u8 *)g->ctxsw_ucode_info.surface_desc.cpu_va + + g->ctxsw_ucode_info.gpccs.boot.offset); + p_img->data_size = ALIGN(p_img->desc->image_size, 256); + p_img->fw_ver = NULL; + p_img->header = NULL; + p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc; + gm20b_dbg_pmu("gpccs fw loaded\n"); + release_firmware(gpccs_sig); + return 0; +free_lsf_desc: + kfree(lsf_desc); +rel_sig: + release_firmware(gpccs_sig); + return err; +} int prepare_ucode_blob(struct gk20a *g) { @@ -571,6 +643,18 @@ static int lsfm_init_wpr_contents(struct gk20a *g, struct ls_flcn_mgr *plsfm, gm20b_dbg_pmu("bl_data_size :%x %x\n", pnode->lsb_header.bl_data_size, lsb_hdr->bl_data_size); + gm20b_dbg_pmu("app_code_off :%x %x\n", + pnode->lsb_header.app_code_off, + lsb_hdr->app_code_off); + gm20b_dbg_pmu("app_code_size :%x %x\n", + pnode->lsb_header.app_code_size, + lsb_hdr->app_code_size); + gm20b_dbg_pmu("app_data_off :%x %x\n", + pnode->lsb_header.app_data_off, + lsb_hdr->app_data_off); + gm20b_dbg_pmu("app_data_size :%x %x\n", + pnode->lsb_header.app_data_size, + lsb_hdr->app_data_size); gm20b_dbg_pmu("flags :%x %x\n", pnode->lsb_header.flags, lsb_hdr->flags); @@ -702,16 +786,6 @@ static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g, VA range */ pnode->lsb_header.bl_imem_off = pnode->ucode_img.desc->bootloader_imem_offset; - pnode->lsb_header.app_code_off = - pnode->ucode_img.desc->app_start_offset + - pnode->ucode_img.desc->app_resident_code_offset; - pnode->lsb_header.app_code_size = - pnode->ucode_img.desc->app_resident_code_size; - pnode->lsb_header.app_data_off = - pnode->ucode_img.desc->app_start_offset + - pnode->ucode_img.desc->app_resident_data_offset; - pnode->lsb_header.app_data_size = - pnode->ucode_img.desc->app_resident_data_size; /* TODO: OBJFLCN should export properties using which the below flags should be populated.*/ @@ -721,6 +795,10 @@ static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g, data = NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE; pnode->lsb_header.flags = data; } + if (falcon_id == LSF_FALCON_ID_GPCCS) { + pnode->lsb_header.flags |= + NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE; + } } } @@ -742,6 +820,9 @@ static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr *plsfm, pnode->wpr_header.bootstrap_owner = LSF_BOOTSTRAP_OWNER_DEFAULT; pnode->wpr_header.status = LSF_IMAGE_STATUS_COPY; + if (falcon_id == LSF_FALCON_ID_GPCCS) + pnode->wpr_header.lazy_bootstrap = 1; + /*TODO to check if PDB_PROP_FLCN_LAZY_BOOTSTRAP is to be supported by Android */ /* Fill in static LSB header info elsewhere */ @@ -854,6 +935,17 @@ static int lsf_gen_wpr_requirements(struct gk20a *g, struct ls_flcn_mgr *plsfm) /* Finally, update ucode surface size to include updates */ pnode->full_ucode_size = wpr_offset - pnode->lsb_header.ucode_off; + if (pnode->wpr_header.falcon_id != LSF_FALCON_ID_PMU) { + pnode->lsb_header.app_code_off = + pnode->lsb_header.bl_code_size; + pnode->lsb_header.app_code_size = + pnode->lsb_header.ucode_size - + pnode->lsb_header.bl_code_size; + pnode->lsb_header.app_data_off = + pnode->lsb_header.ucode_size; + pnode->lsb_header.app_data_size = + pnode->lsb_header.data_size; + } pnode = pnode->next; } plsfm->wpr_size = wpr_offset; diff --git a/drivers/gpu/nvgpu/gm20b/acr_gm20b.h b/drivers/gpu/nvgpu/gm20b/acr_gm20b.h index c279d7979..3a5fa7d07 100644 --- a/drivers/gpu/nvgpu/gm20b/acr_gm20b.h +++ b/drivers/gpu/nvgpu/gm20b/acr_gm20b.h @@ -21,7 +21,7 @@ /*Defines*/ /*chip specific defines*/ -#define MAX_SUPPORTED_LSFM 2 /*PMU, FECS, GPCCS*/ +#define MAX_SUPPORTED_LSFM 3 /*PMU, FECS, GPCCS*/ #define LSF_UCODE_DATA_ALIGNMENT 4096 #define GM20B_PMU_UCODE_IMAGE "gpmu_ucode_image.bin" @@ -75,6 +75,8 @@ #define NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0_TRUE 1 #define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_FALSE 0 #define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE 4 +#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE 8 +#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_FALSE 0 /*! * Light Secure WPR Content Alignments diff --git a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c index 55a21c987..1fa1eb243 100644 --- a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c @@ -710,6 +710,10 @@ static int gr_gm20b_ctx_wait_lsf_ready(struct gk20a *g, u32 timeout, u32 val) static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g) { u32 err; + unsigned long timeout = gk20a_get_gr_idle_timeout(g); + u32 reg_offset = gr_gpcs_gpccs_falcon_hwcfg_r() - + gr_fecs_falcon_hwcfg_r(); + gk20a_dbg_fn(""); if (tegra_platform_is_linsim()) { @@ -719,50 +723,68 @@ static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g) gr_gpccs_ctxsw_mailbox_value_f(0xc0de7777)); } - gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); - gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS); - - gr_gm20b_load_gpccs_with_bootloader(g); - - if (g->ops.pmu.fecsrecoveryinprogress) { - unsigned long timeout = gk20a_get_gr_idle_timeout(g); + if (g->ops.pmu.fecsbootstrapdone) { + gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); + gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS); err = gr_gm20b_ctx_wait_lsf_ready(g, timeout, 0x55AA55AA); if (err) { gk20a_err(dev_from_gk20a(g), "Unable to recover FECS"); return err; } else { - g->ops.pmu.fecsrecoveryinprogress = 0; - gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); - gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1); - gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), - 0xffffffff); - - gk20a_writel(g, gr_gpccs_dmactl_r(), + if (!g->ops.securegpccs) { + gr_gm20b_load_gpccs_with_bootloader(g); + gk20a_writel(g, gr_gpccs_dmactl_r(), gr_gpccs_dmactl_require_ctx_f(0)); - gk20a_writel(g, gr_gpccs_cpuctl_r(), + gk20a_writel(g, gr_gpccs_cpuctl_r(), gr_gpccs_cpuctl_startcpu_f(1)); - - gk20a_writel(g, gr_fecs_cpuctl_alias_r(), - gr_fecs_cpuctl_startcpu_f(1)); + } else { + gk20a_writel(g, + gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); + gm20b_pmu_load_lsf(g, LSF_FALCON_ID_GPCCS); + err = gr_gm20b_ctx_wait_lsf_ready(g, timeout, + 0x55AA55AA); + gk20a_writel(g, reg_offset + + gr_fecs_cpuctl_alias_r(), + gr_gpccs_cpuctl_startcpu_f(1)); + } + } + } else { + g->ops.pmu.fecsbootstrapdone = true; + if (!g->ops.securegpccs) { + gr_gm20b_load_gpccs_with_bootloader(g); + gk20a_writel(g, gr_gpccs_dmactl_r(), + gr_gpccs_dmactl_require_ctx_f(0)); + gk20a_writel(g, gr_gpccs_cpuctl_r(), + gr_gpccs_cpuctl_startcpu_f(1)); + } else { + pmu_wait_message_cond(&g->pmu, + gk20a_get_gr_idle_timeout(g), + &g->ops.pmu.lspmuwprinitdone, 1); + if (!g->ops.pmu.lspmuwprinitdone) { + gk20a_err(dev_from_gk20a(g), + "PMU WPR needed but not ready yet"); + return -ETIMEDOUT; + } + gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); + gm20b_pmu_load_lsf(g, LSF_FALCON_ID_GPCCS); + err = gr_gm20b_ctx_wait_lsf_ready(g, timeout, + 0x55AA55AA); + if (err) { + gk20a_err(dev_from_gk20a(g), + "Unable to boot GPCCS\n"); + return err; + } + gk20a_writel(g, reg_offset + + gr_fecs_cpuctl_alias_r(), + gr_gpccs_cpuctl_startcpu_f(1)); } } - - if (!g->ops.pmu.fecsbootstrapdone) { - g->ops.pmu.fecsbootstrapdone = true; - gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); - gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1); - gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff); - - gk20a_writel(g, gr_gpccs_dmactl_r(), - gr_gpccs_dmactl_require_ctx_f(0)); - gk20a_writel(g, gr_gpccs_cpuctl_r(), - gr_gpccs_cpuctl_startcpu_f(1)); - - gk20a_writel(g, gr_fecs_cpuctl_alias_r(), - gr_fecs_cpuctl_startcpu_f(1)); - } - + gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0); + gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1); + gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff); + gk20a_writel(g, gr_fecs_cpuctl_alias_r(), + gr_fecs_cpuctl_startcpu_f(1)); gk20a_dbg_fn("done"); return 0; diff --git a/drivers/gpu/nvgpu/gm20b/hal_gm20b.c b/drivers/gpu/nvgpu/gm20b/hal_gm20b.c index d5a6e4222..1ab658360 100644 --- a/drivers/gpu/nvgpu/gm20b/hal_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/hal_gm20b.c @@ -91,6 +91,7 @@ int gm20b_init_hal(struct gk20a *g) struct nvgpu_gpu_characteristics *c = &g->gpu_characteristics; *gops = gm20b_ops; + gops->securegpccs = false; #ifdef CONFIG_TEGRA_ACR if (tegra_platform_is_linsim()) { gops->privsecurity = 1; diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c index c25d2d563..28b40b1c8 100644 --- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c @@ -161,7 +161,7 @@ static void pmu_handle_acr_init_wpr_msg(struct gk20a *g, struct pmu_msg *msg, gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_INIT_WPR_REGION"); if (msg->msg.acr.acrmsg.errorcode == PMU_ACR_SUCCESS) - g->ops.pmu.lspmuwprinitdone = true; + g->ops.pmu.lspmuwprinitdone = 1; gk20a_dbg_fn("done"); } @@ -213,7 +213,7 @@ void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id) gk20a_dbg_fn(""); gm20b_dbg_pmu("wprinit status = %x\n", g->ops.pmu.lspmuwprinitdone); - if (g->ops.pmu.lspmuwprinitdone && g->ops.pmu.fecsbootstrapdone) { + if (g->ops.pmu.lspmuwprinitdone) { /* send message to load FECS falcon */ memset(&cmd, 0, sizeof(struct pmu_cmd)); cmd.hdr.unit_id = PMU_UNIT_ACR; @@ -224,8 +224,8 @@ void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id) cmd.cmd.acr.bootstrap_falcon.flags = PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES; cmd.cmd.acr.bootstrap_falcon.falconid = falcon_id; - gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON"); - g->ops.pmu.fecsrecoveryinprogress = 1; + gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON: %x\n", + falcon_id); gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, pmu_handle_fecs_boot_acr_msg, pmu, &seq, ~0); } @@ -244,7 +244,6 @@ void gm20b_init_pmu_ops(struct gpu_ops *gops) gops->pmu.init_wpr_region = NULL; } gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg; - gops->pmu.lspmuwprinitdone = false; + gops->pmu.lspmuwprinitdone = 0; gops->pmu.fecsbootstrapdone = false; - gops->pmu.fecsrecoveryinprogress = 0; }