[PATCH 3/6] sunxi: add SPC setup for R528/T113 secure boot handoff

Lukas Schmid lukas.schmid at netcube.li
Wed Mar 25 20:26:10 CET 2026


The R528/T113 family protects peripheral access through the SPC, and
also uses security switch registers in the CCU, PRCM and DMA
controller.

Configure these blocks during early platform init so Linux can access
the peripherals after U-Boot hands off control when booting in secure
mode. Add an R528/T113-specific SPC init step alongside the existing
early security controller setup, allow non-secure DMA access there, and
switch the CCU and PRCM buses to non-secure access in clock_init_sec().

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/arm/cpu/armv7/sunxi/Makefile             |  1 +
 arch/arm/cpu/armv7/sunxi/spc.c                | 20 ++++++++++++++
 .../include/asm/arch-sunxi/cpu_sunxi_ncat2.h  | 27 +++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/sys_proto.h   |  8 ++++++
 arch/arm/mach-sunxi/board.c                   |  1 +
 arch/arm/mach-sunxi/clock_sun50i_h6.c         |  8 ++++++
 6 files changed, 65 insertions(+)
 create mode 100644 arch/arm/cpu/armv7/sunxi/spc.c

diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
index 0624e93efde..bc19f6a203c 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -8,6 +8,7 @@
 
 obj-$(CONFIG_MACH_SUN6I)	+= tzpc.o
 obj-$(CONFIG_MACH_SUN8I_H3)	+= tzpc.o
+obj-$(CONFIG_MACH_SUN8I_R528)	+= spc.o
 
 obj-$(CONFIG_MACH_SUN6I)	+= sram.o
 obj-$(CONFIG_MACH_SUN8I)	+= sram.o
diff --git a/arch/arm/cpu/armv7/sunxi/spc.c b/arch/arm/cpu/armv7/sunxi/spc.c
new file mode 100644
index 00000000000..bdecfaa1b4b
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/spc.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Chen-Yu Tsai <wens at csie.org>
+ * (C) Copyright 2026 Lukas Schmid <lukas.schmid at netcube.li>
+ */
+
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/sys_proto.h>
+
+void spc_init(void)
+{
+	struct sunxi_spc *spc = (struct sunxi_spc *)SUNXI_SPC_BASE;
+	int i;
+
+	for (i = 0; i < SUNXI_SPC_NUM_PORTS; i++)
+		writel(SUNXI_SPC_DECPORT_MASK, &spc->decport[i].set);
+
+	writel(SUNXI_DMA_SEC_MASK, SUNXI_DMA_BASE + SUNXI_DMA_SEC_REG);
+}
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
index bcfdc0a41c5..7a4d25e6e78 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
@@ -7,6 +7,7 @@
 #ifndef _SUNXI_CPU_SUNXI_NCAT2_H
 #define _SUNXI_CPU_SUNXI_NCAT2_H
 
+#define SUNXI_SPC_BASE			0x02000800
 #define SUNXI_CCM_BASE			0x02001000
 #define SUNXI_TIMER_BASE		0x02050000
 
@@ -16,6 +17,7 @@
 #define SUNXI_TWI3_BASE			0x02502C00
 
 #define SUNXI_SRAMC_BASE		0x03000000
+#define SUNXI_DMA_BASE			0x03002000
 /* SID address space starts at 0x03006000, but e-fuse is at offset 0x200 */
 #define SUNXI_SIDC_BASE			0x03006000
 #define SUNXI_SID_BASE			0x03006200
@@ -50,7 +52,32 @@
 
 #define SUNXI_CPU_PLL_CFG_BASE		0x08817000
 
+#ifdef CONFIG_MACH_SUN8I_R528
+#define SUNXI_CCM_SEC_SWITCH_REG        (SUNXI_CCM_BASE + 0x0f00)
+#define SUNXI_CCM_SEC_SWITCH_NONSEC	0x7
+#define SUNXI_PRCM_SEC_SWITCH_REG       (SUNXI_PRCM_BASE + 0x0290)
+#define SUNXI_PRCM_SEC_SWITCH_NONSEC	0x1
+#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))
+#define SUNXI_SPC_NUM_PORTS             13
+#define SUNXI_SPC_DECPORT_MASK		0xffffffff
+#define SUNXI_DMA_SEC_REG		0x20
+#define SUNXI_DMA_SEC_MASK		0xffff
+#endif
+
 #ifndef __ASSEMBLY__
+struct sunxi_spc_decport {
+	u32 status;
+	u32 set;
+	u32 clear;
+	u32 reserved;
+};
+
+struct sunxi_spc {
+	struct sunxi_spc_decport decport[SUNXI_SPC_NUM_PORTS];
+};
+
 void sunxi_board_init(void);
 void sunxi_reset(void);
 int sunxi_get_sid(unsigned int *sid);
diff --git a/arch/arm/include/asm/arch-sunxi/sys_proto.h b/arch/arm/include/asm/arch-sunxi/sys_proto.h
index 6f70753e948..a006e592f83 100644
--- a/arch/arm/include/asm/arch-sunxi/sys_proto.h
+++ b/arch/arm/include/asm/arch-sunxi/sys_proto.h
@@ -18,6 +18,14 @@ bool sunxi_get_unique_sid(unsigned int *sid);
 /* Build legacy-compatible SID-derived locally administered MAC address. */
 bool sunxi_get_sid_mac_addr(int index, u8 mac[6]);
 
+#ifdef CONFIG_MACH_SUN8I_R528
+void spc_init(void);
+#else
+static inline void spc_init(void)
+{
+}
+#endif
+
 /* return_to_fel() - Return to BROM from SPL
  *
  * This returns back into the BROM after U-Boot SPL has performed its initial
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 432b1c10f92..4d98d350cbe 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -475,6 +475,7 @@ void board_init_f(ulong dummy)
 
 	/* Enable non-secure access to some peripherals */
 	tzpc_init();
+	spc_init();
 
 	timer_init();
 	clock_init();
diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
index 80004f13a1e..217d47c8770 100644
--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
@@ -74,6 +74,14 @@ void clock_init_safe(void)
 	}
 }
 
+void clock_init_sec(void)
+{
+	if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
+		writel(SUNXI_CCM_SEC_SWITCH_NONSEC, SUNXI_CCM_SEC_SWITCH_REG);
+		writel(SUNXI_PRCM_SEC_SWITCH_NONSEC, SUNXI_PRCM_SEC_SWITCH_REG);
+	}
+}
+
 void clock_init_uart(void)
 {
 	void *const ccm = (void *)SUNXI_CCM_BASE;
-- 
2.47.3




More information about the U-Boot mailing list