blob: 22963c4f52a8ef5a0bf4f3a43691056d5adb6387 [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
Haojian Zhuang6a009492018-02-17 12:06:18 +080032static unsigned int uart_base;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080033static uintptr_t hikey960_sec_entrypoint;
34
35static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
36{
37 unsigned long scr;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080038
39 scr = read_scr_el3();
40
Leo Yan3aeba232018-01-04 09:32:50 +080041 /* Enable Physical IRQ and FIQ to wake the CPU */
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080042 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
43
Leo Yan3aeba232018-01-04 09:32:50 +080044 /* Add barrier before CPU enter WFI state */
45 isb();
46 dsb();
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080047 wfi();
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080048
49 /*
50 * Restore SCR to the original value, synchronisazion of
51 * scr_el3 is done by eret while el3_exit to save some
52 * execution cycles.
53 */
54 write_scr_el3(scr);
55}
56
57static int hikey960_pwr_domain_on(u_register_t mpidr)
58{
59 unsigned int core = mpidr & MPIDR_CPU_MASK;
60 unsigned int cluster =
61 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
62 int cluster_stat = cluster_is_powered_on(cluster);
63
64 hisi_set_cpu_boot_flag(cluster, core);
65
66 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
67 hikey960_sec_entrypoint >> 2);
68
69 if (cluster_stat)
70 hisi_powerup_core(cluster, core);
71 else
72 hisi_powerup_cluster(cluster, core);
73
74 return PSCI_E_SUCCESS;
75}
76
77static void
78hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
79{
80 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
81 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
82
83 gicv2_pcpu_distif_init();
84 gicv2_cpuif_enable();
85}
86
87void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
88{
89 unsigned long mpidr = read_mpidr_el1();
90 unsigned int core = mpidr & MPIDR_CPU_MASK;
91 unsigned int cluster =
92 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
93
94 clr_ex();
95 isb();
96 dsbsy();
97
98 gicv2_cpuif_disable();
99
100 hisi_clear_cpu_boot_flag(cluster, core);
101 hisi_powerdn_core(cluster, core);
102
103 /* check if any core is powered up */
Leo Yanb1f0a372017-06-15 13:51:22 +0800104 if (hisi_test_cpu_down(cluster, core)) {
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800105
106 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
107
108 isb();
109 dsbsy();
110
111 hisi_powerdn_cluster(cluster, core);
112 }
113}
114
115static void __dead2 hikey960_system_reset(void)
116{
117 mmio_write_32(SCTRL_SCPEREN1_REG,
118 SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
119 mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
120 panic();
121}
122
123int hikey960_validate_power_state(unsigned int power_state,
124 psci_power_state_t *req_state)
125{
Leo Yan6829b702018-01-03 14:52:19 +0800126 unsigned int pstate = psci_get_pstate_type(power_state);
127 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800128 int i;
129
130 assert(req_state);
131
Leo Yan6829b702018-01-03 14:52:19 +0800132 if (pwr_lvl > PLAT_MAX_PWR_LVL)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800133 return PSCI_E_INVALID_PARAMS;
134
Leo Yan6829b702018-01-03 14:52:19 +0800135 /* Sanity check the requested state */
136 if (pstate == PSTATE_TYPE_STANDBY) {
137 /*
138 * It's possible to enter standby only on power level 0
139 * Ignore any other power level.
140 */
141 if (pwr_lvl != MPIDR_AFFLVL0)
142 return PSCI_E_INVALID_PARAMS;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800143
Leo Yan6829b702018-01-03 14:52:19 +0800144 req_state->pwr_domain_state[MPIDR_AFFLVL0] =
145 PLAT_MAX_RET_STATE;
146 } else {
147 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
148 req_state->pwr_domain_state[i] =
149 PLAT_MAX_OFF_STATE;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800150 }
151
Leo Yan6829b702018-01-03 14:52:19 +0800152 /*
153 * We expect the 'state id' to be zero.
154 */
155 if (psci_get_pstate_id(power_state))
156 return PSCI_E_INVALID_PARAMS;
157
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800158 return PSCI_E_SUCCESS;
159}
160
161static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
162{
163 /*
164 * Check if the non secure entrypoint lies within the non
165 * secure DRAM.
166 */
167 if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
168 return PSCI_E_SUCCESS;
169
170 return PSCI_E_INVALID_ADDRESS;
171}
172
173static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
174{
175 u_register_t mpidr = read_mpidr_el1();
176 unsigned int core = mpidr & MPIDR_CPU_MASK;
177 unsigned int cluster =
178 (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
179
180 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
181 return;
182
183 if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
184 clr_ex();
185 isb();
186 dsbsy();
187
188 gicv2_cpuif_disable();
189
190 hisi_cpuidle_lock(cluster, core);
191 hisi_set_cpuidle_flag(cluster, core);
192 hisi_cpuidle_unlock(cluster, core);
193
194 mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
195 hikey960_sec_entrypoint >> 2);
196
197 hisi_enter_core_idle(cluster, core);
198 }
199
200 /* Perform the common cluster specific operations */
201 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
202 hisi_cpuidle_lock(cluster, core);
203 hisi_disable_pdc(cluster);
204
205 /* check if any core is powered up */
206 if (hisi_test_pwrdn_allcores(cluster, core)) {
207
208 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
209
210 isb();
211 dsbsy();
212
213 /* mask the pdc wakeup irq, then
214 * enable pdc to power down the core
215 */
216 hisi_pdc_mask_cluster_wakeirq(cluster);
217 hisi_enable_pdc(cluster);
218
219 hisi_cpuidle_unlock(cluster, core);
220
221 /* check the SR flag bit to determine
222 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
223 */
224 if (hisi_test_ap_suspend_flag(cluster))
225 hisi_enter_ap_suspend(cluster, core);
226 else
227 hisi_enter_cluster_idle(cluster, core);
228 } else {
229 /* enable pdc */
230 hisi_enable_pdc(cluster);
231 hisi_cpuidle_unlock(cluster, core);
232 }
233 }
234}
235
236static void hikey960_sr_dma_reinit(void)
237{
238 unsigned int ctr = 0;
239
240 mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
241
242 /* 1~15 channel is set non_secure */
243 for (ctr = 1; ctr <= 15; ctr++)
244 mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
245 (1 << 6) | (1 << 18));
246}
247
248static void
249hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
250{
251 unsigned long mpidr = read_mpidr_el1();
Tao Wang06b9d972017-08-03 17:34:09 +0800252 unsigned int core = mpidr & MPIDR_CPU_MASK;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800253 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
Tao Wang06b9d972017-08-03 17:34:09 +0800260 hisi_cpuidle_lock(cluster, core);
261 hisi_clear_cpuidle_flag(cluster, core);
262 hisi_cpuidle_unlock(cluster, core);
263
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800264 if (hisi_test_ap_suspend_flag(cluster)) {
265 hikey960_sr_dma_reinit();
266 gicv2_cpuif_enable();
Haojian Zhuang6a009492018-02-17 12:06:18 +0800267 console_init(uart_base, PL011_UART_CLK_IN_HZ,
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800268 PL011_BAUDRATE);
269 }
270
271 hikey960_pwr_domain_on_finish(target_state);
272}
273
274static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
275{
276 int i;
277
278 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
279 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
280}
281
282static const plat_psci_ops_t hikey960_psci_ops = {
283 .cpu_standby = hikey960_pwr_domain_standby,
284 .pwr_domain_on = hikey960_pwr_domain_on,
285 .pwr_domain_on_finish = hikey960_pwr_domain_on_finish,
286 .pwr_domain_off = hikey960_pwr_domain_off,
287 .pwr_domain_suspend = hikey960_pwr_domain_suspend,
288 .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish,
289 .system_off = NULL,
290 .system_reset = hikey960_system_reset,
291 .validate_power_state = hikey960_validate_power_state,
292 .validate_ns_entrypoint = hikey960_validate_ns_entrypoint,
293 .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state,
294};
295
296int plat_setup_psci_ops(uintptr_t sec_entrypoint,
297 const plat_psci_ops_t **psci_ops)
298{
Haojian Zhuang6a009492018-02-17 12:06:18 +0800299 unsigned int id = 0;
300 int ret;
301
302 ret = hikey960_read_boardid(&id);
303 if (ret == 0) {
304 if (id == 5300U)
305 uart_base = PL011_UART5_BASE;
306 else
307 uart_base = PL011_UART6_BASE;
308 } else {
309 uart_base = PL011_UART6_BASE;
310 }
311
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800312 hikey960_sec_entrypoint = sec_entrypoint;
313
314 INFO("%s: sec_entrypoint=0x%lx\n", __func__,
315 (unsigned long)hikey960_sec_entrypoint);
316
317 /*
318 * Initialize PSCI ops struct
319 */
320 *psci_ops = &hikey960_psci_ops;
321 return 0;
322}