Add Broadcom's code for bcm63xx support
[project/bcm63xx/atf.git] / plat / bcm / brcm_pm.c
1 /*
2 <:copyright-BRCM:2018:DUAL/GPL:standard
3
4 Copyright (c) 2018 Broadcom
5 All Rights Reserved
6
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").
10
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.
15
16
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.
20
21 :>
22 */
23 #include <arch_helpers.h>
24 #include <assert.h>
25 #include <debug.h>
26 #include <gicv2.h>
27 #include <platform_def.h>
28 #include <platform.h>
29 #include <psci.h>
30 #include <bl31.h>
31 #include <io.h>
32 #include <delay_timer.h>
33 #include <pmc_drv_special.h>
34
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);
43
44 /*
45 * set specified CPU start address in the BIUCFG address space.
46 */
47 #if defined (PLATFORM_FLAVOR_6858) && defined(BIUCFG_BASE)
48 #define BIUCFG_EP_LO(i) ((void*)BIUCFG_BASE + 0x120 + (i) * 4)
49 #else
50 #define BIUCFG_EP_LO(i) ((void*)BIUCFG_BASE + 0x120 + (i) * 8)
51 #define BIUCFG_EP_HI(i) ((void*)BIUCFG_BASE + 0x124 + (i) * 8)
52 #endif
53
54 static void biu_set_cpu_ep(int cpu, long ep)
55 {
56 #if defined(BIUCFG_BASE)
57 #if defined (PLATFORM_FLAVOR_6858)
58 writel(((u32)ep) >> 8, BIUCFG_EP_LO(cpu));
59 #else
60 writeq(ep, BIUCFG_EP_LO(cpu));
61 #endif
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);
65 #endif
66
67 #if (!defined (PLATFORM_FLAVOR_6858) && !defined (PLATFORM_FLAVOR_6856))
68 #if defined(BOOT_LUT)
69 BOOT_LUT->bootLutRst = (u32)ep;
70 #endif
71
72 #if defined(BOOTLUT_BASE)
73 writel((u32)ep, (u32*)(BOOTLUT_BASE+0x20));
74 #endif
75 #endif
76 }
77
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)
84 {
85 return PSCI_E_SUCCESS;
86 }
87
88 /*******************************************************************************
89 * Platform handler called to check the validity of the non secure
90 * entrypoint.
91 ******************************************************************************/
92 static int brcm_validate_ns_entrypoint(uintptr_t entrypoint)
93 {
94 /*
95 * Check if the non secure entrypoint lies within the non
96 * secure DRAM.
97 */
98 return PSCI_E_SUCCESS;
99 }
100
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)
105 {
106
107 assert(cpu_state == PLAT_LOCAL_STATE_RET);
108
109 /*
110 * Enter standby state
111 * dsb is good practice before using wfi to enter low power states
112 */
113 dsb();
114 wfi();
115 }
116
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)
122 {
123 int rc = PSCI_E_SUCCESS;
124
125 /*
126 * here it is assumed that CFE didn't start the CPUs. Set the
127 * CPU entry point and power the CPU up.
128 */
129 #ifdef AARCH32
130 biu_set_cpu_ep(mpidr & 0xff, (long)sp_min_warm_entrypoint);
131 #else
132 biu_set_cpu_ep(mpidr & 0xff, (long)bl31_warm_entrypoint);
133 #endif
134 if (pmc_cpu_core_power_up(mpidr & 0xff) < 0)
135 rc = PSCI_E_INTERN_FAIL;
136 return rc;
137 }
138
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)
144 {
145 #if defined (PLATFORM_FLAVOR_63138)
146 assert(0);
147 #else
148 gicv2_cpuif_disable();
149 #endif
150 }
151
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)
157 {
158 assert(0);
159 }
160
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)
167 {
168 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
169 PLAT_LOCAL_STATE_OFF);
170
171 #if defined (PLATFORM_FLAVOR_63138)
172 a9_gic_secure_init();
173 #else
174 /* TODO: This setup is needed only after a cold boot */
175 gicv2_pcpu_distif_init();
176
177 /* Enable the gic cpu interface */
178 gicv2_cpuif_enable();
179 #endif
180 }
181
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)
188 {
189 assert(0);
190 }
191
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)
197 {
198 int idx = plat_my_core_pos();
199
200 pmc_cpu_core_power_down(idx);
201 psci_power_down_wfi();
202
203 panic();
204 }
205
206 /*******************************************************************************
207 * Platform handlers to shutdown/reboot the system
208 ******************************************************************************/
209 static void __dead2 brcm_system_off(void)
210 {
211 ERROR("BRCM System Off: operation not handled.\n");
212 panic();
213 }
214
215 static void __dead2 brcm_system_reset(void)
216 {
217 #if defined(WDTIMR0_BASE)
218 INFO("performing system reset from PSCI.\n");
219
220 #if defined(AARCH32) && ! defined(PLATFORM_FLAVOR_6846)
221 WDTIMER0->WDTimerCtl = SOFT_RESET;
222 #else
223 WDTIMER0->SoftRst = SOFT_RESET;
224 #endif
225 /*
226 * delay 1 second before assuming reset has failed.
227 */
228 udelay(1000 * 1000);
229 ERROR("watchdog system reset failed.");
230 panic();
231 #elif defined(TIMR_BASE)
232 ((volatile Timer * const) (TIMR_BASE + TIMR_OFFSET))->SoftRst |= SOFT_RESET;
233 #endif
234 while(1);
235 }
236
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
249 };
250
251 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
252 const plat_psci_ops_t **psci_ops)
253 {
254 #if defined(PLATFORM_FLAVOR_63138) || defined (PMB_ADDR_ORION_CPU0)
255 pmc_initmode();
256 #endif
257
258 *psci_ops = &plat_brcm_psci_pm_ops;
259
260 return 0;
261 }