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