blob: ede893ecbd9c40f98e96d65c83d0f4c33449b29b [file] [log] [blame]
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08007#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
9#include <arch_helpers.h>
10#include <common/debug.h>
11#include <drivers/arm/cci.h>
12#include <drivers/arm/gicv2.h>
13#include <drivers/arm/pl011.h>
14#include <drivers/delay_timer.h>
15#include <lib/mmio.h>
16#include <lib/psci/psci.h>
17
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080018#include <hi3660.h>
19#include <hi3660_crg.h>
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080020
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000021#include "drivers/pwrc/hisi_pwrc.h"
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080022#include "hikey960_def.h"
23#include "hikey960_private.h"
24
25#define CORE_PWR_STATE(state) \
26 ((state)->pwr_domain_state[MPIDR_AFFLVL0])
27#define CLUSTER_PWR_STATE(state) \
28 ((state)->pwr_domain_state[MPIDR_AFFLVL1])
29#define SYSTEM_PWR_STATE(state) \
30 ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
31
32#define DMAC_GLB_REG_SEC 0x694
33#define AXI_CONF_BASE 0x820
34
Haojian Zhuang6a009492018-02-17 12:06:18 +080035static unsigned int uart_base;
Jerome Forissier3fb19df2018-11-08 09:59:29 +010036static console_pl011_t console;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080037static uintptr_t hikey960_sec_entrypoint;
38
39static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
40{
41 unsigned long scr;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080042
43 scr = read_scr_el3();
44
Leo Yan3aeba232018-01-04 09:32:50 +080045 /* Enable Physical IRQ and FIQ to wake the CPU */
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080046 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
47
Leo Yan3aeba232018-01-04 09:32:50 +080048 /* Add barrier before CPU enter WFI state */
49 isb();
50 dsb();
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080051 wfi();
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080052
53 /*
54 * Restore SCR to the original value, synchronisazion of
55 * scr_el3 is done by eret while el3_exit to save some
56 * execution cycles.
57 */
58 write_scr_el3(scr);
59}
60
61static int hikey960_pwr_domain_on(u_register_t mpidr)
62{
63 unsigned int core = mpidr & MPIDR_CPU_MASK;
64 unsigned int cluster =
65 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
66 int cluster_stat = cluster_is_powered_on(cluster);
67
68 hisi_set_cpu_boot_flag(cluster, core);
69
70 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
71 hikey960_sec_entrypoint >> 2);
72
73 if (cluster_stat)
74 hisi_powerup_core(cluster, core);
75 else
76 hisi_powerup_cluster(cluster, core);
77
78 return PSCI_E_SUCCESS;
79}
80
81static void
82hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
83{
84 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
85 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
86
87 gicv2_pcpu_distif_init();
88 gicv2_cpuif_enable();
89}
90
91void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
92{
93 unsigned long mpidr = read_mpidr_el1();
94 unsigned int core = mpidr & MPIDR_CPU_MASK;
95 unsigned int cluster =
96 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
97
98 clr_ex();
99 isb();
100 dsbsy();
101
102 gicv2_cpuif_disable();
103
104 hisi_clear_cpu_boot_flag(cluster, core);
105 hisi_powerdn_core(cluster, core);
106
107 /* check if any core is powered up */
Leo Yanb1f0a372017-06-15 13:51:22 +0800108 if (hisi_test_cpu_down(cluster, core)) {
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800109
110 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
111
112 isb();
113 dsbsy();
114
115 hisi_powerdn_cluster(cluster, core);
116 }
117}
118
119static void __dead2 hikey960_system_reset(void)
120{
Haojian Zhuang01650282018-03-26 13:18:13 +0800121 dsb();
122 isb();
123 mdelay(2000);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800124 mmio_write_32(SCTRL_SCPEREN1_REG,
125 SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
126 mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
127 panic();
128}
129
130int hikey960_validate_power_state(unsigned int power_state,
131 psci_power_state_t *req_state)
132{
Leo Yan6829b702018-01-03 14:52:19 +0800133 unsigned int pstate = psci_get_pstate_type(power_state);
134 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800135 int i;
136
137 assert(req_state);
138
Leo Yan6829b702018-01-03 14:52:19 +0800139 if (pwr_lvl > PLAT_MAX_PWR_LVL)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800140 return PSCI_E_INVALID_PARAMS;
141
Leo Yan6829b702018-01-03 14:52:19 +0800142 /* Sanity check the requested state */
143 if (pstate == PSTATE_TYPE_STANDBY) {
144 /*
145 * It's possible to enter standby only on power level 0
146 * Ignore any other power level.
147 */
148 if (pwr_lvl != MPIDR_AFFLVL0)
149 return PSCI_E_INVALID_PARAMS;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800150
Leo Yan6829b702018-01-03 14:52:19 +0800151 req_state->pwr_domain_state[MPIDR_AFFLVL0] =
152 PLAT_MAX_RET_STATE;
153 } else {
154 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
155 req_state->pwr_domain_state[i] =
156 PLAT_MAX_OFF_STATE;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800157 }
158
Leo Yan6829b702018-01-03 14:52:19 +0800159 /*
160 * We expect the 'state id' to be zero.
161 */
162 if (psci_get_pstate_id(power_state))
163 return PSCI_E_INVALID_PARAMS;
164
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800165 return PSCI_E_SUCCESS;
166}
167
168static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
169{
170 /*
171 * Check if the non secure entrypoint lies within the non
172 * secure DRAM.
173 */
174 if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
175 return PSCI_E_SUCCESS;
176
177 return PSCI_E_INVALID_ADDRESS;
178}
179
180static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
181{
182 u_register_t mpidr = read_mpidr_el1();
183 unsigned int core = mpidr & MPIDR_CPU_MASK;
184 unsigned int cluster =
185 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
186
187 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
188 return;
189
190 if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
191 clr_ex();
192 isb();
193 dsbsy();
194
195 gicv2_cpuif_disable();
196
197 hisi_cpuidle_lock(cluster, core);
198 hisi_set_cpuidle_flag(cluster, core);
199 hisi_cpuidle_unlock(cluster, core);
200
201 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
202 hikey960_sec_entrypoint >> 2);
203
204 hisi_enter_core_idle(cluster, core);
205 }
206
207 /* Perform the common cluster specific operations */
208 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
209 hisi_cpuidle_lock(cluster, core);
210 hisi_disable_pdc(cluster);
211
212 /* check if any core is powered up */
213 if (hisi_test_pwrdn_allcores(cluster, core)) {
214
215 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
216
217 isb();
218 dsbsy();
219
220 /* mask the pdc wakeup irq, then
221 * enable pdc to power down the core
222 */
223 hisi_pdc_mask_cluster_wakeirq(cluster);
224 hisi_enable_pdc(cluster);
225
226 hisi_cpuidle_unlock(cluster, core);
227
228 /* check the SR flag bit to determine
229 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
230 */
Wei Yu633fc062019-04-07 11:29:28 +0800231 if (hisi_test_ap_suspend_flag())
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800232 hisi_enter_ap_suspend(cluster, core);
233 else
234 hisi_enter_cluster_idle(cluster, core);
235 } else {
236 /* enable pdc */
237 hisi_enable_pdc(cluster);
238 hisi_cpuidle_unlock(cluster, core);
239 }
240 }
241}
242
243static void hikey960_sr_dma_reinit(void)
244{
245 unsigned int ctr = 0;
246
247 mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
248
249 /* 1~15 channel is set non_secure */
250 for (ctr = 1; ctr <= 15; ctr++)
251 mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
252 (1 << 6) | (1 << 18));
253}
254
255static void
256hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
257{
258 unsigned long mpidr = read_mpidr_el1();
Tao Wang06b9d972017-08-03 17:34:09 +0800259 unsigned int core = mpidr & MPIDR_CPU_MASK;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800260 unsigned int cluster =
261 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
262
263 /* Nothing to be done on waking up from retention from CPU level */
264 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
265 return;
266
Tao Wang06b9d972017-08-03 17:34:09 +0800267 hisi_cpuidle_lock(cluster, core);
268 hisi_clear_cpuidle_flag(cluster, core);
269 hisi_cpuidle_unlock(cluster, core);
270
Wei Yu633fc062019-04-07 11:29:28 +0800271 if (hisi_test_ap_suspend_flag()) {
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800272 hikey960_sr_dma_reinit();
273 gicv2_cpuif_enable();
Jerome Forissier3fb19df2018-11-08 09:59:29 +0100274 console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,
275 PL011_BAUDRATE, &console);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800276 }
277
278 hikey960_pwr_domain_on_finish(target_state);
279}
280
281static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
282{
283 int i;
284
285 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
286 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
287}
288
289static const plat_psci_ops_t hikey960_psci_ops = {
290 .cpu_standby = hikey960_pwr_domain_standby,
291 .pwr_domain_on = hikey960_pwr_domain_on,
292 .pwr_domain_on_finish = hikey960_pwr_domain_on_finish,
293 .pwr_domain_off = hikey960_pwr_domain_off,
294 .pwr_domain_suspend = hikey960_pwr_domain_suspend,
295 .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish,
296 .system_off = NULL,
297 .system_reset = hikey960_system_reset,
298 .validate_power_state = hikey960_validate_power_state,
299 .validate_ns_entrypoint = hikey960_validate_ns_entrypoint,
300 .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state,
301};
302
303int plat_setup_psci_ops(uintptr_t sec_entrypoint,
304 const plat_psci_ops_t **psci_ops)
305{
Haojian Zhuang6a009492018-02-17 12:06:18 +0800306 unsigned int id = 0;
307 int ret;
308
309 ret = hikey960_read_boardid(&id);
310 if (ret == 0) {
311 if (id == 5300U)
312 uart_base = PL011_UART5_BASE;
313 else
314 uart_base = PL011_UART6_BASE;
315 } else {
316 uart_base = PL011_UART6_BASE;
317 }
318
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800319 hikey960_sec_entrypoint = sec_entrypoint;
320
321 INFO("%s: sec_entrypoint=0x%lx\n", __func__,
322 (unsigned long)hikey960_sec_entrypoint);
323
324 /*
325 * Initialize PSCI ops struct
326 */
327 *psci_ops = &hikey960_psci_ops;
328 return 0;
329}