blob: 257299e8094e12f676a1ffe8521a592daebfbcae [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>
12#include <gicv2.h>
13#include <hi3660.h>
14#include <hi3660_crg.h>
15#include <mmio.h>
16#include <psci.h>
17#include "drivers/pwrc/hisi_pwrc.h"
18
19#include "hikey960_def.h"
20#include "hikey960_private.h"
21
22#define CORE_PWR_STATE(state) \
23 ((state)->pwr_domain_state[MPIDR_AFFLVL0])
24#define CLUSTER_PWR_STATE(state) \
25 ((state)->pwr_domain_state[MPIDR_AFFLVL1])
26#define SYSTEM_PWR_STATE(state) \
27 ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
28
29#define DMAC_GLB_REG_SEC 0x694
30#define AXI_CONF_BASE 0x820
31
32static uintptr_t hikey960_sec_entrypoint;
33
34static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
35{
36 unsigned long scr;
37 unsigned int val = 0;
38
39 assert(cpu_state == PLAT_MAX_RET_STATE);
40
41 scr = read_scr_el3();
42
43 /* Enable Physical IRQ and FIQ to wake the CPU*/
44 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
45
46 set_retention_ticks(val);
47 wfi();
48 clr_retention_ticks(val);
49
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 */
105 if (hisi_test_pwrdn_allcores(cluster, core)) {
106
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{
118 mmio_write_32(SCTRL_SCPEREN1_REG,
119 SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
120 mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
121 panic();
122}
123
124int hikey960_validate_power_state(unsigned int power_state,
125 psci_power_state_t *req_state)
126{
127 int pstate = psci_get_pstate_type(power_state);
128 int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
129 int i;
130
131 assert(req_state);
132
133 if (pwr_lvl > PLAT_MAX_PWR_LVL)
134 return PSCI_E_INVALID_PARAMS;
135
136 /* Sanity check the requested state */
137 if (pstate == PSTATE_TYPE_STANDBY) {
138 /*
139 * It's possible to enter standby only on power level 0
140 * Ignore any other power level.
141 */
142 if (pwr_lvl != MPIDR_AFFLVL0)
143 return PSCI_E_INVALID_PARAMS;
144
145 req_state->pwr_domain_state[MPIDR_AFFLVL0] =
146 PLAT_MAX_RET_STATE;
147 } else {
148 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
149 req_state->pwr_domain_state[i] =
150 PLAT_MAX_OFF_STATE;
151 }
152
153 /*
154 * We expect the 'state id' to be zero.
155 */
156 if (psci_get_pstate_id(power_state))
157 return PSCI_E_INVALID_PARAMS;
158
159 return PSCI_E_SUCCESS;
160}
161
162static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
163{
164 /*
165 * Check if the non secure entrypoint lies within the non
166 * secure DRAM.
167 */
168 if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
169 return PSCI_E_SUCCESS;
170
171 return PSCI_E_INVALID_ADDRESS;
172}
173
174static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
175{
176 u_register_t mpidr = read_mpidr_el1();
177 unsigned int core = mpidr & MPIDR_CPU_MASK;
178 unsigned int cluster =
179 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
180
181 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
182 return;
183
184 if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
185 clr_ex();
186 isb();
187 dsbsy();
188
189 gicv2_cpuif_disable();
190
191 hisi_cpuidle_lock(cluster, core);
192 hisi_set_cpuidle_flag(cluster, core);
193 hisi_cpuidle_unlock(cluster, core);
194
195 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
196 hikey960_sec_entrypoint >> 2);
197
198 hisi_enter_core_idle(cluster, core);
199 }
200
201 /* Perform the common cluster specific operations */
202 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
203 hisi_cpuidle_lock(cluster, core);
204 hisi_disable_pdc(cluster);
205
206 /* check if any core is powered up */
207 if (hisi_test_pwrdn_allcores(cluster, core)) {
208
209 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
210
211 isb();
212 dsbsy();
213
214 /* mask the pdc wakeup irq, then
215 * enable pdc to power down the core
216 */
217 hisi_pdc_mask_cluster_wakeirq(cluster);
218 hisi_enable_pdc(cluster);
219
220 hisi_cpuidle_unlock(cluster, core);
221
222 /* check the SR flag bit to determine
223 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
224 */
225 if (hisi_test_ap_suspend_flag(cluster))
226 hisi_enter_ap_suspend(cluster, core);
227 else
228 hisi_enter_cluster_idle(cluster, core);
229 } else {
230 /* enable pdc */
231 hisi_enable_pdc(cluster);
232 hisi_cpuidle_unlock(cluster, core);
233 }
234 }
235}
236
237static void hikey960_sr_dma_reinit(void)
238{
239 unsigned int ctr = 0;
240
241 mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
242
243 /* 1~15 channel is set non_secure */
244 for (ctr = 1; ctr <= 15; ctr++)
245 mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
246 (1 << 6) | (1 << 18));
247}
248
249static void
250hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
251{
252 unsigned long mpidr = read_mpidr_el1();
253 unsigned int cluster =
254 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
255
256 /* Nothing to be done on waking up from retention from CPU level */
257 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
258 return;
259
260 if (hisi_test_ap_suspend_flag(cluster)) {
261 hikey960_sr_dma_reinit();
262 gicv2_cpuif_enable();
263 console_init(PL011_UART6_BASE, PL011_UART_CLK_IN_HZ,
264 PL011_BAUDRATE);
265 }
266
267 hikey960_pwr_domain_on_finish(target_state);
268}
269
270static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
271{
272 int i;
273
274 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
275 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
276}
277
278static const plat_psci_ops_t hikey960_psci_ops = {
279 .cpu_standby = hikey960_pwr_domain_standby,
280 .pwr_domain_on = hikey960_pwr_domain_on,
281 .pwr_domain_on_finish = hikey960_pwr_domain_on_finish,
282 .pwr_domain_off = hikey960_pwr_domain_off,
283 .pwr_domain_suspend = hikey960_pwr_domain_suspend,
284 .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish,
285 .system_off = NULL,
286 .system_reset = hikey960_system_reset,
287 .validate_power_state = hikey960_validate_power_state,
288 .validate_ns_entrypoint = hikey960_validate_ns_entrypoint,
289 .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state,
290};
291
292int plat_setup_psci_ops(uintptr_t sec_entrypoint,
293 const plat_psci_ops_t **psci_ops)
294{
295 hikey960_sec_entrypoint = sec_entrypoint;
296
297 INFO("%s: sec_entrypoint=0x%lx\n", __func__,
298 (unsigned long)hikey960_sec_entrypoint);
299
300 /*
301 * Initialize PSCI ops struct
302 */
303 *psci_ops = &hikey960_psci_ops;
304 return 0;
305}