diff options
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.c | 19 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.h | 90 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/gr_gm20b.c | 69 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/pmu_gm20b.c | 96 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/pmu_gm20b.h | 1 |
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 | ||
2267 | int gk20a_init_pmu_support(struct gk20a *g) | 2268 | int 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 | ||
2752 | static int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, | 2753 | int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, |
2753 | u32 *var, u32 val); | 2754 | u32 *var, u32 val); |
2754 | 2755 | ||
2755 | static void pmu_handle_zbc_msg(struct gk20a *g, struct pmu_msg *msg, | 2756 | static 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 | ||
2933 | static int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout, | 2938 | int 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 | |||
295 | enum { | 294 | enum { |
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 | |||
647 | enum { | ||
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 | */ | ||
655 | struct 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 | */ | ||
665 | struct 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 | |||
674 | struct 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 | */ | ||
703 | struct pmu_acr_msg_bootstrap_falcon { | ||
704 | u8 msg_type; | ||
705 | union { | ||
706 | u32 errorcode; | ||
707 | u32 falconid; | ||
708 | }; | ||
709 | }; | ||
710 | |||
711 | struct 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, | |||
1145 | int gk20a_aelpg_init(struct gk20a *g); | 1229 | int gk20a_aelpg_init(struct gk20a *g); |
1146 | int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id); | 1230 | int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id); |
1147 | void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable); | 1231 | void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable); |
1232 | int 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 | ||
28 | static void gr_gm20b_init_gpc_mmu(struct gk20a *g) | 31 | static 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 | ||
631 | static 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 | |||
628 | static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g) | 651 | static 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*/ |
31 | static struct pg_init_sequence_list _pginitseq_gm20b[] = { | 36 | static 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 | ||
156 | void 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 | |||
169 | int 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 | |||
193 | void 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 | |||
207 | void 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 | |||
151 | void gm20b_init_pmu_ops(struct gpu_ops *gops) | 237 | void 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 | ||
19 | void gm20b_init_pmu_ops(struct gpu_ops *gops); | 19 | void gm20b_init_pmu_ops(struct gpu_ops *gops); |
20 | void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id); | ||
20 | 21 | ||
21 | #endif /*__PMU_GM20B_H_*/ | 22 | #endif /*__PMU_GM20B_H_*/ |