From 748475df20bbe6843bdf4fbc02384dc5aa28866e Mon Sep 17 00:00:00 2001 From: Vijayakumar Date: Tue, 30 Sep 2014 20:19:44 +0530 Subject: gpu: nvgpu: gm20b: Support secure FECS recovery When falcons are secured use PMU commands to reload FECS firmware. Bug 200042729 Change-Id: I09f2472b16dac6a510dba067bce3950075973d5f Signed-off-by: Vijayakumar Reviewed-on: http://git-master/r/552544 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom --- drivers/gpu/nvgpu/gm20b/gr_gm20b.c | 69 +++++++++++++++++++++++--- drivers/gpu/nvgpu/gm20b/pmu_gm20b.c | 96 ++++++++++++++++++++++++++++++++++++- drivers/gpu/nvgpu/gm20b/pmu_gm20b.h | 1 + 3 files changed, 158 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/nvgpu/gm20b') diff --git a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c index 660ffa88..8a3de4e8 100644 --- a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c @@ -14,6 +14,7 @@ */ #include +#include /* for mdelay */ #include "gk20a/gk20a.h" #include "gk20a/gr_gk20a.h" @@ -24,6 +25,8 @@ #include "hw_proj_gm20b.h" #include "hw_ctxsw_prog_gm20b.h" #include "hw_fuse_gm20b.h" +#include "pmu_gm20b.h" +#include "acr_gm20b.h" static void gr_gm20b_init_gpc_mmu(struct gk20a *g) { @@ -625,8 +628,29 @@ static void gr_gm20b_load_gpccs_with_bootloader(struct gk20a *g) gr_fecs_falcon_hwcfg_r()); } +static int gr_gm20b_ctx_wait_lsf_ready(struct gk20a *g, u32 timeout, u32 val) +{ + unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); + unsigned long delay = GR_IDLE_CHECK_DEFAULT; + u32 reg; + + gk20a_dbg_fn(""); + reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0)); + do { + reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0)); + if (reg == val) + return 0; + usleep_range(delay, delay * 2); + delay = min_t(u32, delay << 1, GR_IDLE_CHECK_MAX); + } while (time_before(jiffies, end_jiffies) || + !tegra_platform_is_silicon()); + + return -ETIMEDOUT; +} + static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g) { + u32 err; gk20a_dbg_fn(""); if (tegra_platform_is_linsim()) { @@ -636,16 +660,49 @@ 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); - 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); + if (g->ops.pmu.fecsrecoveryinprogress) { + unsigned long timeout = gk20a_get_gr_idle_timeout(g); + 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(), + 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_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)); + 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_dbg_fn("done"); diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c index 98dc6845..91927950 100644 --- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c @@ -13,7 +13,9 @@ * more details. */ +#include /* for udelay */ #include "gk20a/gk20a.h" +#include "gk20a/pmu_gk20a.h" #include "acr_gm20b.h" #include "pmu_gm20b.h" @@ -26,6 +28,9 @@ struct pg_init_sequence_list { u32 writeval; }; +#define gm20b_dbg_pmu(fmt, arg...) \ + gk20a_dbg(gpu_dbg_pmu, fmt, ##arg) + /* PROD settings for ELPG sequencing registers*/ static struct pg_init_sequence_list _pginitseq_gm20b[] = { @@ -148,11 +153,98 @@ int gm20b_pmu_setup_elpg(struct gk20a *g) return ret; } +void pmu_handle_acr_init_wpr_msg(struct gk20a *g, struct pmu_msg *msg, + void *param, u32 handle, u32 status) +{ + gk20a_dbg_fn(""); + + 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; + gk20a_dbg_fn("done"); +} + + +int gm20b_pmu_init_acr(struct gk20a *g) +{ + struct pmu_gk20a *pmu = &g->pmu; + struct pmu_cmd cmd; + u32 seq; + + gk20a_dbg_fn(""); + + /* init ACR */ + memset(&cmd, 0, sizeof(struct pmu_cmd)); + cmd.hdr.unit_id = PMU_UNIT_ACR; + cmd.hdr.size = PMU_CMD_HDR_SIZE + + sizeof(struct pmu_acr_cmd_init_wpr_details); + cmd.cmd.acr.init_wpr.cmd_type = PMU_ACR_CMD_ID_INIT_WPR_REGION; + cmd.cmd.acr.init_wpr.regionid = 0x01; + cmd.cmd.acr.init_wpr.wproffset = 0x00; + gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_INIT_WPR_REGION"); + gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, + pmu_handle_acr_init_wpr_msg, pmu, &seq, ~0); + + gk20a_dbg_fn("done"); + return 0; +} + +void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg, + void *param, u32 handle, u32 status) +{ + + gk20a_dbg_fn(""); + + + if (msg->msg.acr.acrmsg.falconid == LSF_FALCON_ID_FECS) + gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_BOOTSTRAP_FALCON"); + + gm20b_dbg_pmu("response code = %x\n", msg->msg.acr.acrmsg.falconid); + gk20a_dbg_fn("done"); +} + +void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id) +{ + struct pmu_gk20a *pmu = &g->pmu; + struct pmu_cmd cmd; + u32 seq; + + gk20a_dbg_fn(""); + + gm20b_dbg_pmu("wprinit status = %x\n", g->ops.pmu.lspmuwprinitdone); + if (g->ops.pmu.lspmuwprinitdone && g->ops.pmu.fecsbootstrapdone) { + /* send message to load FECS falcon */ + memset(&cmd, 0, sizeof(struct pmu_cmd)); + cmd.hdr.unit_id = PMU_UNIT_ACR; + cmd.hdr.size = PMU_CMD_HDR_SIZE + + sizeof(struct pmu_acr_cmd_bootstrap_falcon); + cmd.cmd.acr.bootstrap_falcon.cmd_type = + PMU_ACR_CMD_ID_BOOTSTRAP_FALCON; + 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; + gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, + pmu_handle_fecs_boot_acr_msg, pmu, &seq, ~0); + } + + gk20a_dbg_fn("done"); + return; +} + void gm20b_init_pmu_ops(struct gpu_ops *gops) { - if (gops->privsecurity) + if (gops->privsecurity) { gm20b_init_secure_pmu(gops); - else + gops->pmu.init_wpr_region = gm20b_pmu_init_acr; + } else { gk20a_init_pmu_ops(gops); + gops->pmu.init_wpr_region = NULL; + } gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg; + gops->pmu.lspmuwprinitdone = false; + gops->pmu.fecsbootstrapdone = false; + gops->pmu.fecsrecoveryinprogress = 0; } diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h index fc2f7d60..f62a0786 100644 --- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h +++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.h @@ -17,5 +17,6 @@ #define __PMU_GM20B_H_ void gm20b_init_pmu_ops(struct gpu_ops *gops); +void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id); #endif /*__PMU_GM20B_H_*/ -- cgit v1.2.2