arm-trusted-firmware-sunxi: add Allwinner A523 support

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2026-05-07 09:47:36 +08:00
parent a086361471
commit dd27afa631
9 changed files with 1495 additions and 0 deletions
@@ -26,6 +26,11 @@ define Trusted-Firmware-A/Default
BUILD_SUBTARGET:=cortexa53
endef
define Trusted-Firmware-A/sunxi-a523
NAME:=Allwinner A523
PLAT:=sun55i_a523
endef
define Trusted-Firmware-A/sunxi-a64
NAME:=Allwinner A64
PLAT:=sun50i_a64
@@ -42,6 +47,7 @@ define Trusted-Firmware-A/sunxi-h616
endef
TFA_TARGETS:= \
sunxi-a523 \
sunxi-a64 \
sunxi-h6 \
sunxi-h616
@@ -0,0 +1,126 @@
From 653b8680b2af40c8cde66b56134bd8a2be4f610a Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 12 Jan 2025 21:33:53 +0100
Subject: [PATCH] refactor(allwinner): split cortex-a53 and gicv2 config
Till now all Allwinner 64-bit SoC were Cortex-A53 and used GICv2. In
preparation for newer cores with newer GIC split out those settings to
separate mk file.
Change-Id: Ic5e2bd5034c87bc7fe1f64e1867a369fe700848c
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
plat/allwinner/common/allwinner-common-a53.mk | 20 +++++++++++++++++++
plat/allwinner/common/allwinner-common.mk | 13 ------------
plat/allwinner/sun50i_a64/platform.mk | 1 +
plat/allwinner/sun50i_h6/platform.mk | 1 +
plat/allwinner/sun50i_h616/platform.mk | 1 +
plat/allwinner/sun50i_r329/platform.mk | 1 +
6 files changed, 24 insertions(+), 13 deletions(-)
create mode 100644 plat/allwinner/common/allwinner-common-a53.mk
--- /dev/null
+++ b/plat/allwinner/common/allwinner-common-a53.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+
+BL31_SOURCES += ${GICV2_SOURCES} \
+ lib/cpus/${ARCH}/cortex_a53.S \
+ plat/common/plat_gicv2.c
+
+# Enable workarounds for Cortex-A53 errata. Allwinner uses at least r0p4.
+ERRATA_A53_835769 := 1
+ERRATA_A53_843419 := 1
+ERRATA_A53_855873 := 1
+ERRATA_A53_1530924 := 1
+
+# This platform is single-cluster and does not require coherency setup.
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -6,7 +6,6 @@
include lib/xlat_tables_v2/xlat_tables.mk
include lib/libfdt/libfdt.mk
-include drivers/arm/gic/v2/gicv2.mk
AW_PLAT := plat/allwinner
@@ -20,11 +19,8 @@ PLAT_BL_COMMON_SOURCES := drivers/ti/uar
${AW_PLAT}/common/sunxi_common.c
BL31_SOURCES += drivers/allwinner/axp/common.c \
- ${GICV2_SOURCES} \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
- lib/cpus/${ARCH}/cortex_a53.S \
- plat/common/plat_gicv2.c \
plat/common/plat_psci_common.c \
${AW_PLAT}/common/sunxi_bl31_setup.c \
${AW_PLAT}/${PLAT}/sunxi_idle_states.c \
@@ -97,12 +93,6 @@ WORKAROUND_CVE_2022_23960 := 0
WORKAROUND_CVE_2024_7881 := 0
WORKAROUND_CVE_2024_5660 := 0
-# Enable workarounds for Cortex-A53 errata. Allwinner uses at least r0p4.
-ERRATA_A53_835769 := 1
-ERRATA_A53_843419 := 1
-ERRATA_A53_855873 := 1
-ERRATA_A53_1530924 := 1
-
# The traditional U-Boot load address is 160MB into DRAM.
PRELOADED_BL33_BASE ?= 0x4a000000
@@ -114,6 +104,3 @@ SEPARATE_CODE_AND_RODATA := 1
# BL31 gets loaded alongside BL33 (U-Boot) by U-Boot's SPL
RESET_TO_BL31 := 1
-
-# This platform is single-cluster and does not require coherency setup.
-WARMBOOT_ENABLE_DCACHE_EARLY := 1
--- a/plat/allwinner/sun50i_a64/platform.mk
+++ b/plat/allwinner/sun50i_a64/platform.mk
@@ -10,6 +10,7 @@ SUNXI_AMEND_DTB := 1
# The differences between the platform are covered by the include files.
include plat/allwinner/common/allwinner-common.mk
+include plat/allwinner/common/allwinner-common-a53.mk
BL31_SOURCES += drivers/allwinner/axp/axp803.c \
drivers/allwinner/sunxi_rsb.c
--- a/plat/allwinner/sun50i_h6/platform.mk
+++ b/plat/allwinner/sun50i_h6/platform.mk
@@ -6,6 +6,7 @@
# The differences between the platform are covered by the include files.
include plat/allwinner/common/allwinner-common.mk
+include plat/allwinner/common/allwinner-common-a53.mk
BL31_SOURCES += drivers/allwinner/axp/axp805.c \
drivers/allwinner/sunxi_rsb.c
--- a/plat/allwinner/sun50i_h616/platform.mk
+++ b/plat/allwinner/sun50i_h616/platform.mk
@@ -12,6 +12,7 @@ SUNXI_PSCI_USE_NATIVE := 1
# The differences between the platforms are covered by the include files.
include plat/allwinner/common/allwinner-common.mk
+include plat/allwinner/common/allwinner-common-a53.mk
# the above could be overwritten on the command line
ifeq (${SUNXI_PSCI_USE_SCPI}, 1)
--- a/plat/allwinner/sun50i_r329/platform.mk
+++ b/plat/allwinner/sun50i_r329/platform.mk
@@ -10,6 +10,7 @@ SUNXI_PSCI_USE_NATIVE := 1
# The differences between the platforms are covered by the include files.
include plat/allwinner/common/allwinner-common.mk
+include plat/allwinner/common/allwinner-common-a53.mk
# the above could be overwritten on the command line
ifeq (${SUNXI_PSCI_USE_SCPI}, 1)
@@ -0,0 +1,28 @@
From 3dfc3c078fc5525f3a30332aeb685d055b736385 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Mon, 27 Oct 2025 20:18:59 +0100
Subject: [PATCH] feat(gicv2): Make IRQ groups optional
Not all platforms define Group 0 interrupts. Make G0 and G1S groups
optional so such platforms can use generic driver.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/arm/gic/v2/gicv2_base.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/arm/gic/v2/gicv2_base.c
+++ b/drivers/arm/gic/v2/gicv2_base.c
@@ -20,8 +20,12 @@
* interrupts.
*****************************************************************************/
static const interrupt_prop_t arm_interrupt_props[] = {
+#ifdef PLAT_ARM_G1S_IRQ_PROPS
PLAT_ARM_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+#endif
+#ifdef PLAT_ARM_G0_IRQ_PROPS
PLAT_ARM_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+#endif
};
static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
@@ -0,0 +1,212 @@
From 4f788f7dd4d3582d6a754af33b85696980363284 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Mon, 27 Oct 2025 20:22:36 +0100
Subject: [PATCH] refactor(allwinner): use generic GIC driver
Using generic GIC driver simplifies code a lot and also allows us to
introduce GICv3 platform more easily later.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
plat/allwinner/common/allwinner-common-a53.mk | 7 ++--
plat/allwinner/common/include/platform_def.h | 3 ++
plat/allwinner/common/sunxi_bl31_setup.c | 12 ------
plat/allwinner/common/sunxi_native_pm.c | 9 ----
plat/allwinner/common/sunxi_scpi_pm.c | 41 ++++++++++---------
5 files changed, 28 insertions(+), 44 deletions(-)
--- a/plat/allwinner/common/allwinner-common-a53.mk
+++ b/plat/allwinner/common/allwinner-common-a53.mk
@@ -4,11 +4,10 @@
# SPDX-License-Identifier: BSD-3-Clause
#
-include drivers/arm/gic/v2/gicv2.mk
+BL31_SOURCES += lib/cpus/${ARCH}/cortex_a53.S
-BL31_SOURCES += ${GICV2_SOURCES} \
- lib/cpus/${ARCH}/cortex_a53.S \
- plat/common/plat_gicv2.c
+# A53 cores use GICv2
+USE_GIC_DRIVER := 2
# Enable workarounds for Cortex-A53 errata. Allwinner uses at least r0p4.
ERRATA_A53_835769 := 1
--- a/plat/allwinner/common/include/platform_def.h
+++ b/plat/allwinner/common/include/platform_def.h
@@ -81,4 +81,7 @@
#endif
#endif
+#define PLAT_ARM_GICD_BASE SUNXI_GICD_BASE
+#define PLAT_ARM_GICC_BASE SUNXI_GICC_BASE
+
#endif /* PLATFORM_DEF_H */
--- a/plat/allwinner/common/sunxi_bl31_setup.c
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -14,7 +14,6 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/fdt_fixup.h>
-#include <drivers/arm/gicv2.h>
#include <drivers/console.h>
#include <drivers/generic_delay_timer.h>
#include <drivers/ti/uart/uart_16550.h>
@@ -33,11 +32,6 @@ static console_t console;
static void *fdt;
-static const gicv2_driver_data_t sunxi_gic_data = {
- .gicd_base = SUNXI_GICD_BASE,
- .gicc_base = SUNXI_GICC_BASE,
-};
-
/*
* Try to find a DTB loaded in memory by previous stages.
*
@@ -149,12 +143,6 @@ void bl31_platform_setup(void)
NOTICE("BL31: No DTB found.\n");
}
- /* Configure the interrupt controller */
- gicv2_driver_init(&sunxi_gic_data);
- gicv2_distif_init();
- gicv2_pcpu_distif_init();
- gicv2_cpuif_enable();
-
sunxi_security_setup();
/*
--- a/plat/allwinner/common/sunxi_native_pm.c
+++ b/plat/allwinner/common/sunxi_native_pm.c
@@ -6,7 +6,6 @@
#include <arch_helpers.h>
#include <common/debug.h>
-#include <drivers/arm/gicv2.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
@@ -27,21 +26,15 @@ static int sunxi_pwr_domain_on(u_registe
static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
{
- gicv2_cpuif_disable();
-
sunxi_cpu_power_off_self();
}
static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
- gicv2_pcpu_distif_init();
- gicv2_cpuif_enable();
}
static void sunxi_system_off(void)
{
- gicv2_cpuif_disable();
-
/* Attempt to power down the board (may not return) */
sunxi_power_down();
@@ -52,8 +45,6 @@ static void sunxi_system_off(void)
static void __dead2 sunxi_system_reset(void)
{
- gicv2_cpuif_disable();
-
/* Reset the whole system when the watchdog times out */
mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
/* Enable the watchdog with the shortest timeout (0.5 seconds) */
--- a/plat/allwinner/common/sunxi_scpi_pm.c
+++ b/plat/allwinner/common/sunxi_scpi_pm.c
@@ -11,7 +11,7 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/css/css_scpi.h>
-#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gic.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
@@ -74,9 +74,19 @@ static void sunxi_pwr_domain_off(const p
plat_local_state_t cluster_pwr_state = CLUSTER_PWR_STATE(target_state);
plat_local_state_t system_pwr_state = SYSTEM_PWR_STATE(target_state);
- if (is_local_state_off(cpu_pwr_state)) {
- gicv2_cpuif_disable();
- }
+ scpi_set_css_power_state(read_mpidr(),
+ cpu_pwr_state,
+ cluster_pwr_state,
+ system_pwr_state);
+}
+
+static void sunxi_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ plat_local_state_t cpu_pwr_state = CPU_PWR_STATE(target_state);
+ plat_local_state_t cluster_pwr_state = CLUSTER_PWR_STATE(target_state);
+ plat_local_state_t system_pwr_state = SYSTEM_PWR_STATE(target_state);
+
+ gic_save();
scpi_set_css_power_state(read_mpidr(),
cpu_pwr_state,
@@ -86,21 +96,18 @@ static void sunxi_pwr_domain_off(const p
static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
- if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
- gicv2_distif_init();
- }
- if (is_local_state_off(CPU_PWR_STATE(target_state))) {
- gicv2_pcpu_distif_init();
- gicv2_cpuif_enable();
- }
+
+}
+
+static void sunxi_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ gic_resume();
}
static void sunxi_system_off(void)
{
uint32_t ret;
- gicv2_cpuif_disable();
-
/* Send the power down request to the SCP. */
ret = scpi_sys_power_state(scpi_system_shutdown);
if (ret != SCP_OK) {
@@ -112,8 +119,6 @@ static void sunxi_system_reset(void)
{
uint32_t ret;
- gicv2_cpuif_disable();
-
/* Send the system reset request to the SCP. */
ret = scpi_sys_power_state(scpi_system_reboot);
if (ret != SCP_OK) {
@@ -128,8 +133,6 @@ static int sunxi_system_reset2(int is_ve
if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET))
return PSCI_E_NOT_SUPPORTED;
- gicv2_cpuif_disable();
-
/* Send the system reset request to the SCP. */
ret = scpi_sys_power_state(scpi_system_reset);
if (ret != SCP_OK) {
@@ -190,9 +193,9 @@ static const plat_psci_ops_t sunxi_scpi_
.cpu_standby = sunxi_cpu_standby,
.pwr_domain_on = sunxi_pwr_domain_on,
.pwr_domain_off = sunxi_pwr_domain_off,
- .pwr_domain_suspend = sunxi_pwr_domain_off,
+ .pwr_domain_suspend = sunxi_pwr_domain_suspend,
.pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
- .pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish,
+ .pwr_domain_suspend_finish = sunxi_pwr_domain_suspend_finish,
.system_off = sunxi_system_off,
.system_reset = sunxi_system_reset,
.system_reset2 = sunxi_system_reset2,
@@ -0,0 +1,505 @@
From a36c863db5fbbfb85cb509ce23955fbad29e5a63 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Mon, 27 Oct 2025 20:34:52 +0100
Subject: [PATCH] refactor(allwinner): Make native PM A53 specific
Native PM callbacks are tailored to A53 based SoCs. With new A55
platform, concept is slightly changed.
Mark current native PM as A53 specific. Later, A55 specific variant will
be added.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
plat/allwinner/common/allwinner-common-a53.mk | 5 +++++
plat/allwinner/common/allwinner-common.mk | 5 -----
.../common/{sunxi_cpu_ops.c => sunxi_cpu_ops_a53.c} | 0
.../common/{sunxi_native_pm.c => sunxi_native_pm_a53.c} | 0
4 files changed, 5 insertions(+), 5 deletions(-)
rename plat/allwinner/common/{sunxi_cpu_ops.c => sunxi_cpu_ops_a53.c} (100%)
rename plat/allwinner/common/{sunxi_native_pm.c => sunxi_native_pm_a53.c} (100%)
--- a/plat/allwinner/common/allwinner-common-a53.mk
+++ b/plat/allwinner/common/allwinner-common-a53.mk
@@ -6,6 +6,11 @@
BL31_SOURCES += lib/cpus/${ARCH}/cortex_a53.S
+ifeq (${SUNXI_PSCI_USE_NATIVE},1)
+BL31_SOURCES += ${AW_PLAT}/common/sunxi_cpu_ops_a53.c \
+ ${AW_PLAT}/common/sunxi_native_pm_a53.c
+endif
+
# A53 cores use GICv2
USE_GIC_DRIVER := 2
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -47,11 +47,6 @@ ifeq (${SUNXI_PSCI_USE_NATIVE}${SUNXI_PS
$(error "At least one of SCPI or native PSCI ops must be enabled")
endif
-ifeq (${SUNXI_PSCI_USE_NATIVE},1)
-BL31_SOURCES += ${AW_PLAT}/common/sunxi_cpu_ops.c \
- ${AW_PLAT}/common/sunxi_native_pm.c
-endif
-
ifeq (${SUNXI_PSCI_USE_SCPI},1)
BL31_SOURCES += drivers/allwinner/sunxi_msgbox.c \
drivers/arm/css/scpi/css_scpi.c \
--- a/plat/allwinner/common/sunxi_cpu_ops.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-
-#include <platform_def.h>
-
-#include <arch_helpers.h>
-#include <common/debug.h>
-#include <drivers/delay_timer.h>
-#include <lib/mmio.h>
-#include <lib/utils_def.h>
-#include <plat/common/platform.h>
-
-#include <sunxi_cpucfg.h>
-#include <sunxi_mmap.h>
-#include <sunxi_private.h>
-
-#ifndef SUNXI_C0_CPU_CTRL_REG
-#define SUNXI_C0_CPU_CTRL_REG(n) 0
-#define SUNXI_CPU_UNK_REG(n) 0
-#define SUNXI_CPU_CTRL_REG(n) 0
-#endif
-
-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;
-
- VERBOSE("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;
-
- VERBOSE("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);
- udelay(1);
-}
-
-/* We can't turn ourself off like this, but it works for other cores. */
-static void sunxi_cpu_off(u_register_t mpidr)
-{
- unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
- unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
-
- VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core);
-
- if (sunxi_cpucfg_has_per_cluster_regs()) {
- /* Deassert DBGPWRDUP */
- mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
- /* Activate the core output clamps, but not for core 0. */
- if (core != 0) {
- 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);
- } else {
- /* power down(?) debug core */
- mmio_clrbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(8));
- /* ??? Activate the core output clamps, but not for core 0 */
- if (core != 0) {
- mmio_setbits_32(SUNXI_CPU_UNK_REG(core), BIT(1));
- }
- /* ??? Assert CPU power-on reset ??? */
- mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
- /* Remove power from the CPU */
- sunxi_cpu_disable_power(cluster, core);
- }
-}
-
-void sunxi_cpu_on(u_register_t mpidr)
-{
- unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
- unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
-
- VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core);
-
- if (sunxi_cpucfg_has_per_cluster_regs()) {
- /* 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_AA64nAA32_REG(cluster),
- BIT(SUNXI_AA64nAA32_OFFSET + 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));
- } else {
- /* Assert CPU core reset */
- mmio_clrbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(0));
- /* ??? Assert CPU power-on reset ??? */
- mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
-
- /* Set CPU to start in AArch64 mode */
- mmio_setbits_32(SUNXI_CPU_CTRL_REG(core), BIT(0));
-
- /* Apply power to the CPU */
- sunxi_cpu_enable_power(cluster, core);
-
- /* ??? Release the core output clamps ??? */
- mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(1));
- /* ??? Deassert CPU power-on reset ??? */
- mmio_setbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
- /* Deassert CPU core reset */
- mmio_setbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(0));
- /* power up(?) debug core */
- mmio_setbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(8));
- }
-}
-
-void sunxi_cpu_power_off_others(void)
-{
- u_register_t self = read_mpidr();
- unsigned int cluster;
- unsigned int core;
-
- for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
- for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
- u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
- (core << MPIDR_AFF0_SHIFT) |
- BIT(31);
- if (mpidr != self)
- sunxi_cpu_off(mpidr);
- }
- }
-}
--- /dev/null
+++ b/plat/allwinner/common/sunxi_cpu_ops_a53.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <sunxi_cpucfg.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#ifndef SUNXI_C0_CPU_CTRL_REG
+#define SUNXI_C0_CPU_CTRL_REG(n) 0
+#define SUNXI_CPU_UNK_REG(n) 0
+#define SUNXI_CPU_CTRL_REG(n) 0
+#endif
+
+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;
+
+ VERBOSE("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;
+
+ VERBOSE("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);
+ udelay(1);
+}
+
+/* We can't turn ourself off like this, but it works for other cores. */
+static void sunxi_cpu_off(u_register_t mpidr)
+{
+ unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+ VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core);
+
+ if (sunxi_cpucfg_has_per_cluster_regs()) {
+ /* Deassert DBGPWRDUP */
+ mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
+ /* Activate the core output clamps, but not for core 0. */
+ if (core != 0) {
+ 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);
+ } else {
+ /* power down(?) debug core */
+ mmio_clrbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(8));
+ /* ??? Activate the core output clamps, but not for core 0 */
+ if (core != 0) {
+ mmio_setbits_32(SUNXI_CPU_UNK_REG(core), BIT(1));
+ }
+ /* ??? Assert CPU power-on reset ??? */
+ mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
+ /* Remove power from the CPU */
+ sunxi_cpu_disable_power(cluster, core);
+ }
+}
+
+void sunxi_cpu_on(u_register_t mpidr)
+{
+ unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+ VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core);
+
+ if (sunxi_cpucfg_has_per_cluster_regs()) {
+ /* 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_AA64nAA32_REG(cluster),
+ BIT(SUNXI_AA64nAA32_OFFSET + 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));
+ } else {
+ /* Assert CPU core reset */
+ mmio_clrbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(0));
+ /* ??? Assert CPU power-on reset ??? */
+ mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
+
+ /* Set CPU to start in AArch64 mode */
+ mmio_setbits_32(SUNXI_CPU_CTRL_REG(core), BIT(0));
+
+ /* Apply power to the CPU */
+ sunxi_cpu_enable_power(cluster, core);
+
+ /* ??? Release the core output clamps ??? */
+ mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(1));
+ /* ??? Deassert CPU power-on reset ??? */
+ mmio_setbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
+ /* Deassert CPU core reset */
+ mmio_setbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(0));
+ /* power up(?) debug core */
+ mmio_setbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(8));
+ }
+}
+
+void sunxi_cpu_power_off_others(void)
+{
+ u_register_t self = read_mpidr();
+ unsigned int cluster;
+ unsigned int core;
+
+ for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
+ for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
+ u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
+ (core << MPIDR_AFF0_SHIFT) |
+ BIT(31);
+ if (mpidr != self)
+ sunxi_cpu_off(mpidr);
+ }
+ }
+}
--- a/plat/allwinner/common/sunxi_native_pm.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch_helpers.h>
-#include <common/debug.h>
-#include <drivers/delay_timer.h>
-#include <lib/mmio.h>
-#include <lib/psci/psci.h>
-
-#include <sunxi_mmap.h>
-#include <sunxi_private.h>
-
-#define SUNXI_WDOG0_CTRL_REG (SUNXI_R_WDOG_BASE + 0x0010)
-#define SUNXI_WDOG0_CFG_REG (SUNXI_R_WDOG_BASE + 0x0014)
-#define SUNXI_WDOG0_MODE_REG (SUNXI_R_WDOG_BASE + 0x0018)
-
-static int sunxi_pwr_domain_on(u_register_t mpidr)
-{
- sunxi_cpu_on(mpidr);
-
- return PSCI_E_SUCCESS;
-}
-
-static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
-{
- sunxi_cpu_power_off_self();
-}
-
-static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
-{
-}
-
-static void sunxi_system_off(void)
-{
- /* Attempt to power down the board (may not return) */
- sunxi_power_down();
-
- /* Turn off all CPUs */
- sunxi_cpu_power_off_others();
- sunxi_cpu_power_off_self();
-}
-
-static void __dead2 sunxi_system_reset(void)
-{
- /* Reset the whole system when the watchdog times out */
- mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
- /* Enable the watchdog with the shortest timeout (0.5 seconds) */
- mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1);
- /* Wait for twice the watchdog timeout before panicking */
- mdelay(1000);
-
- ERROR("PSCI: System reset failed\n");
- panic();
-}
-
-static const plat_psci_ops_t sunxi_native_psci_ops = {
- .pwr_domain_on = sunxi_pwr_domain_on,
- .pwr_domain_off = sunxi_pwr_domain_off,
- .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
- .system_off = sunxi_system_off,
- .system_reset = sunxi_system_reset,
- .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
-};
-
-void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
-{
- *psci_ops = &sunxi_native_psci_ops;
-}
--- /dev/null
+++ b/plat/allwinner/common/sunxi_native_pm_a53.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define SUNXI_WDOG0_CTRL_REG (SUNXI_R_WDOG_BASE + 0x0010)
+#define SUNXI_WDOG0_CFG_REG (SUNXI_R_WDOG_BASE + 0x0014)
+#define SUNXI_WDOG0_MODE_REG (SUNXI_R_WDOG_BASE + 0x0018)
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+ sunxi_cpu_on(mpidr);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ sunxi_cpu_power_off_self();
+}
+
+static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+}
+
+static void sunxi_system_off(void)
+{
+ /* Attempt to power down the board (may not return) */
+ sunxi_power_down();
+
+ /* Turn off all CPUs */
+ sunxi_cpu_power_off_others();
+ sunxi_cpu_power_off_self();
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+ /* Reset the whole system when the watchdog times out */
+ mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
+ /* Enable the watchdog with the shortest timeout (0.5 seconds) */
+ mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1);
+ /* Wait for twice the watchdog timeout before panicking */
+ mdelay(1000);
+
+ ERROR("PSCI: System reset failed\n");
+ panic();
+}
+
+static const plat_psci_ops_t sunxi_native_psci_ops = {
+ .pwr_domain_on = sunxi_pwr_domain_on,
+ .pwr_domain_off = sunxi_pwr_domain_off,
+ .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
+ .system_off = sunxi_system_off,
+ .system_reset = sunxi_system_reset,
+ .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
+};
+
+void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &sunxi_native_psci_ops;
+}
@@ -0,0 +1,35 @@
From cd69f2aad5f14c53be857cf178c928d6958f6fa3 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Thu, 16 Jan 2025 22:12:42 +0100
Subject: [PATCH] refactor(allwinner): allow max cpus to be overridden
Some Allwinner SoCs, like A523, have more than 4 cores per cluster, so
allow this macro to be overridden.
Change-Id: I384d3907cc7cb5be0a4a76f9081b5164629ec49c
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
plat/allwinner/common/allwinner-common.mk | 4 ++++
plat/allwinner/common/include/platform_def.h | 1 -
2 files changed, 4 insertions(+), 1 deletion(-)
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -99,3 +99,7 @@ SEPARATE_CODE_AND_RODATA := 1
# BL31 gets loaded alongside BL33 (U-Boot) by U-Boot's SPL
RESET_TO_BL31 := 1
+
+# Most Allwinner SoCs have 4 cores, but not all
+PLATFORM_MAX_CPUS_PER_CLUSTER ?= 4
+$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
--- a/plat/allwinner/common/include/platform_def.h
+++ b/plat/allwinner/common/include/platform_def.h
@@ -72,7 +72,6 @@
#define PLATFORM_CLUSTER_COUNT U(1)
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
PLATFORM_MAX_CPUS_PER_CLUSTER)
-#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
#define PLATFORM_STACK_SIZE (0x1000 / PLATFORM_CORE_COUNT)
#ifndef SPD_none
@@ -0,0 +1,75 @@
From 26a5fb2370615b1b20ed6425bc608b333a68d2ca Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Sun, 14 Sep 2025 12:50:10 +0100
Subject: [PATCH] feat(allwinner): plat_core_pos: support MT bit
So far all CPU cores used in Allwinner SoCs use the older MPIDR
affinity style, where the MT bit is clear, and the cores are enumerated
using the Aff0 MPIDR field.
Newer SoCs use a newer generation of Arm Cortex cores, which set the MT
bit and put the core number in the Aff1 field.
To accommodate both generations within the shared code, query the MT bit
during the calculation, and use one or the other calculation method.
Change-Id: I2aa5de8c759e0ae5d1cd4a04b6dcc82cadf855ef
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
plat/allwinner/common/plat_helpers.S | 9 ++++++---
plat/allwinner/common/sunxi_topology.c | 18 ++++++++++++------
2 files changed, 18 insertions(+), 9 deletions(-)
--- a/plat/allwinner/common/plat_helpers.S
+++ b/plat/allwinner/common/plat_helpers.S
@@ -32,11 +32,14 @@ func plat_crash_console_flush
ret
endfunc plat_crash_console_flush
+/* All Allwinner SoCs group all their cores in one affinity level */
func plat_my_core_pos
mrs x0, mpidr_el1
- and x1, x0, #MPIDR_CLUSTER_MASK
- and x0, x0, #MPIDR_CPU_MASK
- add x0, x0, x1, LSR #6
+ /* shift MPIDR left by 8 bits if needed to always place cores in Aff1 */
+ tst x0, #MPIDR_MT_MASK
+ lsl x1, x0, #MPIDR_AFFINITY_BITS
+ csel x1, x1, x0, eq
+ ubfx x0, x1, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
ret
endfunc plat_my_core_pos
--- a/plat/allwinner/common/sunxi_topology.c
+++ b/plat/allwinner/common/sunxi_topology.c
@@ -18,19 +18,25 @@ static const unsigned char plat_power_do
PLATFORM_MAX_CPUS_PER_CLUSTER,
};
+/*
+ * All Allwinner SoCs place all their cores in one affinity level. Which one
+ * this is just differs depending on whether they use the "new" MPDIR encoding
+ * (cores in Aff1, clusters in Aff2) or the traditional one (cores in Aff0).
+ */
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
- unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
- unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+ if (!(read_mpidr() & MPIDR_MT_MASK)) {
+ mpidr <<= MPIDR_AFFINITY_BITS;
+ }
- if (MPIDR_AFFLVL3_VAL(mpidr) > 0 ||
+ if (MPIDR_AFFLVL0_VAL(mpidr) > 0 ||
+ MPIDR_AFFLVL1_VAL(mpidr) >= PLATFORM_CORE_COUNT ||
MPIDR_AFFLVL2_VAL(mpidr) > 0 ||
- cluster >= PLATFORM_CLUSTER_COUNT ||
- core >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+ MPIDR_AFFLVL3_VAL(mpidr) > 0) {
return -1;
}
- return cluster * PLATFORM_MAX_CPUS_PER_CLUSTER + core;
+ return MPIDR_AFFLVL1_VAL(mpidr);
}
const unsigned char *plat_get_power_domain_tree_desc(void)
@@ -0,0 +1,45 @@
From bb80445f8308e27127c36e902c5a76ce0458bf53 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Mon, 27 Oct 2025 21:54:32 +0100
Subject: [PATCH] feat(allwinner): add plat_arm_calc_core_pos helper
This helper is just generalized version of plat_my_core_pos().
It will be needed for generic gic driver for gicv3.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
plat/allwinner/common/plat_helpers.S | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
--- a/plat/allwinner/common/plat_helpers.S
+++ b/plat/allwinner/common/plat_helpers.S
@@ -12,6 +12,7 @@
.globl plat_crash_console_init
.globl plat_crash_console_putc
.globl plat_crash_console_flush
+ .globl plat_arm_calc_core_pos
.globl plat_my_core_pos
.globl platform_mem_init
.globl plat_report_exception
@@ -33,14 +34,18 @@ func plat_crash_console_flush
endfunc plat_crash_console_flush
/* All Allwinner SoCs group all their cores in one affinity level */
-func plat_my_core_pos
- mrs x0, mpidr_el1
+func plat_arm_calc_core_pos
/* shift MPIDR left by 8 bits if needed to always place cores in Aff1 */
tst x0, #MPIDR_MT_MASK
lsl x1, x0, #MPIDR_AFFINITY_BITS
csel x1, x1, x0, eq
ubfx x0, x1, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
ret
+endfunc plat_arm_calc_core_pos
+
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_arm_calc_core_pos
endfunc plat_my_core_pos
func platform_mem_init
@@ -0,0 +1,463 @@
From e019f64d91ff7c2dfbbfe7f76a14f240761b9edc Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 12 Jan 2025 21:48:24 +0100
Subject: [PATCH] feat(allwinner): add A523 support
The Allwinner A523 features two clusters with four Cortex-A55 cores
each, also use an Arm GIC-600 for the interrupt controller. The memory
map changes a bit, but most of the peripherals are compatible as far as
TF-A is concerned.
An exception are the CPU ops, which turn the power of cores on or off,
they use a separate implementation, dictated by the DSU interconnect.
Add a new build platform, enabling the Cortex-A55 cores, and provide an
A55 specific Makefile snippet. Describe the new memory map, and add the
new CPU ops implementation.
Change-Id: I10d5bd1224e21593ab96ec62b986e01b141bf8d8
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
docs/plat/allwinner.rst | 2 +
plat/allwinner/common/allwinner-common-a55.mk | 25 ++++
plat/allwinner/common/include/plat_macros.S | 4 +
plat/allwinner/common/include/sunxi_def.h | 1 +
plat/allwinner/common/sunxi_bl31_setup.c | 15 +++
plat/allwinner/common/sunxi_native_pm_a55.c | 118 ++++++++++++++++++
plat/allwinner/common/sunxi_security.c | 17 +++
.../allwinner/sun55i_a523/include/sunxi_ccu.h | 14 +++
.../sun55i_a523/include/sunxi_cpucfg.h | 7 ++
.../sun55i_a523/include/sunxi_mmap.h | 50 ++++++++
.../allwinner/sun55i_a523/include/sunxi_spc.h | 17 +++
plat/allwinner/sun55i_a523/platform.mk | 25 ++++
.../allwinner/sun55i_a523/sunxi_idle_states.c | 11 ++
plat/allwinner/sun55i_a523/sunxi_power.c | 20 +++
14 files changed, 326 insertions(+)
create mode 100644 plat/allwinner/common/allwinner-common-a55.mk
create mode 100644 plat/allwinner/common/sunxi_native_pm_a55.c
create mode 100644 plat/allwinner/sun55i_a523/include/sunxi_ccu.h
create mode 100644 plat/allwinner/sun55i_a523/include/sunxi_cpucfg.h
create mode 100644 plat/allwinner/sun55i_a523/include/sunxi_mmap.h
create mode 100644 plat/allwinner/sun55i_a523/include/sunxi_spc.h
create mode 100644 plat/allwinner/sun55i_a523/platform.mk
create mode 100644 plat/allwinner/sun55i_a523/sunxi_idle_states.c
create mode 100644 plat/allwinner/sun55i_a523/sunxi_power.c
--- a/docs/plat/allwinner.rst
+++ b/docs/plat/allwinner.rst
@@ -27,6 +27,8 @@ There is one build target per supported
+------+-------------------+
| R329 | sun50i_r329 |
+------+-------------------+
+| A523 | sun55i_a523 |
++------+-------------------+
To build with the default settings for a particular SoC:
--- /dev/null
+++ b/plat/allwinner/common/allwinner-common-a55.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL31_SOURCES += lib/cpus/${ARCH}/cortex_a55.S
+
+ifeq (${SUNXI_PSCI_USE_NATIVE},1)
+BL31_SOURCES += ${AW_PLAT}/common/sunxi_native_pm_a55.c
+endif
+
+# A55 cores use GIC-600
+USE_GIC_DRIVER := 3
+GICV3_SUPPORT_GIC600 := 1
+
+# ARISC SCP not yet supported
+SUNXI_PSCI_USE_SCPI := 0
+
+# Enable workarounds for Cortex-A55 errata. Allwinner uses at least r2p0.
+ERRATA_A55_1530923 := 1
+
+USE_COHERENT_MEM := 0
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
+HW_ASSISTED_COHERENCY := 1
--- a/plat/allwinner/common/include/plat_macros.S
+++ b/plat/allwinner/common/include/plat_macros.S
@@ -19,7 +19,11 @@
* ---------------------------------------------
*/
.macro plat_crash_print_regs
+#if USE_GIC_DRIVER == 3
+ mov_imm x17, SUNXI_GICR_BASE
+#else
mov_imm x17, SUNXI_GICC_BASE
+#endif
mov_imm x16, SUNXI_GICD_BASE
arm_print_gic_regs
.endm
--- a/plat/allwinner/common/include/sunxi_def.h
+++ b/plat/allwinner/common/include/sunxi_def.h
@@ -19,6 +19,7 @@
#define SUNXI_SOC_H6 0x1728
#define SUNXI_SOC_H616 0x1823
#define SUNXI_SOC_R329 0x1851
+#define SUNXI_SOC_A523 0x1890
#define SUNXI_VER_BITS_MASK 0xffU
#define JEDEC_ALLWINNER_BKID 9U
--- a/plat/allwinner/common/sunxi_bl31_setup.c
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -18,6 +18,7 @@
#include <drivers/generic_delay_timer.h>
#include <drivers/ti/uart/uart_16550.h>
#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
#include <plat/common/platform.h>
#include <sunxi_def.h>
@@ -32,6 +33,13 @@ static console_t console;
static void *fdt;
+#if USE_GIC_DRIVER == 3
+static const uintptr_t sunxi_gicr_base_addrs[2] = {
+ SUNXI_GICR_BASE,
+ 0U
+};
+#endif
+
/*
* Try to find a DTB loaded in memory by previous stages.
*
@@ -123,6 +131,9 @@ void bl31_platform_setup(void)
case SUNXI_SOC_R329:
soc_name = "R329";
break;
+ case SUNXI_SOC_A523:
+ soc_name = "A523";
+ break;
default:
soc_name = "unknown";
break;
@@ -166,6 +177,10 @@ void bl31_platform_setup(void)
sunxi_pmic_setup(soc_id, fdt);
+#if USE_GIC_DRIVER == 3
+ gic_set_gicr_frames(sunxi_gicr_base_addrs);
+#endif
+
INFO("BL31: Platform setup done\n");
}
--- /dev/null
+++ b/plat/allwinner/common/sunxi_native_pm_a55.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include <sunxi_cpucfg.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define SUNXI_WDOG0_SRST_REG (SUNXI_R_WDOG_BASE + 0x0008)
+
+#define SUNXI_INITARCH_REG(n) (SUNXI_CPUCFG_BASE + 0x0020 + (n) * 4)
+#define HOTPLUG_CONTROL_REG(n) (SUNXI_R_CPUCFG_BASE + 0x200 + (n) * 4)
+#define HOTPLUG_POWERMODE_REG(n) (SUNXI_R_CPUCFG_BASE + 0x220 + (n) * 4)
+#define PPU_PWSR(n) (SUNXI_R_CPUCFG_BASE + (n) * 0x1000 + 0x1008)
+
+#define STATE_ON 8
+#define STATE_OFF 0
+
+#define GIC_WAKEUP_DISABLE BIT(1)
+#define POWER_ON BIT(0)
+
+#define HOTPLUG_EN BIT(0)
+
+#define AARCH64 BIT(0)
+
+static void sunxi_cpu_off(u_register_t mpidr)
+{
+ unsigned int core = MPIDR_AFFLVL1_VAL(mpidr);
+
+ mmio_clrbits_32(HOTPLUG_POWERMODE_REG(core), POWER_ON);
+
+ mmio_setbits_32(HOTPLUG_CONTROL_REG(core), GIC_WAKEUP_DISABLE);
+}
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+ unsigned int core = MPIDR_AFFLVL1_VAL(mpidr);
+
+ mmio_setbits_32(SUNXI_INITARCH_REG(core), AARCH64);
+
+ while ((mmio_read_32(PPU_PWSR(core + 1)) & 0xf) != STATE_OFF)
+ ;
+
+ mmio_setbits_32(HOTPLUG_POWERMODE_REG(core), POWER_ON);
+ mmio_setbits_32(HOTPLUG_CONTROL_REG(core), HOTPLUG_EN);
+
+ while ((mmio_read_32(PPU_PWSR(core + 1)) & 0xf) != STATE_ON)
+ ;
+
+ mmio_clrbits_32(HOTPLUG_CONTROL_REG(core), HOTPLUG_EN);
+ mmio_clrbits_32(HOTPLUG_POWERMODE_REG(core), POWER_ON);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ sunxi_cpu_off(read_mpidr());
+}
+
+static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ unsigned int core = plat_my_core_pos();
+
+ mmio_clrbits_32(HOTPLUG_CONTROL_REG(core), GIC_WAKEUP_DISABLE);
+}
+
+static void sunxi_system_off(void)
+{
+ unsigned int cluster;
+ unsigned int core;
+
+ /* Attempt to power down the board (may not return) */
+ sunxi_power_down();
+
+ /* Turn off all CPUs */
+ for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
+ for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
+ u_register_t mpidr = (cluster << MPIDR_AFF2_SHIFT) |
+ (core << MPIDR_AFF1_SHIFT) |
+ BIT(24) | BIT(31);
+ sunxi_cpu_off(mpidr);
+ }
+ }
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+ /* Reset the whole system when using watchdog reset */
+ mmio_write_32(SUNXI_WDOG0_SRST_REG, 0x16aa0001);
+
+ ERROR("PSCI: System reset failed\n");
+ panic();
+}
+
+static const plat_psci_ops_t sunxi_native_psci_ops = {
+ .pwr_domain_on = sunxi_pwr_domain_on,
+ .pwr_domain_off = sunxi_pwr_domain_off,
+ .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
+ .system_off = sunxi_system_off,
+ .system_reset = sunxi_system_reset,
+ .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
+};
+
+void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &sunxi_native_psci_ops;
+}
--- a/plat/allwinner/common/sunxi_security.c
+++ b/plat/allwinner/common/sunxi_security.c
@@ -37,4 +37,21 @@ void sunxi_security_setup(void)
/* Set all DMA channels (16 max.) to non-secure */
mmio_write_32(SUNXI_DMA_BASE + DMA_SEC_REG, 0xffff);
+
+ /* Some SoCs feature more protection bits in the PRCM block */
+#ifdef SUNXI_R_TZMA_BASE
+ mmio_write_32(SUNXI_R_TZMA_BASE + 0, 0);
+ mmio_write_32(SUNXI_R_TZMA_BASE + 4, 0);
+ mmio_write_32(SUNXI_R_TZMA_BASE + 8, 0);
+#endif
+
+#ifdef SUNXI_R_SPC_BASE
+ mmio_write_32(SUNXI_R_SPC_BASE + 0x04, 0xffffffff);
+ mmio_write_32(SUNXI_R_SPC_BASE + 0x14, 0xffffffff);
+ mmio_write_32(SUNXI_R_SPC_BASE + 0x24, 0xffffffff);
+#endif
+
+#ifdef SUNXI_DSP_PRCM_BASE
+ mmio_write_32(SUNXI_DSP_PRCM_BASE + 8, 7);
+#endif
}
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x0f00)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x0290)
+
+#endif /* SUNXI_CCU_H */
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/include/sunxi_cpucfg.h
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sunxi_cpucfg_ncat2.h>
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/include/sunxi_mmap.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_MMAP_H
+#define SUNXI_MMAP_H
+
+/* Memory regions */
+#define SUNXI_ROM_BASE 0x00000000
+#define SUNXI_ROM_SIZE 0x00010000
+#define SUNXI_SRAM_BASE 0x00020000
+#define SUNXI_SRAM_SIZE 0x00044000
+#define SUNXI_SRAM_A1_BASE 0x00020000
+#define SUNXI_SRAM_A1_SIZE 0x00020000
+#define SUNXI_SRAM_A2_BASE 0x00040000
+#define SUNXI_SRAM_A2_BL31_OFFSET 0x00014000
+#define SUNXI_SRAM_A2_SIZE 0x00024000
+#define SUNXI_DEV_BASE 0x01000000
+#define SUNXI_DEV_SIZE 0x09000000
+#define SUNXI_DRAM_BASE 0x40000000
+#define SUNXI_DRAM_VIRT_BASE 0x0a000000
+
+/* Memory-mapped devices */
+#define SUNXI_PIO_BASE 0x02000000
+#define SUNXI_SPC_BASE 0x02000800
+#define SUNXI_CCU_BASE 0x02001000
+#define SUNXI_WDOG_BASE 0x02050000
+#define SUNXI_UART0_BASE 0x02500000
+#define SUNXI_SYSCON_BASE 0x03000000
+#define SUNXI_DMA_BASE 0x03002000
+#define SUNXI_SID_BASE 0x03006000
+#define SUNXI_GICD_BASE 0x03400000
+#define SUNXI_GICR_BASE 0x03460000
+#define SUNXI_SPI0_BASE 0x04025000
+#define SUNXI_R_SPC_BASE 0x07002000
+#define SUNXI_R_TZMA_BASE 0x07002400
+#define SUNXI_R_PRCM_BASE 0x07010000
+#define SUNXI_R_WDOG_BASE 0x07020400
+#define SUNXI_R_PIO_BASE 0x07022000
+#define SUNXI_R_CPUCFG_BASE 0x07050000
+#define SUNXI_R_UART_BASE 0x07080000
+#define SUNXI_R_I2C_BASE 0x07081400
+#define SUNXI_MSGBOX_BASE 0x07094000
+#define SUNXI_DSP_PRCM_BASE 0x07102000
+#define SUNXI_CPUCFG_BASE 0x08000000
+#define SUNXI_C0_CPUXCFG_BASE 0x09010000
+
+#endif /* SUNXI_MMAP_H */
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/include/sunxi_spc.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+/* Get by REing stock ATF and checking initialization loop boundary */
+#define SUNXI_SPC_NUM_PORTS 14
+
+#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
+
+#endif /* SUNXI_SPC_H */
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/platform.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Allwinner A523 supports Armv8.2 extensions
+ARM_ARCH_MAJOR := 8
+ARM_ARCH_MINOR := 2
+
+# There are 8 cores in 1 cluster
+PLATFORM_MAX_CPUS_PER_CLUSTER := 8
+
+SUNXI_SETUP_REGULATORS := 0
+
+# No ARISC SCP support at the moment
+SUNXI_PSCI_USE_SCPI := 0
+SUNXI_PSCI_USE_NATIVE := 1
+
+# The differences between the platforms are covered by the include files.
+include plat/allwinner/common/allwinner-common.mk
+include plat/allwinner/common/allwinner-common-a55.mk
+
+# Put NOBITS memory in the first 64K of SRAM A2, overwriting U-Boot's SPL.
+SEPARATE_NOBITS_REGION := 1
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/sunxi_idle_states.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sunxi_private.h>
+
+const struct psci_cpu_idle_state sunxi_idle_states[] = {
+ {}
+};
--- /dev/null
+++ b/plat/allwinner/sun55i_a523/sunxi_power.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_cpucfg.h>
+#include <sunxi_private.h>
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+ /* PMIC not yet supported */
+ return 0;
+}
+
+void sunxi_power_down(void)
+{
+}