2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
9 #include <platform_def.h>
11 #include <arch_helpers.h>
12 #include <common/debug.h>
13 #include <drivers/arm/gicv2.h>
14 #include <drivers/delay_timer.h>
16 #include <lib/psci/psci.h>
17 #include <plat/common/platform.h>
19 #include <sunxi_cpucfg.h>
20 #include <sunxi_mmap.h>
21 #include <sunxi_private.h>
23 #define SUNXI_WDOG0_CTRL_REG (SUNXI_WDOG_BASE + 0x0010)
24 #define SUNXI_WDOG0_CFG_REG (SUNXI_WDOG_BASE + 0x0014)
25 #define SUNXI_WDOG0_MODE_REG (SUNXI_WDOG_BASE + 0x0018)
27 #define mpidr_is_valid(mpidr) ( \
28 MPIDR_AFFLVL3_VAL(mpidr) == 0 && \
29 MPIDR_AFFLVL2_VAL(mpidr) == 0 && \
30 MPIDR_AFFLVL1_VAL(mpidr) < PLATFORM_CLUSTER_COUNT && \
31 MPIDR_AFFLVL0_VAL(mpidr) < PLATFORM_MAX_CPUS_PER_CLUSTER)
33 static int sunxi_pwr_domain_on(u_register_t mpidr
)
35 if (mpidr_is_valid(mpidr
) == 0)
36 return PSCI_E_INTERN_FAIL
;
38 sunxi_cpu_on(MPIDR_AFFLVL1_VAL(mpidr
), MPIDR_AFFLVL0_VAL(mpidr
));
40 return PSCI_E_SUCCESS
;
43 static void sunxi_pwr_domain_off(const psci_power_state_t
*target_state
)
45 gicv2_cpuif_disable();
48 static void __dead2
sunxi_pwr_down_wfi(const psci_power_state_t
*target_state
)
50 u_register_t mpidr
= read_mpidr();
52 sunxi_cpu_off(MPIDR_AFFLVL1_VAL(mpidr
), MPIDR_AFFLVL0_VAL(mpidr
));
58 static void sunxi_pwr_domain_on_finish(const psci_power_state_t
*target_state
)
60 gicv2_pcpu_distif_init();
64 static void __dead2
sunxi_system_off(void)
66 /* Turn off all secondary CPUs */
67 sunxi_disable_secondary_cpus(plat_my_core_pos());
72 static void __dead2
sunxi_system_reset(void)
74 /* Reset the whole system when the watchdog times out */
75 mmio_write_32(SUNXI_WDOG0_CFG_REG
, 1);
76 /* Enable the watchdog with the shortest timeout (0.5 seconds) */
77 mmio_write_32(SUNXI_WDOG0_MODE_REG
, (0 << 4) | 1);
78 /* Wait for twice the watchdog timeout before panicking */
81 ERROR("PSCI: System reset failed\n");
86 static int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint
)
88 /* The non-secure entry point must be in DRAM */
89 if (ns_entrypoint
>= SUNXI_DRAM_BASE
)
90 return PSCI_E_SUCCESS
;
92 return PSCI_E_INVALID_ADDRESS
;
95 static plat_psci_ops_t sunxi_psci_ops
= {
96 .pwr_domain_on
= sunxi_pwr_domain_on
,
97 .pwr_domain_off
= sunxi_pwr_domain_off
,
98 .pwr_domain_pwr_down_wfi
= sunxi_pwr_down_wfi
,
99 .pwr_domain_on_finish
= sunxi_pwr_domain_on_finish
,
100 .system_off
= sunxi_system_off
,
101 .system_reset
= sunxi_system_reset
,
102 .validate_ns_entrypoint
= sunxi_validate_ns_entrypoint
,
105 int plat_setup_psci_ops(uintptr_t sec_entrypoint
,
106 const plat_psci_ops_t
**psci_ops
)
110 for (int cpu
= 0; cpu
< PLATFORM_CORE_COUNT
; cpu
+= 1) {
111 mmio_write_32(SUNXI_CPUCFG_RVBAR_LO_REG(cpu
),
112 sec_entrypoint
& 0xffffffff);
113 mmio_write_32(SUNXI_CPUCFG_RVBAR_HI_REG(cpu
),
114 sec_entrypoint
>> 32);
117 *psci_ops
= &sunxi_psci_ops
;