summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorVijayakumar <vsubbu@nvidia.com>2014-09-30 10:49:44 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:11:52 -0400
commit748475df20bbe6843bdf4fbc02384dc5aa28866e (patch)
tree700012cf758d6731017b8b23153abae4311bf065 /drivers/gpu
parent4739499f07b29282ee1031d08adaa76c238da2a6 (diff)
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 <vsubbu@nvidia.com> Reviewed-on: http://git-master/r/552544 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h4
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.c19
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.h90
-rw-r--r--drivers/gpu/nvgpu/gm20b/gr_gm20b.c69
-rw-r--r--drivers/gpu/nvgpu/gm20b/pmu_gm20b.c96
-rw-r--r--drivers/gpu/nvgpu/gm20b/pmu_gm20b.h1
6 files changed, 264 insertions, 15 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index 20afd2bd..5669e1c5 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -307,6 +307,10 @@ struct gpu_ops {
307 int (*prepare_ucode)(struct gk20a *g); 307 int (*prepare_ucode)(struct gk20a *g);
308 int (*pmu_setup_hw_and_bootstrap)(struct gk20a *g); 308 int (*pmu_setup_hw_and_bootstrap)(struct gk20a *g);
309 int (*pmu_setup_elpg)(struct gk20a *g); 309 int (*pmu_setup_elpg)(struct gk20a *g);
310 int (*init_wpr_region)(struct gk20a *g);
311 bool lspmuwprinitdone;
312 bool fecsbootstrapdone;
313 u32 fecsrecoveryinprogress;
310 } pmu; 314 } pmu;
311 struct { 315 struct {
312 int (*init_clk_support)(struct gk20a *g); 316 int (*init_clk_support)(struct gk20a *g);
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
index e60de70b..0580f19d 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
@@ -2262,6 +2262,7 @@ void gk20a_init_pmu_ops(struct gpu_ops *gops)
2262 gops->pmu.prepare_ucode = gk20a_prepare_ucode; 2262 gops->pmu.prepare_ucode = gk20a_prepare_ucode;
2263 gops->pmu.pmu_setup_hw_and_bootstrap = gk20a_init_pmu_setup_hw1; 2263 gops->pmu.pmu_setup_hw_and_bootstrap = gk20a_init_pmu_setup_hw1;
2264 gops->pmu.pmu_setup_elpg = NULL; 2264 gops->pmu.pmu_setup_elpg = NULL;
2265 gops->pmu.init_wpr_region = NULL;
2265} 2266}
2266 2267
2267int gk20a_init_pmu_support(struct gk20a *g) 2268int gk20a_init_pmu_support(struct gk20a *g)
@@ -2749,7 +2750,7 @@ static int pmu_response_handle(struct pmu_gk20a *pmu,
2749 return 0; 2750 return 0;
2750} 2751}
2751 2752
2752static int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, 2753int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout,
2753 u32 *var, u32 val); 2754 u32 *var, u32 val);
2754 2755
2755static void pmu_handle_zbc_msg(struct gk20a *g, struct pmu_msg *msg, 2756static void pmu_handle_zbc_msg(struct gk20a *g, struct pmu_msg *msg,
@@ -2902,10 +2903,14 @@ static int pmu_process_message(struct pmu_gk20a *pmu)
2902{ 2903{
2903 struct pmu_msg msg; 2904 struct pmu_msg msg;
2904 int status; 2905 int status;
2906 struct gk20a *g = gk20a_from_pmu(pmu);
2905 2907
2906 if (unlikely(!pmu->pmu_ready)) { 2908 if (unlikely(!pmu->pmu_ready)) {
2907 pmu_process_init_msg(pmu, &msg); 2909 pmu_process_init_msg(pmu, &msg);
2910 if (g->ops.pmu.init_wpr_region != NULL)
2911 g->ops.pmu.init_wpr_region(g);
2908 pmu_init_perfmon(pmu); 2912 pmu_init_perfmon(pmu);
2913
2909 return 0; 2914 return 0;
2910 } 2915 }
2911 2916
@@ -2930,7 +2935,7 @@ static int pmu_process_message(struct pmu_gk20a *pmu)
2930 return 0; 2935 return 0;
2931} 2936}
2932 2937
2933static int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, 2938int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout,
2934 u32 *var, u32 val) 2939 u32 *var, u32 val)
2935{ 2940{
2936 struct gk20a *g = gk20a_from_pmu(pmu); 2941 struct gk20a *g = gk20a_from_pmu(pmu);
@@ -3166,10 +3171,11 @@ void gk20a_pmu_isr(struct gk20a *g)
3166 mask = gk20a_readl(g, pwr_falcon_irqmask_r()) & 3171 mask = gk20a_readl(g, pwr_falcon_irqmask_r()) &
3167 gk20a_readl(g, pwr_falcon_irqdest_r()); 3172 gk20a_readl(g, pwr_falcon_irqdest_r());
3168 3173
3169 intr = gk20a_readl(g, pwr_falcon_irqstat_r()) & mask; 3174 intr = gk20a_readl(g, pwr_falcon_irqstat_r());
3170 3175
3171 gk20a_dbg_pmu("received falcon interrupt: 0x%08x", intr); 3176 gk20a_dbg_pmu("received falcon interrupt: 0x%08x", intr);
3172 3177
3178 intr = gk20a_readl(g, pwr_falcon_irqstat_r()) & mask;
3173 if (!intr || pmu->pmu_state == PMU_STATE_OFF) { 3179 if (!intr || pmu->pmu_state == PMU_STATE_OFF) {
3174 gk20a_writel(g, pwr_falcon_irqsclr_r(), intr); 3180 gk20a_writel(g, pwr_falcon_irqsclr_r(), intr);
3175 mutex_unlock(&pmu->isr_mutex); 3181 mutex_unlock(&pmu->isr_mutex);
@@ -3631,6 +3637,10 @@ int gk20a_pmu_destroy(struct gk20a *g)
3631 pmu->pmu_ready = false; 3637 pmu->pmu_ready = false;
3632 pmu->perfmon_ready = false; 3638 pmu->perfmon_ready = false;
3633 pmu->zbc_ready = false; 3639 pmu->zbc_ready = false;
3640 g->ops.pmu.lspmuwprinitdone = false;
3641 g->ops.pmu.fecsbootstrapdone = false;
3642 g->ops.pmu.fecsrecoveryinprogress = 0;
3643
3634 3644
3635 gk20a_dbg_fn("done"); 3645 gk20a_dbg_fn("done");
3636 return 0; 3646 return 0;
@@ -3738,7 +3748,6 @@ int gk20a_pmu_ap_send_command(struct gk20a *g,
3738 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_INIT"); 3748 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_INIT");
3739 cmd.cmd.pg.ap_cmd.init.pg_sampling_period_us = 3749 cmd.cmd.pg.ap_cmd.init.pg_sampling_period_us =
3740 p_ap_cmd->init.pg_sampling_period_us; 3750 p_ap_cmd->init.pg_sampling_period_us;
3741 p_callback = ap_callback_init_and_enable_ctrl;
3742 break; 3751 break;
3743 3752
3744 case PMU_AP_CMD_ID_INIT_AND_ENABLE_CTRL: 3753 case PMU_AP_CMD_ID_INIT_AND_ENABLE_CTRL:
@@ -3782,7 +3791,7 @@ int gk20a_pmu_ap_send_command(struct gk20a *g,
3782 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, 3791 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
3783 p_callback, pmu, &seq, ~0); 3792 p_callback, pmu, &seq, ~0);
3784 3793
3785 if (!status) { 3794 if (status) {
3786 gk20a_dbg_pmu( 3795 gk20a_dbg_pmu(
3787 "%s: Unable to submit Adaptive Power Command %d\n", 3796 "%s: Unable to submit Adaptive Power Command %d\n",
3788 __func__, p_ap_cmd->cmn.cmd_id); 3797 __func__, p_ap_cmd->cmn.cmd_id);
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
index 6dd1ad3b..823f5484 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
@@ -291,7 +291,6 @@ struct pmu_ap {
291 struct ap_ctrl ap_ctrl[PMU_AP_CTRL_ID_MAX]; 291 struct ap_ctrl ap_ctrl[PMU_AP_CTRL_ID_MAX];
292}; 292};
293 293
294
295enum { 294enum {
296 GK20A_PMU_DMAIDX_UCODE = 0, 295 GK20A_PMU_DMAIDX_UCODE = 0,
297 GK20A_PMU_DMAIDX_VIRT = 1, 296 GK20A_PMU_DMAIDX_VIRT = 1,
@@ -390,7 +389,7 @@ struct pmu_ucode_desc {
390#define PMU_UNIT_INIT (0x07) 389#define PMU_UNIT_INIT (0x07)
391#define PMU_UNIT_FBBA (0x08) 390#define PMU_UNIT_FBBA (0x08)
392#define PMU_UNIT_DIDLE (0x09) 391#define PMU_UNIT_DIDLE (0x09)
393#define PMU_UNIT_AVAILABLE3 (0x0A) 392#define PMU_UNIT_ACR (0x0A)
394#define PMU_UNIT_AVAILABLE4 (0x0B) 393#define PMU_UNIT_AVAILABLE4 (0x0B)
395#define PMU_UNIT_HDCP_MAIN (0x0C) 394#define PMU_UNIT_HDCP_MAIN (0x0C)
396#define PMU_UNIT_HDCP_V (0x0D) 395#define PMU_UNIT_HDCP_V (0x0D)
@@ -643,6 +642,89 @@ struct pmu_pg_cmd {
643 }; 642 };
644}; 643};
645 644
645/* ACR Commands/Message structures */
646
647enum {
648 PMU_ACR_CMD_ID_INIT_WPR_REGION = 0x0 ,
649 PMU_ACR_CMD_ID_BOOTSTRAP_FALCON,
650};
651
652/*
653 * Initializes the WPR region details
654 */
655struct pmu_acr_cmd_init_wpr_details {
656 u8 cmd_type;
657 u32 regionid;
658 u32 wproffset;
659
660};
661
662/*
663 * falcon ID to bootstrap
664 */
665struct pmu_acr_cmd_bootstrap_falcon {
666 u8 cmd_type;
667 u32 flags;
668 u32 falconid;
669};
670
671#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO 1
672#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0
673
674struct pmu_acr_cmd {
675 union {
676 u8 cmd_type;
677 struct pmu_acr_cmd_bootstrap_falcon bootstrap_falcon;
678 struct pmu_acr_cmd_init_wpr_details init_wpr;
679 };
680};
681
682/* acr messages */
683
684/*
685 * returns the WPR region init information
686 */
687#define PMU_ACR_MSG_ID_INIT_WPR_REGION 0
688
689/*
690 * Returns the Bootstrapped falcon ID to RM
691 */
692#define PMU_ACR_MSG_ID_BOOTSTRAP_FALCON 1
693
694/*
695 * Returns the WPR init status
696 */
697#define PMU_ACR_SUCCESS 0
698#define PMU_ACR_ERROR 1
699
700/*
701 * PMU notifies about bootstrap status of falcon
702 */
703struct pmu_acr_msg_bootstrap_falcon {
704 u8 msg_type;
705 union {
706 u32 errorcode;
707 u32 falconid;
708 };
709};
710
711struct pmu_acr_msg {
712 union {
713 u8 msg_type;
714 struct pmu_acr_msg_bootstrap_falcon acrmsg;
715 };
716};
717
718/***************************** ACR ERROR CODES ******************************/
719/*!
720 * Error codes used in PMU-ACR Task
721 *
722 * LSF_ACR_INVALID_TRANSCFG_SETUP : Indicates that TRANSCFG Setup is not valid
723 * MAILBOX1 returns the CTXDMA ID of invalid setup
724 *
725 */
726#define ACR_ERROR_INVALID_TRANSCFG_SETUP (0xAC120001)
727
646/* PERFMON */ 728/* PERFMON */
647#define PMU_DOMAIN_GROUP_PSTATE 0 729#define PMU_DOMAIN_GROUP_PSTATE 0
648#define PMU_DOMAIN_GROUP_GPC2CLK 1 730#define PMU_DOMAIN_GROUP_GPC2CLK 1
@@ -770,6 +852,7 @@ struct pmu_cmd {
770 struct pmu_perfmon_cmd perfmon; 852 struct pmu_perfmon_cmd perfmon;
771 struct pmu_pg_cmd pg; 853 struct pmu_pg_cmd pg;
772 struct pmu_zbc_cmd zbc; 854 struct pmu_zbc_cmd zbc;
855 struct pmu_acr_cmd acr;
773 } cmd; 856 } cmd;
774}; 857};
775 858
@@ -780,6 +863,7 @@ struct pmu_msg {
780 struct pmu_perfmon_msg perfmon; 863 struct pmu_perfmon_msg perfmon;
781 struct pmu_pg_msg pg; 864 struct pmu_pg_msg pg;
782 struct pmu_rc_msg rc; 865 struct pmu_rc_msg rc;
866 struct pmu_acr_msg acr;
783 } msg; 867 } msg;
784}; 868};
785 869
@@ -1145,4 +1229,6 @@ int gk20a_pmu_ap_send_command(struct gk20a *g,
1145int gk20a_aelpg_init(struct gk20a *g); 1229int gk20a_aelpg_init(struct gk20a *g);
1146int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id); 1230int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id);
1147void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable); 1231void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable);
1232int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout,
1233 u32 *var, u32 val);
1148#endif /*__PMU_GK20A_H__*/ 1234#endif /*__PMU_GK20A_H__*/
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 @@
14 */ 14 */
15 15
16#include <linux/types.h> 16#include <linux/types.h>
17#include <linux/delay.h> /* for mdelay */
17 18
18#include "gk20a/gk20a.h" 19#include "gk20a/gk20a.h"
19#include "gk20a/gr_gk20a.h" 20#include "gk20a/gr_gk20a.h"
@@ -24,6 +25,8 @@
24#include "hw_proj_gm20b.h" 25#include "hw_proj_gm20b.h"
25#include "hw_ctxsw_prog_gm20b.h" 26#include "hw_ctxsw_prog_gm20b.h"
26#include "hw_fuse_gm20b.h" 27#include "hw_fuse_gm20b.h"
28#include "pmu_gm20b.h"
29#include "acr_gm20b.h"
27 30
28static void gr_gm20b_init_gpc_mmu(struct gk20a *g) 31static void gr_gm20b_init_gpc_mmu(struct gk20a *g)
29{ 32{
@@ -625,8 +628,29 @@ static void gr_gm20b_load_gpccs_with_bootloader(struct gk20a *g)
625 gr_fecs_falcon_hwcfg_r()); 628 gr_fecs_falcon_hwcfg_r());
626} 629}
627 630
631static int gr_gm20b_ctx_wait_lsf_ready(struct gk20a *g, u32 timeout, u32 val)
632{
633 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
634 unsigned long delay = GR_IDLE_CHECK_DEFAULT;
635 u32 reg;
636
637 gk20a_dbg_fn("");
638 reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0));
639 do {
640 reg = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0));
641 if (reg == val)
642 return 0;
643 usleep_range(delay, delay * 2);
644 delay = min_t(u32, delay << 1, GR_IDLE_CHECK_MAX);
645 } while (time_before(jiffies, end_jiffies) ||
646 !tegra_platform_is_silicon());
647
648 return -ETIMEDOUT;
649}
650
628static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g) 651static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g)
629{ 652{
653 u32 err;
630 gk20a_dbg_fn(""); 654 gk20a_dbg_fn("");
631 655
632 if (tegra_platform_is_linsim()) { 656 if (tegra_platform_is_linsim()) {
@@ -636,16 +660,49 @@ static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g)
636 gr_gpccs_ctxsw_mailbox_value_f(0xc0de7777)); 660 gr_gpccs_ctxsw_mailbox_value_f(0xc0de7777));
637 } 661 }
638 662
663 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
664 gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS);
665
639 gr_gm20b_load_gpccs_with_bootloader(g); 666 gr_gm20b_load_gpccs_with_bootloader(g);
640 667
641 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), 0x0); 668 if (g->ops.pmu.fecsrecoveryinprogress) {
642 gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1); 669 unsigned long timeout = gk20a_get_gr_idle_timeout(g);
643 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff); 670 err = gr_gm20b_ctx_wait_lsf_ready(g, timeout, 0x55AA55AA);
671 if (err) {
672 gk20a_err(dev_from_gk20a(g), "Unable to recover FECS");
673 return err;
674 } else {
675 g->ops.pmu.fecsrecoveryinprogress = 0;
676 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
677 gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1);
678 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6),
679 0xffffffff);
680
681 gk20a_writel(g, gr_gpccs_dmactl_r(),
682 gr_gpccs_dmactl_require_ctx_f(0));
683 gk20a_writel(g, gr_gpccs_cpuctl_r(),
684 gr_gpccs_cpuctl_startcpu_f(1));
685
686 gk20a_writel(g, gr_fecs_cpuctl_alias_r(),
687 gr_fecs_cpuctl_startcpu_f(1));
688 }
689 }
644 690
645 gk20a_writel(g, gr_gpccs_dmactl_r(), gr_gpccs_dmactl_require_ctx_f(0));
646 691
647 gk20a_writel(g, gr_gpccs_cpuctl_r(), gr_gpccs_cpuctl_startcpu_f(1)); 692 if (!g->ops.pmu.fecsbootstrapdone) {
648 gk20a_writel(g, gr_fecs_cpuctl_alias_r(), gr_fecs_cpuctl_startcpu_f(1)); 693 g->ops.pmu.fecsbootstrapdone = true;
694 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
695 gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1);
696 gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff);
697
698 gk20a_writel(g, gr_gpccs_dmactl_r(),
699 gr_gpccs_dmactl_require_ctx_f(0));
700 gk20a_writel(g, gr_gpccs_cpuctl_r(),
701 gr_gpccs_cpuctl_startcpu_f(1));
702
703 gk20a_writel(g, gr_fecs_cpuctl_alias_r(),
704 gr_fecs_cpuctl_startcpu_f(1));
705 }
649 706
650 gk20a_dbg_fn("done"); 707 gk20a_dbg_fn("done");
651 708
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 @@
13 * more details. 13 * more details.
14 */ 14 */
15 15
16#include <linux/delay.h> /* for udelay */
16#include "gk20a/gk20a.h" 17#include "gk20a/gk20a.h"
18#include "gk20a/pmu_gk20a.h"
17#include "acr_gm20b.h" 19#include "acr_gm20b.h"
18#include "pmu_gm20b.h" 20#include "pmu_gm20b.h"
19 21
@@ -26,6 +28,9 @@ struct pg_init_sequence_list {
26 u32 writeval; 28 u32 writeval;
27}; 29};
28 30
31#define gm20b_dbg_pmu(fmt, arg...) \
32 gk20a_dbg(gpu_dbg_pmu, fmt, ##arg)
33
29 34
30/* PROD settings for ELPG sequencing registers*/ 35/* PROD settings for ELPG sequencing registers*/
31static struct pg_init_sequence_list _pginitseq_gm20b[] = { 36static struct pg_init_sequence_list _pginitseq_gm20b[] = {
@@ -148,11 +153,98 @@ int gm20b_pmu_setup_elpg(struct gk20a *g)
148 return ret; 153 return ret;
149} 154}
150 155
156void pmu_handle_acr_init_wpr_msg(struct gk20a *g, struct pmu_msg *msg,
157 void *param, u32 handle, u32 status)
158{
159 gk20a_dbg_fn("");
160
161 gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_INIT_WPR_REGION");
162
163 if (msg->msg.acr.acrmsg.errorcode == PMU_ACR_SUCCESS)
164 g->ops.pmu.lspmuwprinitdone = true;
165 gk20a_dbg_fn("done");
166}
167
168
169int gm20b_pmu_init_acr(struct gk20a *g)
170{
171 struct pmu_gk20a *pmu = &g->pmu;
172 struct pmu_cmd cmd;
173 u32 seq;
174
175 gk20a_dbg_fn("");
176
177 /* init ACR */
178 memset(&cmd, 0, sizeof(struct pmu_cmd));
179 cmd.hdr.unit_id = PMU_UNIT_ACR;
180 cmd.hdr.size = PMU_CMD_HDR_SIZE +
181 sizeof(struct pmu_acr_cmd_init_wpr_details);
182 cmd.cmd.acr.init_wpr.cmd_type = PMU_ACR_CMD_ID_INIT_WPR_REGION;
183 cmd.cmd.acr.init_wpr.regionid = 0x01;
184 cmd.cmd.acr.init_wpr.wproffset = 0x00;
185 gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_INIT_WPR_REGION");
186 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
187 pmu_handle_acr_init_wpr_msg, pmu, &seq, ~0);
188
189 gk20a_dbg_fn("done");
190 return 0;
191}
192
193void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg,
194 void *param, u32 handle, u32 status)
195{
196
197 gk20a_dbg_fn("");
198
199
200 if (msg->msg.acr.acrmsg.falconid == LSF_FALCON_ID_FECS)
201 gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_BOOTSTRAP_FALCON");
202
203 gm20b_dbg_pmu("response code = %x\n", msg->msg.acr.acrmsg.falconid);
204 gk20a_dbg_fn("done");
205}
206
207void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id)
208{
209 struct pmu_gk20a *pmu = &g->pmu;
210 struct pmu_cmd cmd;
211 u32 seq;
212
213 gk20a_dbg_fn("");
214
215 gm20b_dbg_pmu("wprinit status = %x\n", g->ops.pmu.lspmuwprinitdone);
216 if (g->ops.pmu.lspmuwprinitdone && g->ops.pmu.fecsbootstrapdone) {
217 /* send message to load FECS falcon */
218 memset(&cmd, 0, sizeof(struct pmu_cmd));
219 cmd.hdr.unit_id = PMU_UNIT_ACR;
220 cmd.hdr.size = PMU_CMD_HDR_SIZE +
221 sizeof(struct pmu_acr_cmd_bootstrap_falcon);
222 cmd.cmd.acr.bootstrap_falcon.cmd_type =
223 PMU_ACR_CMD_ID_BOOTSTRAP_FALCON;
224 cmd.cmd.acr.bootstrap_falcon.flags =
225 PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
226 cmd.cmd.acr.bootstrap_falcon.falconid = falcon_id;
227 gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON");
228 g->ops.pmu.fecsrecoveryinprogress = 1;
229 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
230 pmu_handle_fecs_boot_acr_msg, pmu, &seq, ~0);
231 }
232
233 gk20a_dbg_fn("done");
234 return;
235}
236
151void gm20b_init_pmu_ops(struct gpu_ops *gops) 237void gm20b_init_pmu_ops(struct gpu_ops *gops)
152{ 238{
153 if (gops->privsecurity) 239 if (gops->privsecurity) {
154 gm20b_init_secure_pmu(gops); 240 gm20b_init_secure_pmu(gops);
155 else 241 gops->pmu.init_wpr_region = gm20b_pmu_init_acr;
242 } else {
156 gk20a_init_pmu_ops(gops); 243 gk20a_init_pmu_ops(gops);
244 gops->pmu.init_wpr_region = NULL;
245 }
157 gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg; 246 gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg;
247 gops->pmu.lspmuwprinitdone = false;
248 gops->pmu.fecsbootstrapdone = false;
249 gops->pmu.fecsrecoveryinprogress = 0;
158} 250}
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 @@
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);
20 21
21#endif /*__PMU_GM20B_H_*/ 22#endif /*__PMU_GM20B_H_*/