blob: ffe7fcf87fcb59a8c98499f8baf0abd70cdea96e [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
7#include <arch_helpers.h>
8#include <assert.h>
9#include <cci.h>
10#include <console.h>
11#include <debug.h>
Haojian Zhuang01650282018-03-26 13:18:13 +080012#include <delay_timer.h>
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080013#include <gicv2.h>
14#include <hi3660.h>
15#include <hi3660_crg.h>
16#include <mmio.h>
17#include <psci.h>
18#include "drivers/pwrc/hisi_pwrc.h"
19
20#include "hikey960_def.h"
21#include "hikey960_private.h"
22
23#define CORE_PWR_STATE(state) \
24 ((state)->pwr_domain_state[MPIDR_AFFLVL0])
25#define CLUSTER_PWR_STATE(state) \
26 ((state)->pwr_domain_state[MPIDR_AFFLVL1])
27#define SYSTEM_PWR_STATE(state) \
28 ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
29
30#define DMAC_GLB_REG_SEC 0x694
31#define AXI_CONF_BASE 0x820
32
Haojian Zhuang6a009492018-02-17 12:06:18 +080033static unsigned int uart_base;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080034static uintptr_t hikey960_sec_entrypoint;
35
36static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
37{
38 unsigned long scr;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080039
40 scr = read_scr_el3();
41
Leo Yan3aeba232018-01-04 09:32:50 +080042 /* Enable Physical IRQ and FIQ to wake the CPU */
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080043 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
44
Leo Yan3aeba232018-01-04 09:32:50 +080045 /* Add barrier before CPU enter WFI state */
46 isb();
47 dsb();
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080048 wfi();
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080049
50 /*
51 * Restore SCR to the original value, synchronisazion of
52 * scr_el3 is done by eret while el3_exit to save some
53 * execution cycles.
54 */
55 write_scr_el3(scr);
56}
57
58static int hikey960_pwr_domain_on(u_register_t mpidr)
59{
60 unsigned int core = mpidr & MPIDR_CPU_MASK;
61 unsigned int cluster =
62 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
63 int cluster_stat = cluster_is_powered_on(cluster);
64
65 hisi_set_cpu_boot_flag(cluster, core);
66
67 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
68 hikey960_sec_entrypoint >> 2);
69
70 if (cluster_stat)
71 hisi_powerup_core(cluster, core);
72 else
73 hisi_powerup_cluster(cluster, core);
74
75 return PSCI_E_SUCCESS;
76}
77
78static void
79hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
80{
81 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
82 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
83
84 gicv2_pcpu_distif_init();
85 gicv2_cpuif_enable();
86}
87
88void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
89{
90 unsigned long mpidr = read_mpidr_el1();
91 unsigned int core = mpidr & MPIDR_CPU_MASK;
92 unsigned int cluster =
93 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
94
95 clr_ex();
96 isb();
97 dsbsy();
98
99 gicv2_cpuif_disable();
100
101 hisi_clear_cpu_boot_flag(cluster, core);
102 hisi_powerdn_core(cluster, core);
103
104 /* check if any core is powered up */
Leo Yanb1f0a372017-06-15 13:51:22 +0800105 if (hisi_test_cpu_down(cluster, core)) {
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800106
107 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
108
109 isb();
110 dsbsy();
111
112 hisi_powerdn_cluster(cluster, core);
113 }
114}
115
116static void __dead2 hikey960_system_reset(void)
117{
Haojian Zhuang01650282018-03-26 13:18:13 +0800118 dsb();
119 isb();
120 mdelay(2000);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800121 mmio_write_32(SCTRL_SCPEREN1_REG,
122 SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
123 mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
124 panic();
125}
126
127int hikey960_validate_power_state(unsigned int power_state,
128 psci_power_state_t *req_state)
129{
Leo Yan6829b702018-01-03 14:52:19 +0800130 unsigned int pstate = psci_get_pstate_type(power_state);
131 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800132 int i;
133
134 assert(req_state);
135
Leo Yan6829b702018-01-03 14:52:19 +0800136 if (pwr_lvl > PLAT_MAX_PWR_LVL)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800137 return PSCI_E_INVALID_PARAMS;
138
Leo Yan6829b702018-01-03 14:52:19 +0800139 /* Sanity check the requested state */
140 if (pstate == PSTATE_TYPE_STANDBY) {
141 /*
142 * It's possible to enter standby only on power level 0
143 * Ignore any other power level.
144 */
145 if (pwr_lvl != MPIDR_AFFLVL0)
146 return PSCI_E_INVALID_PARAMS;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800147
Leo Yan6829b702018-01-03 14:52:19 +0800148 req_state->pwr_domain_state[MPIDR_AFFLVL0] =
149 PLAT_MAX_RET_STATE;
150 } else {
151 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
152 req_state->pwr_domain_state[i] =
153 PLAT_MAX_OFF_STATE;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800154 }
155
Leo Yan6829b702018-01-03 14:52:19 +0800156 /*
157 * We expect the 'state id' to be zero.
158 */
159 if (psci_get_pstate_id(power_state))
160 return PSCI_E_INVALID_PARAMS;
161
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800162 return PSCI_E_SUCCESS;
163}
164
165static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
166{
167 /*
168 * Check if the non secure entrypoint lies within the non
169 * secure DRAM.
170 */
171 if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
172 return PSCI_E_SUCCESS;
173
174 return PSCI_E_INVALID_ADDRESS;
175}
176
177static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
178{
179 u_register_t mpidr = read_mpidr_el1();
180 unsigned int core = mpidr & MPIDR_CPU_MASK;
181 unsigned int cluster =
182 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
183
184 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
185 return;
186
187 if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
188 clr_ex();
189 isb();
190 dsbsy();
191
192 gicv2_cpuif_disable();
193
194 hisi_cpuidle_lock(cluster, core);
195 hisi_set_cpuidle_flag(cluster, core);
196 hisi_cpuidle_unlock(cluster, core);
197
198 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
199 hikey960_sec_entrypoint >> 2);
200
201 hisi_enter_core_idle(cluster, core);
202 }
203
204 /* Perform the common cluster specific operations */
205 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
206 hisi_cpuidle_lock(cluster, core);
207 hisi_disable_pdc(cluster);
208
209 /* check if any core is powered up */
210 if (hisi_test_pwrdn_allcores(cluster, core)) {
211
212 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
213
214 isb();
215 dsbsy();
216
217 /* mask the pdc wakeup irq, then
218 * enable pdc to power down the core
219 */
220 hisi_pdc_mask_cluster_wakeirq(cluster);
221 hisi_enable_pdc(cluster);
222
223 hisi_cpuidle_unlock(cluster, core);
224
225 /* check the SR flag bit to determine
226 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
227 */
228 if (hisi_test_ap_suspend_flag(cluster))
229 hisi_enter_ap_suspend(cluster, core);
230 else
231 hisi_enter_cluster_idle(cluster, core);
232 } else {
233 /* enable pdc */
234 hisi_enable_pdc(cluster);
235 hisi_cpuidle_unlock(cluster, core);
236 }
237 }
238}
239
240static void hikey960_sr_dma_reinit(void)
241{
242 unsigned int ctr = 0;
243
244 mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
245
246 /* 1~15 channel is set non_secure */
247 for (ctr = 1; ctr <= 15; ctr++)
248 mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
249 (1 << 6) | (1 << 18));
250}
251
252static void
253hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
254{
255 unsigned long mpidr = read_mpidr_el1();
Tao Wang06b9d972017-08-03 17:34:09 +0800256 unsigned int core = mpidr & MPIDR_CPU_MASK;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800257 unsigned int cluster =
258 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
259
260 /* Nothing to be done on waking up from retention from CPU level */
261 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
262 return;
263
Tao Wang06b9d972017-08-03 17:34:09 +0800264 hisi_cpuidle_lock(cluster, core);
265 hisi_clear_cpuidle_flag(cluster, core);
266 hisi_cpuidle_unlock(cluster, core);
267
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800268 if (hisi_test_ap_suspend_flag(cluster)) {
269 hikey960_sr_dma_reinit();
270 gicv2_cpuif_enable();
Haojian Zhuang6a009492018-02-17 12:06:18 +0800271 console_init(uart_base, PL011_UART_CLK_IN_HZ,
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800272 PL011_BAUDRATE);
273 }
274
275 hikey960_pwr_domain_on_finish(target_state);
276}
277
278static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
279{
280 int i;
281
282 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
283 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
284}
285
286static const plat_psci_ops_t hikey960_psci_ops = {
287 .cpu_standby = hikey960_pwr_domain_standby,
288 .pwr_domain_on = hikey960_pwr_domain_on,
289 .pwr_domain_on_finish = hikey960_pwr_domain_on_finish,
290 .pwr_domain_off = hikey960_pwr_domain_off,
291 .pwr_domain_suspend = hikey960_pwr_domain_suspend,
292 .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish,
293 .system_off = NULL,
294 .system_reset = hikey960_system_reset,
295 .validate_power_state = hikey960_validate_power_state,
296 .validate_ns_entrypoint = hikey960_validate_ns_entrypoint,
297 .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state,
298};
299
300int plat_setup_psci_ops(uintptr_t sec_entrypoint,
301 const plat_psci_ops_t **psci_ops)
302{
Haojian Zhuang6a009492018-02-17 12:06:18 +0800303 unsigned int id = 0;
304 int ret;
305
306 ret = hikey960_read_boardid(&id);
307 if (ret == 0) {
308 if (id == 5300U)
309 uart_base = PL011_UART5_BASE;
310 else
311 uart_base = PL011_UART6_BASE;
312 } else {
313 uart_base = PL011_UART6_BASE;
314 }
315
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800316 hikey960_sec_entrypoint = sec_entrypoint;
317
318 INFO("%s: sec_entrypoint=0x%lx\n", __func__,
319 (unsigned long)hikey960_sec_entrypoint);
320
321 /*
322 * Initialize PSCI ops struct
323 */
324 *psci_ops = &hikey960_psci_ops;
325 return 0;
326}