2 <:copyright-BRCM:2018:DUAL/GPL:standard
4 Copyright (c) 2018 Broadcom
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License, version 2, as published by
9 the Free Software Foundation (the "GPL").
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
17 A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by
18 writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
23 #include <arch_helpers.h>
27 #include <platform_def.h>
32 #include <delay_timer.h>
33 #include <pmc_drv_special.h>
35 extern int pmc_cpu_core_power_up(int cpu
);
36 extern int pmc_cpu_core_power_down(int cpu
);
37 extern void pmc_initmode(void);
38 extern void udelay(uint32_t);
39 extern void sp_min_warm_entrypoint(void);
40 extern void gicv2_pcpu_distif_init(void);
41 extern void gicv2_cpuif_enable(void);
42 extern void a9_gic_secure_init(void);
45 * set specified CPU start address in the BIUCFG address space.
47 #if defined (PLATFORM_FLAVOR_6858) && defined(BIUCFG_BASE)
48 #define BIUCFG_EP_LO(i) ((void*)BIUCFG_BASE + 0x120 + (i) * 4)
50 #define BIUCFG_EP_LO(i) ((void*)BIUCFG_BASE + 0x120 + (i) * 8)
51 #define BIUCFG_EP_HI(i) ((void*)BIUCFG_BASE + 0x124 + (i) * 8)
54 static void biu_set_cpu_ep(int cpu
, long ep
)
56 #if defined(BIUCFG_BASE)
57 #if defined (PLATFORM_FLAVOR_6858)
58 writel(((u32
)ep
) >> 8, BIUCFG_EP_LO(cpu
));
60 writeq(ep
, BIUCFG_EP_LO(cpu
));
62 #elif defined(BIUCTRL_BASE)
63 BIUCTRL
->power_cfg
|= 1 << (cpu
+ BIU_CPU_CTRL_PWR_CFG_CPU0_BPCM_INIT_ON_SHIFT
);
64 BIUCTRL
->reset_cfg
&= ~(0x1 << cpu
);
67 #if (!defined (PLATFORM_FLAVOR_6858) && !defined (PLATFORM_FLAVOR_6856))
69 BOOT_LUT
->bootLutRst
= (u32
)ep
;
72 #if defined(BOOTLUT_BASE)
73 writel((u32
)ep
, (u32
*)(BOOTLUT_BASE
+0x20));
78 /*******************************************************************************
79 * Platform handler called to check the validity of the power state
80 * parameter. The power state parameter has to be a composite power state.
81 ******************************************************************************/
82 static int brcm_validate_power_state(unsigned int power_state
,
83 psci_power_state_t
*req_state
)
85 return PSCI_E_SUCCESS
;
88 /*******************************************************************************
89 * Platform handler called to check the validity of the non secure
91 ******************************************************************************/
92 static int brcm_validate_ns_entrypoint(uintptr_t entrypoint
)
95 * Check if the non secure entrypoint lies within the non
98 return PSCI_E_SUCCESS
;
101 /*******************************************************************************
102 * Platform handler called when a CPU is about to enter standby.
103 ******************************************************************************/
104 static void brcm_cpu_standby(plat_local_state_t cpu_state
)
107 assert(cpu_state
== PLAT_LOCAL_STATE_RET
);
110 * Enter standby state
111 * dsb is good practice before using wfi to enter low power states
117 /*******************************************************************************
118 * Platform handler called when a power domain is about to be turned on. The
119 * mpidr determines the CPU to be turned on.
120 ******************************************************************************/
121 static int brcm_pwr_domain_on(u_register_t mpidr
)
123 int rc
= PSCI_E_SUCCESS
;
126 * here it is assumed that CFE didn't start the CPUs. Set the
127 * CPU entry point and power the CPU up.
130 biu_set_cpu_ep(mpidr
& 0xff, (long)sp_min_warm_entrypoint
);
132 biu_set_cpu_ep(mpidr
& 0xff, (long)bl31_warm_entrypoint
);
134 if (pmc_cpu_core_power_up(mpidr
& 0xff) < 0)
135 rc
= PSCI_E_INTERN_FAIL
;
139 /*******************************************************************************
140 * Platform handler called when a power domain is about to be turned off. The
141 * target_state encodes the power state that each level should transition to.
142 ******************************************************************************/
143 void brcm_pwr_domain_off(const psci_power_state_t
*target_state
)
145 #if defined (PLATFORM_FLAVOR_63138)
148 gicv2_cpuif_disable();
152 /*******************************************************************************
153 * Platform handler called when a power domain is about to be suspended. The
154 * target_state encodes the power state that each level should transition to.
155 ******************************************************************************/
156 void brcm_pwr_domain_suspend(const psci_power_state_t
*target_state
)
161 /*******************************************************************************
162 * Platform handler called when a power domain has just been powered on after
163 * being turned off earlier. The target_state encodes the low power state that
164 * each level has woken up from.
165 ******************************************************************************/
166 void brcm_pwr_domain_on_finish(const psci_power_state_t
*target_state
)
168 assert(target_state
->pwr_domain_state
[MPIDR_AFFLVL0
] ==
169 PLAT_LOCAL_STATE_OFF
);
171 #if defined (PLATFORM_FLAVOR_63138)
172 a9_gic_secure_init();
174 /* TODO: This setup is needed only after a cold boot */
175 gicv2_pcpu_distif_init();
177 /* Enable the gic cpu interface */
178 gicv2_cpuif_enable();
182 /*******************************************************************************
183 * Platform handler called when a power domain has just been powered on after
184 * having been suspended earlier. The target_state encodes the low power state
185 * that each level has woken up from.
186 ******************************************************************************/
187 void brcm_pwr_domain_suspend_finish(const psci_power_state_t
*target_state
)
192 /*******************************************************************************
193 * Platform handler called when a power domain is about to be turned off. The
194 * target_state encodes the power state that each level should transition to.
195 ******************************************************************************/
196 __dead2
void brcm_pwr_domain_pwr_down_wfi(const psci_power_state_t
*target_state
)
198 int idx
= plat_my_core_pos();
200 pmc_cpu_core_power_down(idx
);
201 psci_power_down_wfi();
206 /*******************************************************************************
207 * Platform handlers to shutdown/reboot the system
208 ******************************************************************************/
209 static void __dead2
brcm_system_off(void)
211 ERROR("BRCM System Off: operation not handled.\n");
215 static void __dead2
brcm_system_reset(void)
217 #if defined(WDTIMR0_BASE)
218 INFO("performing system reset from PSCI.\n");
220 #if defined(AARCH32) && ! defined(PLATFORM_FLAVOR_6846)
221 WDTIMER0
->WDTimerCtl
= SOFT_RESET
;
223 WDTIMER0
->SoftRst
= SOFT_RESET
;
226 * delay 1 second before assuming reset has failed.
229 ERROR("watchdog system reset failed.");
231 #elif defined(TIMR_BASE)
232 ((volatile Timer
* const) (TIMR_BASE
+ TIMR_OFFSET
))->SoftRst
|= SOFT_RESET
;
237 static const plat_psci_ops_t plat_brcm_psci_pm_ops
= {
238 .cpu_standby
= brcm_cpu_standby
,
239 .pwr_domain_on
= brcm_pwr_domain_on
,
240 .pwr_domain_off
= brcm_pwr_domain_off
,
241 .pwr_domain_suspend
= brcm_pwr_domain_suspend
,
242 .pwr_domain_on_finish
= brcm_pwr_domain_on_finish
,
243 .pwr_domain_suspend_finish
= brcm_pwr_domain_suspend_finish
,
244 .pwr_domain_pwr_down_wfi
= brcm_pwr_domain_pwr_down_wfi
,
245 .system_off
= brcm_system_off
,
246 .system_reset
= brcm_system_reset
,
247 .validate_power_state
= brcm_validate_power_state
,
248 .validate_ns_entrypoint
= brcm_validate_ns_entrypoint
251 int plat_setup_psci_ops(uintptr_t sec_entrypoint
,
252 const plat_psci_ops_t
**psci_ops
)
254 #if defined(PLATFORM_FLAVOR_63138) || defined (PMB_ADDR_ORION_CPU0)
258 *psci_ops
= &plat_brcm_psci_pm_ops
;