diff options
-rw-r--r-- | plat/allwinner/common/sunxi_bl31_setup.c | 3 | ||||
-rw-r--r-- | plat/allwinner/common/sunxi_cpu_ops.c | 85 | ||||
-rw-r--r-- | plat/allwinner/common/sunxi_pm.c | 5 | ||||
-rw-r--r-- | plat/allwinner/common/sunxi_private.h | 3 | ||||
-rw-r--r-- | plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h | 36 | ||||
-rw-r--r-- | plat/allwinner/sun50i_a64/platform.mk | 1 |
6 files changed, 133 insertions, 0 deletions
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c index 63312381..22abafe9 100644 --- a/plat/allwinner/common/sunxi_bl31_setup.c +++ b/plat/allwinner/common/sunxi_bl31_setup.c @@ -44,6 +44,9 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + + /* Turn off all secondary CPUs */ + sunxi_disable_secondary_cpus(plat_my_core_pos()); } void bl31_plat_arch_setup(void) diff --git a/plat/allwinner/common/sunxi_cpu_ops.c b/plat/allwinner/common/sunxi_cpu_ops.c new file mode 100644 index 00000000..be72dee4 --- /dev/null +++ b/plat/allwinner/common/sunxi_cpu_ops.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <mmio.h> +#include <platform_def.h> +#include <sunxi_mmap.h> +#include <sunxi_cpucfg.h> +#include <utils_def.h> + +#include "sunxi_private.h" + +static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core) +{ + if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff) + return; + + INFO("PSCI: Disabling power to cluster %d core %d\n", cluster, core); + + mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xff); +} + +static void sunxi_cpu_enable_power(unsigned int cluster, unsigned int core) +{ + if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0) + return; + + INFO("PSCI: Enabling power to cluster %d core %d\n", cluster, core); + + /* Power enable sequence from original Allwinner sources */ + mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xfe); + mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xf8); + mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xe0); + mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x80); + mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00); +} + +void sunxi_cpu_off(unsigned int cluster, unsigned int core) +{ + INFO("PSCI: Powering off cluster %d core %d\n", cluster, core); + + /* Deassert DBGPWRDUP */ + mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core)); + /* Activate the core output clamps */ + mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core)); + /* Assert CPU power-on reset */ + mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core)); + /* Remove power from the CPU */ + sunxi_cpu_disable_power(cluster, core); +} + +void sunxi_cpu_on(unsigned int cluster, unsigned int core) +{ + INFO("PSCI: Powering on cluster %d core %d\n", cluster, core); + + /* Assert CPU core reset */ + mmio_clrbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core)); + /* Assert CPU power-on reset */ + mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core)); + /* Set CPU to start in AArch64 mode */ + mmio_setbits_32(SUNXI_CPUCFG_CLS_CTRL_REG0(cluster), BIT(24 + core)); + /* Apply power to the CPU */ + sunxi_cpu_enable_power(cluster, core); + /* Release the core output clamps */ + mmio_clrbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core)); + /* Deassert CPU power-on reset */ + mmio_setbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core)); + /* Deassert CPU core reset */ + mmio_setbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core)); + /* Assert DBGPWRDUP */ + mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core)); +} + +void sunxi_disable_secondary_cpus(unsigned int primary_cpu) +{ + for (unsigned int cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu += 1) { + if (cpu == primary_cpu) + continue; + sunxi_cpu_off(cpu / PLATFORM_MAX_CPUS_PER_CLUSTER, + cpu % PLATFORM_MAX_CPUS_PER_CLUSTER); + } +} diff --git a/plat/allwinner/common/sunxi_pm.c b/plat/allwinner/common/sunxi_pm.c index c73400e1..fb3842db 100644 --- a/plat/allwinner/common/sunxi_pm.c +++ b/plat/allwinner/common/sunxi_pm.c @@ -18,8 +18,13 @@ #define SUNXI_WDOG0_CFG_REG (SUNXI_WDOG_BASE + 0x0014) #define SUNXI_WDOG0_MODE_REG (SUNXI_WDOG_BASE + 0x0018) +#include "sunxi_private.h" + static void __dead2 sunxi_system_off(void) { + /* Turn off all secondary CPUs */ + sunxi_disable_secondary_cpus(plat_my_core_pos()); + ERROR("PSCI: Full shutdown not implemented, halting\n"); wfi(); panic(); diff --git a/plat/allwinner/common/sunxi_private.h b/plat/allwinner/common/sunxi_private.h index 34e5639d..bd923f40 100644 --- a/plat/allwinner/common/sunxi_private.h +++ b/plat/allwinner/common/sunxi_private.h @@ -8,5 +8,8 @@ #define __SUNXI_PRIVATE_H__ void sunxi_configure_mmu_el3(int flags); +void sunxi_cpu_off(unsigned int cluster, unsigned int core); +void sunxi_cpu_on(unsigned int cluster, unsigned int core); +void sunxi_disable_secondary_cpus(unsigned int primary_cpu); #endif /* __SUNXI_PRIVATE_H__ */ diff --git a/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h new file mode 100644 index 00000000..049c2ad2 --- /dev/null +++ b/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SUNXI_CPUCFG_H__ +#define __SUNXI_CPUCFG_H__ + +#include <sunxi_mmap.h> + +/* c = cluster, n = core */ +#define SUNXI_CPUCFG_CLS_CTRL_REG0(c) (SUNXI_CPUCFG_BASE + 0x0000 + (c) * 16) +#define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_CPUCFG_BASE + 0x0004 + (c) * 16) +#define SUNXI_CPUCFG_CACHE_CFG_REG0 (SUNXI_CPUCFG_BASE + 0x0008) +#define SUNXI_CPUCFG_CACHE_CFG_REG1 (SUNXI_CPUCFG_BASE + 0x000c) +#define SUNXI_CPUCFG_DBG_REG0 (SUNXI_CPUCFG_BASE + 0x0020) +#define SUNXI_CPUCFG_GLB_CTRL_REG (SUNXI_CPUCFG_BASE + 0x0028) +#define SUNXI_CPUCFG_CPU_STS_REG(c) (SUNXI_CPUCFG_BASE + 0x0030 + (c) * 4) +#define SUNXI_CPUCFG_L2_STS_REG (SUNXI_CPUCFG_BASE + 0x003c) +#define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_CPUCFG_BASE + 0x0080 + (c) * 4) +#define SUNXI_CPUCFG_RVBAR_LO_REG(n) (SUNXI_CPUCFG_BASE + 0x00a0 + (n) * 8) +#define SUNXI_CPUCFG_RVBAR_HI_REG(n) (SUNXI_CPUCFG_BASE + 0x00a4 + (n) * 8) + +#define SUNXI_CPU_POWER_CLAMP_REG(c, n) (SUNXI_R_PRCM_BASE + 0x0140 + \ + (c) * 16 + (n) * 4) +#define SUNXI_POWEROFF_GATING_REG(c) (SUNXI_R_PRCM_BASE + 0x0100 + (c) * 4) +#define SUNXI_R_CPUCFG_CPUS_RST_REG (SUNXI_R_CPUCFG_BASE + 0x0000) +#define SUNXI_POWERON_RST_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0030 + (c) * 4) +#define SUNXI_R_CPUCFG_SYS_RST_REG (SUNXI_R_CPUCFG_BASE + 0x0140) +#define SUNXI_R_CPUCFG_SS_FLAG_REG (SUNXI_R_CPUCFG_BASE + 0x01a0) +#define SUNXI_R_CPUCFG_CPU_ENTRY_REG (SUNXI_R_CPUCFG_BASE + 0x01a4) +#define SUNXI_R_CPUCFG_SS_ENTRY_REG (SUNXI_R_CPUCFG_BASE + 0x01a8) +#define SUNXI_R_CPUCFG_HP_FLAG_REG (SUNXI_R_CPUCFG_BASE + 0x01ac) + +#endif /* __SUNXI_CPUCFG_H__ */ diff --git a/plat/allwinner/sun50i_a64/platform.mk b/plat/allwinner/sun50i_a64/platform.mk index 074a64b4..49764e09 100644 --- a/plat/allwinner/sun50i_a64/platform.mk +++ b/plat/allwinner/sun50i_a64/platform.mk @@ -28,6 +28,7 @@ BL31_SOURCES += drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv2.c \ plat/common/plat_psci_common.c \ ${AW_PLAT}/common/sunxi_bl31_setup.c \ + ${AW_PLAT}/common/sunxi_cpu_ops.c \ ${AW_PLAT}/common/sunxi_pm.c \ ${AW_PLAT}/common/sunxi_topology.c |