[PATCH v4 0/4] Allwinner R528/T113s PSCI

Hi list,
This is the third, and hopefully final, version of my patchset for PSCI support on R528/T113-s3. This one, as always, depends on Andre Przywara's T113s support series (v2), available on the list and also located on a Git branch at: https://source.denx.de/u-boot/custodians/u-boot-sunxi.git t113s-v2
NOTE THAT THIS ALSO depends on the following commit on master: 3d5e52bd97 ("ARM: psci: move GIC address override to Kconfig")
For testing: I can confirm that patch 2/4 results in no change to machine code whatsoever on any supported target. Patch 1/4 results in a minor machine code change on R40 only. Patch 3/4 will likely require testing on each of the 4 "special case" sunxi targets (sun6i, sun7i, R40, H3) to ensure that register offsets are kept consistent. Patch 4/4 needs testing on R528 only.
Warm regards, Sam
Changes v3->v4: - The GIC base address override is done through Kconfig, instead of in sunxi-common.h
Changes v2->v3: - Fix missing `cpu=0;` for the sun7i power management case. - Make sunxi_cpu_power_off() a static function, per feedback on v2. - Kevin Amadiva of MEC electronics got in touch with me off-list, reported success bringing up CPU1 of a T113 with this patchset, and kindly provided me with a Tested-by tag for patch 4/4. - Remove a comment about R40/R528 being special, per feedback on v2. - Simplify an if statement, per feedback on v2. - Add missing 'select' directives to the R528 Kconfig, per feedback on v2.
Changes v1->v2: - Power clamp is now adjusted ONLY on sun{6,7}i, H3, R40. The previous version was mistakenly doing this EXCEPT on those machines. - Flattened sunxi_power_switch() into sunxi_cpu_set_power() for simplicity's sake. - Moved the "power clamp is not NULL" conditional into sunxi_cpu_set_power(). - Removed unnecessary H6 special-case, since H6 is actually ARM64. - Renamed SUNXI_CPUX_BASE to SUNXI_CPUCFG_BASE, to mirror expected changes in Andre's v2 of the R528 series (we decided against using a new name for this block). - Removed sunxi_cpucfg_reg struct, and stopped using the PRCM struct in psci.c.
Sam Edwards (4): sunxi: psci: clean away preprocessor macros sunxi: psci: refactor register access to separate functions sunxi: psci: stop modeling register layout with C structs sunxi: psci: implement PSCI on R528
arch/arm/cpu/armv7/Kconfig | 3 +- arch/arm/cpu/armv7/sunxi/psci.c | 185 ++++++++++++++--------- arch/arm/include/asm/arch-sunxi/cpucfg.h | 67 -------- arch/arm/mach-sunxi/Kconfig | 4 + 4 files changed, 121 insertions(+), 138 deletions(-) delete mode 100644 arch/arm/include/asm/arch-sunxi/cpucfg.h

This patch restructures psci.c to get away from the "many different function definitions switched by #ifdef" paradigm to the preferred style of having a single function definition with `if (IS_ENABLED(...))` to make the optimizer include only the appropriate function bodies instead.
There are no functional changes here.
Signed-off-by: Sam Edwards CFSworks@gmail.com Reviewed-by: Andre Przywara andre.przywara@arm.com --- arch/arm/cpu/armv7/sunxi/psci.c | 103 +++++++++++++------------------- 1 file changed, 43 insertions(+), 60 deletions(-)
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index e1d3638b5c..69fa3f3c2e 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -76,11 +76,8 @@ static void __secure __mdelay(u32 ms) isb(); }
-static void __secure clamp_release(u32 __maybe_unused *clamp) +static void __secure clamp_release(u32 *clamp) { -#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_H3) || \ - defined(CONFIG_MACH_SUN8I_R40) u32 tmp = 0x1ff; do { tmp >>= 1; @@ -88,83 +85,69 @@ static void __secure clamp_release(u32 __maybe_unused *clamp) } while (tmp);
__mdelay(10); -#endif }
-static void __secure clamp_set(u32 __maybe_unused *clamp) +static void __secure clamp_set(u32 *clamp) { -#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_H3) || \ - defined(CONFIG_MACH_SUN8I_R40) writel(0xff, clamp); -#endif }
-static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on, - int cpu) +static void __secure sunxi_set_entry_address(void *entry) { - if (on) { - /* Release power clamp */ - clamp_release(clamp); - - /* Clear power gating */ - clrbits_le32(pwroff, BIT(cpu)); + /* secondary core entry address is programmed differently on R40 */ + if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { + writel((u32)entry, + SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); } else { - /* Set power gating */ - setbits_le32(pwroff, BIT(cpu)); + struct sunxi_cpucfg_reg *cpucfg = + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
- /* Activate power clamp */ - clamp_set(clamp); + writel((u32)entry, &cpucfg->priv0); } }
-#ifdef CONFIG_MACH_SUN8I_R40 -/* secondary core entry address is programmed differently on R40 */ -static void __secure sunxi_set_entry_address(void *entry) -{ - writel((u32)entry, - SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); -} -#else -static void __secure sunxi_set_entry_address(void *entry) +static void __secure sunxi_cpu_set_power(int cpu, bool on) { + u32 *clamp = NULL; + u32 *pwroff; struct sunxi_cpucfg_reg *cpucfg = (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
- writel((u32)entry, &cpucfg->priv0); -} -#endif + /* sun7i (A20) is different from other single cluster SoCs */ + if (IS_ENABLED(CONFIG_MACH_SUN7I)) { + clamp = &cpucfg->cpu1_pwr_clamp; + pwroff = &cpucfg->cpu1_pwroff; + cpu = 0; + } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { + clamp = (void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu); + pwroff = (void *)cpucfg + SUN8I_R40_PWROFF; + } else { + struct sunxi_prcm_reg *prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
-#ifdef CONFIG_MACH_SUN7I -/* sun7i (A20) is different from other single cluster SoCs */ -static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on) -{ - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + if (IS_ENABLED(CONFIG_MACH_SUN6I) || + IS_ENABLED(CONFIG_MACH_SUN8I_H3)) + clamp = &prcm->cpu_pwr_clamp[cpu];
- sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff, - on, 0); -} -#elif defined CONFIG_MACH_SUN8I_R40 -static void __secure sunxi_cpu_set_power(int cpu, bool on) -{ - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + pwroff = &prcm->cpu_pwroff; + }
- sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu), - (void *)cpucfg + SUN8I_R40_PWROFF, - on, cpu); -} -#else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */ -static void __secure sunxi_cpu_set_power(int cpu, bool on) -{ - struct sunxi_prcm_reg *prcm = - (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; + if (on) { + /* Release power clamp */ + if (clamp) + clamp_release(clamp);
- sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff, - on, cpu); + /* Clear power gating */ + clrbits_le32(pwroff, BIT(cpu)); + } else { + /* Set power gating */ + setbits_le32(pwroff, BIT(cpu)); + + /* Activate power clamp */ + if (clamp) + clamp_set(clamp); + } } -#endif /* CONFIG_MACH_SUN7I */
void __secure sunxi_cpu_power_off(u32 cpuid) {

This is to prepare for R528, which does not have the typical "CPUCFG" block; it has a "CPUX" block which provides these same functions but is organized differently.
Moving the hardware-access bits to their own functions separates the logic from the hardware so we can reuse the same logic.
Signed-off-by: Sam Edwards CFSworks@gmail.com Reviewed-by: Andre Przywara andre.przywara@arm.com --- arch/arm/cpu/armv7/sunxi/psci.c | 66 +++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 19 deletions(-)
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 69fa3f3c2e..27ca9c39e1 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -92,7 +92,7 @@ static void __secure clamp_set(u32 *clamp) writel(0xff, clamp); }
-static void __secure sunxi_set_entry_address(void *entry) +static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry) { /* secondary core entry address is programmed differently on R40 */ if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { @@ -149,30 +149,60 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) } }
-void __secure sunxi_cpu_power_off(u32 cpuid) +static void __secure sunxi_cpu_set_reset(int cpu, bool reset) { struct sunxi_cpucfg_reg *cpucfg = (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + + writel(reset ? 0b00 : 0b11, &cpucfg->cpu[cpu].rst); +} + +static void __secure sunxi_cpu_set_locking(int cpu, bool lock) +{ + struct sunxi_cpucfg_reg *cpucfg = + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + + if (lock) + clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + else + setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); +} + +static bool __secure sunxi_cpu_poll_wfi(int cpu) +{ + struct sunxi_cpucfg_reg *cpucfg = + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + + return !!(readl(&cpucfg->cpu[cpu].status) & BIT(2)); +} + +static void __secure sunxi_cpu_invalidate_cache(int cpu) +{ + struct sunxi_cpucfg_reg *cpucfg = + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + + clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu)); +} + +static void __secure sunxi_cpu_power_off(u32 cpuid) +{ u32 cpu = cpuid & 0x3;
/* Wait for the core to enter WFI */ - while (1) { - if (readl(&cpucfg->cpu[cpu].status) & BIT(2)) - break; + while (!sunxi_cpu_poll_wfi(cpu)) __mdelay(1); - }
/* Assert reset on target CPU */ - writel(0, &cpucfg->cpu[cpu].rst); + sunxi_cpu_set_reset(cpu, true);
/* Lock CPU (Disable external debug access) */ - clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + sunxi_cpu_set_locking(cpu, true);
/* Power down CPU */ sunxi_cpu_set_power(cpuid, false);
- /* Unlock CPU (Disable external debug access) */ - setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + /* Unlock CPU (Reenable external debug access) */ + sunxi_cpu_set_locking(cpu, false); }
static u32 __secure cp15_read_scr(void) @@ -229,33 +259,31 @@ out: int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc, u32 context_id) { - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; u32 cpu = (mpidr & 0x3);
/* store target PC and context id */ psci_save(cpu, pc, context_id);
/* Set secondary core power on PC */ - sunxi_set_entry_address(&psci_cpu_entry); + sunxi_cpu_set_entry(cpu, &psci_cpu_entry);
/* Assert reset on target CPU */ - writel(0, &cpucfg->cpu[cpu].rst); + sunxi_cpu_set_reset(cpu, true);
/* Invalidate L1 cache */ - clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu)); + sunxi_cpu_invalidate_cache(cpu);
/* Lock CPU (Disable external debug access) */ - clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + sunxi_cpu_set_locking(cpu, true);
/* Power up target CPU */ sunxi_cpu_set_power(cpu, true);
/* De-assert reset on target CPU */ - writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst); + sunxi_cpu_set_reset(cpu, false);
- /* Unlock CPU (Disable external debug access) */ - setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + /* Unlock CPU (Reenable external debug access) */ + sunxi_cpu_set_locking(cpu, false);
return ARM_PSCI_RET_SUCCESS; }

Since the sunxi support nowadays generally prefers #defined register offsets instead of modeling register layouts using C structs, now is a good time to do this for PSCI as well. This patch moves away from using the structs `sunxi_cpucfg_reg` and `sunxi_prcm_reg` in psci.c.
The former struct and its associated header file existed only to support PSCI code, so also delete them altogether.
Signed-off-by: Sam Edwards CFSworks@gmail.com --- arch/arm/cpu/armv7/sunxi/psci.c | 57 ++++++++------------ arch/arm/include/asm/arch-sunxi/cpucfg.h | 67 ------------------------ 2 files changed, 23 insertions(+), 101 deletions(-) delete mode 100644 arch/arm/include/asm/arch-sunxi/cpucfg.h
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 27ca9c39e1..207aa6bc4b 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -11,8 +11,6 @@ #include <asm/cache.h>
#include <asm/arch/cpu.h> -#include <asm/arch/cpucfg.h> -#include <asm/arch/prcm.h> #include <asm/armv7.h> #include <asm/gic.h> #include <asm/io.h> @@ -27,6 +25,17 @@ #define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET) #define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
+/* + * Offsets into the CPUCFG block applicable to most SUNXIs. + */ +#define SUNXI_CPU_RST(cpu) (0x40 + (cpu) * 0x40 + 0x0) +#define SUNXI_CPU_STATUS(cpu) (0x40 + (cpu) * 0x40 + 0x8) +#define SUNXI_GEN_CTRL (0x184) +#define SUNXI_PRIV0 (0x1a4) +#define SUN7I_CPU1_PWR_CLAMP (0x1b0) +#define SUN7I_CPU1_PWROFF (0x1b4) +#define SUNXI_DBG_CTRL1 (0x1e4) + /* * R40 is different from other single cluster SoCs. * @@ -99,10 +108,7 @@ static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry) writel((u32)entry, SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); } else { - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; - - writel((u32)entry, &cpucfg->priv0); + writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0); } }
@@ -110,26 +116,21 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) { u32 *clamp = NULL; u32 *pwroff; - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
/* sun7i (A20) is different from other single cluster SoCs */ if (IS_ENABLED(CONFIG_MACH_SUN7I)) { - clamp = &cpucfg->cpu1_pwr_clamp; - pwroff = &cpucfg->cpu1_pwroff; + clamp = (void *)SUNXI_CPUCFG_BASE + SUN7I_CPU1_PWR_CLAMP; + pwroff = (void *)SUNXI_CPUCFG_BASE + SUN7I_CPU1_PWROFF; cpu = 0; } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { - clamp = (void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu); - pwroff = (void *)cpucfg + SUN8I_R40_PWROFF; + clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu); + pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF; } else { - struct sunxi_prcm_reg *prcm = - (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; - if (IS_ENABLED(CONFIG_MACH_SUN6I) || IS_ENABLED(CONFIG_MACH_SUN8I_H3)) - clamp = &prcm->cpu_pwr_clamp[cpu]; + clamp = (void *)SUNXI_PRCM_BASE + 0x140 + cpu * 0x4;
- pwroff = &prcm->cpu_pwroff; + pwroff = (void *)SUNXI_PRCM_BASE + 0x100; }
if (on) { @@ -151,37 +152,25 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
static void __secure sunxi_cpu_set_reset(int cpu, bool reset) { - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; - - writel(reset ? 0b00 : 0b11, &cpucfg->cpu[cpu].rst); + writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu)); }
static void __secure sunxi_cpu_set_locking(int cpu, bool lock) { - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; - if (lock) - clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu)); else - setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); + setbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu)); }
static bool __secure sunxi_cpu_poll_wfi(int cpu) { - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; - - return !!(readl(&cpucfg->cpu[cpu].status) & BIT(2)); + return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2)); }
static void __secure sunxi_cpu_invalidate_cache(int cpu) { - struct sunxi_cpucfg_reg *cpucfg = - (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; - - clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu)); + clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu)); }
static void __secure sunxi_cpu_power_off(u32 cpuid) diff --git a/arch/arm/include/asm/arch-sunxi/cpucfg.h b/arch/arm/include/asm/arch-sunxi/cpucfg.h deleted file mode 100644 index 4aaebe0a97..0000000000 --- a/arch/arm/include/asm/arch-sunxi/cpucfg.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Sunxi A31 CPUCFG register definition. - * - * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com - */ - -#ifndef _SUNXI_CPUCFG_H -#define _SUNXI_CPUCFG_H - -#include <linux/compiler.h> -#include <linux/types.h> - -#ifndef __ASSEMBLY__ - -struct __packed sunxi_cpucfg_cpu { - u32 rst; /* base + 0x0 */ - u32 ctrl; /* base + 0x4 */ - u32 status; /* base + 0x8 */ - u8 res[0x34]; /* base + 0xc */ -}; - -struct __packed sunxi_cpucfg_reg { - u8 res0[0x40]; /* 0x000 */ - struct sunxi_cpucfg_cpu cpu[4]; /* 0x040 */ - u8 res1[0x44]; /* 0x140 */ - u32 gen_ctrl; /* 0x184 */ - u32 l2_status; /* 0x188 */ - u8 res2[0x4]; /* 0x18c */ - u32 event_in; /* 0x190 */ - u8 res3[0xc]; /* 0x194 */ - u32 super_standy_flag; /* 0x1a0 */ - u32 priv0; /* 0x1a4 */ - u32 priv1; /* 0x1a8 */ - u8 res4[0x4]; /* 0x1ac */ - u32 cpu1_pwr_clamp; /* 0x1b0 sun7i only */ - u32 cpu1_pwroff; /* 0x1b4 sun7i only */ - u8 res5[0x2c]; /* 0x1b8 */ - u32 dbg_ctrl1; /* 0x1e4 */ - u8 res6[0x18]; /* 0x1e8 */ - u32 idle_cnt0_low; /* 0x200 */ - u32 idle_cnt0_high; /* 0x204 */ - u32 idle_cnt0_ctrl; /* 0x208 */ - u8 res8[0x4]; /* 0x20c */ - u32 idle_cnt1_low; /* 0x210 */ - u32 idle_cnt1_high; /* 0x214 */ - u32 idle_cnt1_ctrl; /* 0x218 */ - u8 res9[0x4]; /* 0x21c */ - u32 idle_cnt2_low; /* 0x220 */ - u32 idle_cnt2_high; /* 0x224 */ - u32 idle_cnt2_ctrl; /* 0x228 */ - u8 res10[0x4]; /* 0x22c */ - u32 idle_cnt3_low; /* 0x230 */ - u32 idle_cnt3_high; /* 0x234 */ - u32 idle_cnt3_ctrl; /* 0x238 */ - u8 res11[0x4]; /* 0x23c */ - u32 idle_cnt4_low; /* 0x240 */ - u32 idle_cnt4_high; /* 0x244 */ - u32 idle_cnt4_ctrl; /* 0x248 */ - u8 res12[0x34]; /* 0x24c */ - u32 cnt64_ctrl; /* 0x280 */ - u32 cnt64_low; /* 0x284 */ - u32 cnt64_high; /* 0x288 */ -}; - -#endif /* __ASSEMBLY__ */ -#endif /* _SUNXI_CPUCFG_H */

On Wed, 11 Oct 2023 19:47:55 -0600 Sam Edwards cfsworks@gmail.com wrote:
Since the sunxi support nowadays generally prefers #defined register offsets instead of modeling register layouts using C structs, now is a good time to do this for PSCI as well. This patch moves away from using the structs `sunxi_cpucfg_reg` and `sunxi_prcm_reg` in psci.c.
The former struct and its associated header file existed only to support PSCI code, so also delete them altogether.
Signed-off-by: Sam Edwards CFSworks@gmail.com
Thanks for doing this!
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre
arch/arm/cpu/armv7/sunxi/psci.c | 57 ++++++++------------ arch/arm/include/asm/arch-sunxi/cpucfg.h | 67 ------------------------ 2 files changed, 23 insertions(+), 101 deletions(-) delete mode 100644 arch/arm/include/asm/arch-sunxi/cpucfg.h
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 27ca9c39e1..207aa6bc4b 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -11,8 +11,6 @@ #include <asm/cache.h>
#include <asm/arch/cpu.h> -#include <asm/arch/cpucfg.h> -#include <asm/arch/prcm.h> #include <asm/armv7.h> #include <asm/gic.h> #include <asm/io.h> @@ -27,6 +25,17 @@ #define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET) #define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
+/*
- Offsets into the CPUCFG block applicable to most SUNXIs.
- */
+#define SUNXI_CPU_RST(cpu) (0x40 + (cpu) * 0x40 + 0x0) +#define SUNXI_CPU_STATUS(cpu) (0x40 + (cpu) * 0x40 + 0x8) +#define SUNXI_GEN_CTRL (0x184) +#define SUNXI_PRIV0 (0x1a4) +#define SUN7I_CPU1_PWR_CLAMP (0x1b0) +#define SUN7I_CPU1_PWROFF (0x1b4) +#define SUNXI_DBG_CTRL1 (0x1e4)
/*
- R40 is different from other single cluster SoCs.
@@ -99,10 +108,7 @@ static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry) writel((u32)entry, SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); } else {
struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
writel((u32)entry, &cpucfg->priv0);
}writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0);
}
@@ -110,26 +116,21 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) { u32 *clamp = NULL; u32 *pwroff;
struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
/* sun7i (A20) is different from other single cluster SoCs */ if (IS_ENABLED(CONFIG_MACH_SUN7I)) {
clamp = &cpucfg->cpu1_pwr_clamp;
pwroff = &cpucfg->cpu1_pwroff;
clamp = (void *)SUNXI_CPUCFG_BASE + SUN7I_CPU1_PWR_CLAMP;
cpu = 0; } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {pwroff = (void *)SUNXI_CPUCFG_BASE + SUN7I_CPU1_PWROFF;
clamp = (void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu);
pwroff = (void *)cpucfg + SUN8I_R40_PWROFF;
clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu);
} else {pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF;
struct sunxi_prcm_reg *prcm =
(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
- if (IS_ENABLED(CONFIG_MACH_SUN6I) || IS_ENABLED(CONFIG_MACH_SUN8I_H3))
clamp = &prcm->cpu_pwr_clamp[cpu];
clamp = (void *)SUNXI_PRCM_BASE + 0x140 + cpu * 0x4;
pwroff = &prcm->cpu_pwroff;
pwroff = (void *)SUNXI_PRCM_BASE + 0x100;
}
if (on) {
@@ -151,37 +152,25 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
static void __secure sunxi_cpu_set_reset(int cpu, bool reset) {
- struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
- writel(reset ? 0b00 : 0b11, &cpucfg->cpu[cpu].rst);
- writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu));
}
static void __secure sunxi_cpu_set_locking(int cpu, bool lock) {
- struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
- if (lock)
clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
elseclrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu));
setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
setbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu));
}
static bool __secure sunxi_cpu_poll_wfi(int cpu) {
- struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
- return !!(readl(&cpucfg->cpu[cpu].status) & BIT(2));
- return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2));
}
static void __secure sunxi_cpu_invalidate_cache(int cpu) {
- struct sunxi_cpucfg_reg *cpucfg =
(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
- clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
- clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu));
}
static void __secure sunxi_cpu_power_off(u32 cpuid) diff --git a/arch/arm/include/asm/arch-sunxi/cpucfg.h b/arch/arm/include/asm/arch-sunxi/cpucfg.h deleted file mode 100644 index 4aaebe0a97..0000000000 --- a/arch/arm/include/asm/arch-sunxi/cpucfg.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/*
- Sunxi A31 CPUCFG register definition.
- (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com
- */
-#ifndef _SUNXI_CPUCFG_H -#define _SUNXI_CPUCFG_H
-#include <linux/compiler.h> -#include <linux/types.h>
-#ifndef __ASSEMBLY__
-struct __packed sunxi_cpucfg_cpu {
- u32 rst; /* base + 0x0 */
- u32 ctrl; /* base + 0x4 */
- u32 status; /* base + 0x8 */
- u8 res[0x34]; /* base + 0xc */
-};
-struct __packed sunxi_cpucfg_reg {
- u8 res0[0x40]; /* 0x000 */
- struct sunxi_cpucfg_cpu cpu[4]; /* 0x040 */
- u8 res1[0x44]; /* 0x140 */
- u32 gen_ctrl; /* 0x184 */
- u32 l2_status; /* 0x188 */
- u8 res2[0x4]; /* 0x18c */
- u32 event_in; /* 0x190 */
- u8 res3[0xc]; /* 0x194 */
- u32 super_standy_flag; /* 0x1a0 */
- u32 priv0; /* 0x1a4 */
- u32 priv1; /* 0x1a8 */
- u8 res4[0x4]; /* 0x1ac */
- u32 cpu1_pwr_clamp; /* 0x1b0 sun7i only */
- u32 cpu1_pwroff; /* 0x1b4 sun7i only */
- u8 res5[0x2c]; /* 0x1b8 */
- u32 dbg_ctrl1; /* 0x1e4 */
- u8 res6[0x18]; /* 0x1e8 */
- u32 idle_cnt0_low; /* 0x200 */
- u32 idle_cnt0_high; /* 0x204 */
- u32 idle_cnt0_ctrl; /* 0x208 */
- u8 res8[0x4]; /* 0x20c */
- u32 idle_cnt1_low; /* 0x210 */
- u32 idle_cnt1_high; /* 0x214 */
- u32 idle_cnt1_ctrl; /* 0x218 */
- u8 res9[0x4]; /* 0x21c */
- u32 idle_cnt2_low; /* 0x220 */
- u32 idle_cnt2_high; /* 0x224 */
- u32 idle_cnt2_ctrl; /* 0x228 */
- u8 res10[0x4]; /* 0x22c */
- u32 idle_cnt3_low; /* 0x230 */
- u32 idle_cnt3_high; /* 0x234 */
- u32 idle_cnt3_ctrl; /* 0x238 */
- u8 res11[0x4]; /* 0x23c */
- u32 idle_cnt4_low; /* 0x240 */
- u32 idle_cnt4_high; /* 0x244 */
- u32 idle_cnt4_ctrl; /* 0x248 */
- u8 res12[0x34]; /* 0x24c */
- u32 cnt64_ctrl; /* 0x280 */
- u32 cnt64_low; /* 0x284 */
- u32 cnt64_high; /* 0x288 */
-};
-#endif /* __ASSEMBLY__ */ -#endif /* _SUNXI_CPUCFG_H */

This patch adds the necessary code to make nonsec booting and PSCI secondary core management functional on the R528/T113.
Signed-off-by: Sam Edwards CFSworks@gmail.com Tested-by: Maksim Kiselev bigunclemax@gmail.com Tested-by: Kevin Amadiva kevin.amadiva@mec.at --- arch/arm/cpu/armv7/Kconfig | 3 ++- arch/arm/cpu/armv7/sunxi/psci.c | 47 ++++++++++++++++++++++++++++++++- arch/arm/mach-sunxi/Kconfig | 4 +++ 3 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig index f015d133cb..4eb34b7b44 100644 --- a/arch/arm/cpu/armv7/Kconfig +++ b/arch/arm/cpu/armv7/Kconfig @@ -61,8 +61,9 @@ config ARMV7_SECURE_MAX_SIZE config ARM_GIC_BASE_ADDRESS hex depends on ARMV7_NONSEC - depends on ARCH_EXYNOS5 + depends on ARCH_EXYNOS5 || MACH_SUN8I_R528 default 0x10480000 if ARCH_EXYNOS5 + default 0x03020000 if MACH_SUN8I_R528 help Override the GIC base address if the Arm Cortex defined CBAR/PERIPHBASE system register holds the wrong value. diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 207aa6bc4b..b03a865483 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -47,6 +47,19 @@ #define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4) #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
+/* + * R528 is also different, as it has both cores powered up (but held in reset + * state) after the SoC is reset. Like the R40, it uses a "soft" entry point + * address register, but unlike the R40, it uses a newer "CPUX" block to manage + * CPU state, rather than the older CPUCFG system. + */ +#define SUN8I_R528_SOFT_ENTRY (0x1c8) +#define SUN8I_R528_C0_RST_CTRL (0x0000) +#define SUN8I_R528_C0_CTRL_REG0 (0x0010) +#define SUN8I_R528_C0_CPU_STATUS (0x0080) + +#define SUN8I_R528_C0_STATUS_STANDBYWFI (16) + static void __secure cp15_write_cntp_tval(u32 tval) { asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); @@ -103,10 +116,12 @@ static void __secure clamp_set(u32 *clamp)
static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry) { - /* secondary core entry address is programmed differently on R40 */ if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { writel((u32)entry, SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); + } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) { + writel((u32)entry, + SUNXI_R_CPUCFG_BASE + SUN8I_R528_SOFT_ENTRY); } else { writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0); } @@ -125,6 +140,9 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu); pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF; + } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) { + /* R528 leaves both cores powered up, manages them via reset */ + return; } else { if (IS_ENABLED(CONFIG_MACH_SUN6I) || IS_ENABLED(CONFIG_MACH_SUN8I_H3)) @@ -152,11 +170,27 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
static void __secure sunxi_cpu_set_reset(int cpu, bool reset) { + if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) { + if (reset) + clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL, + BIT(cpu)); + else + setbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL, + BIT(cpu)); + + return; + } + writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu)); }
static void __secure sunxi_cpu_set_locking(int cpu, bool lock) { + if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) { + /* Not required on R528 */ + return; + } + if (lock) clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu)); else @@ -165,11 +199,22 @@ static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
static bool __secure sunxi_cpu_poll_wfi(int cpu) { + if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) { + return !!(readl(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CPU_STATUS) & + BIT(SUN8I_R528_C0_STATUS_STANDBYWFI + cpu)); + } + return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2)); }
static void __secure sunxi_cpu_invalidate_cache(int cpu) { + if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) { + clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CTRL_REG0, + BIT(cpu)); + return; + } + clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu)); }
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index e891e291f1..23b5b27b97 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -355,6 +355,10 @@ config MACH_SUN8I_R40 config MACH_SUN8I_R528 bool "sun8i (Allwinner R528)" select CPU_V7A + select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_VIRT + select ARCH_SUPPORT_PSCI + select SPL_ARMV7_SET_CORTEX_SMPEN select SUNXI_GEN_NCAT2 select SUNXI_NEW_PINCTRL select MMC_SUNXI_HAS_NEW_MODE

On Wed, 11 Oct 2023 19:47:56 -0600 Sam Edwards cfsworks@gmail.com wrote:
This patch adds the necessary code to make nonsec booting and PSCI secondary core management functional on the R528/T113.
Signed-off-by: Sam Edwards CFSworks@gmail.com Tested-by: Maksim Kiselev bigunclemax@gmail.com Tested-by: Kevin Amadiva kevin.amadiva@mec.at
Thanks, that looks good now. It's debatable whether the Kconfig depends on should be NCAT2 instead, but we can fix this when the need arises.
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre
arch/arm/cpu/armv7/Kconfig | 3 ++- arch/arm/cpu/armv7/sunxi/psci.c | 47 ++++++++++++++++++++++++++++++++- arch/arm/mach-sunxi/Kconfig | 4 +++ 3 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig index f015d133cb..4eb34b7b44 100644 --- a/arch/arm/cpu/armv7/Kconfig +++ b/arch/arm/cpu/armv7/Kconfig @@ -61,8 +61,9 @@ config ARMV7_SECURE_MAX_SIZE config ARM_GIC_BASE_ADDRESS hex depends on ARMV7_NONSEC
- depends on ARCH_EXYNOS5
- depends on ARCH_EXYNOS5 || MACH_SUN8I_R528 default 0x10480000 if ARCH_EXYNOS5
- default 0x03020000 if MACH_SUN8I_R528 help Override the GIC base address if the Arm Cortex defined CBAR/PERIPHBASE system register holds the wrong value.
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 207aa6bc4b..b03a865483 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -47,6 +47,19 @@ #define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4) #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
+/*
- R528 is also different, as it has both cores powered up (but held in reset
- state) after the SoC is reset. Like the R40, it uses a "soft" entry point
- address register, but unlike the R40, it uses a newer "CPUX" block to manage
- CPU state, rather than the older CPUCFG system.
- */
+#define SUN8I_R528_SOFT_ENTRY (0x1c8) +#define SUN8I_R528_C0_RST_CTRL (0x0000) +#define SUN8I_R528_C0_CTRL_REG0 (0x0010) +#define SUN8I_R528_C0_CPU_STATUS (0x0080)
+#define SUN8I_R528_C0_STATUS_STANDBYWFI (16)
static void __secure cp15_write_cntp_tval(u32 tval) { asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); @@ -103,10 +116,12 @@ static void __secure clamp_set(u32 *clamp)
static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry) {
- /* secondary core entry address is programmed differently on R40 */ if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { writel((u32)entry, SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
- } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
writel((u32)entry,
} else { writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0); }SUNXI_R_CPUCFG_BASE + SUN8I_R528_SOFT_ENTRY);
@@ -125,6 +140,9 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu); pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF;
- } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
/* R528 leaves both cores powered up, manages them via reset */
} else { if (IS_ENABLED(CONFIG_MACH_SUN6I) || IS_ENABLED(CONFIG_MACH_SUN8I_H3))return;
@@ -152,11 +170,27 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
static void __secure sunxi_cpu_set_reset(int cpu, bool reset) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
if (reset)
clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL,
BIT(cpu));
else
setbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL,
BIT(cpu));
return;
- }
- writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu));
}
static void __secure sunxi_cpu_set_locking(int cpu, bool lock) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
/* Not required on R528 */
return;
- }
- if (lock) clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu)); else
@@ -165,11 +199,22 @@ static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
static bool __secure sunxi_cpu_poll_wfi(int cpu) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
return !!(readl(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CPU_STATUS) &
BIT(SUN8I_R528_C0_STATUS_STANDBYWFI + cpu));
- }
- return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2));
}
static void __secure sunxi_cpu_invalidate_cache(int cpu) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CTRL_REG0,
BIT(cpu));
return;
- }
- clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu));
}
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index e891e291f1..23b5b27b97 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -355,6 +355,10 @@ config MACH_SUN8I_R40 config MACH_SUN8I_R528 bool "sun8i (Allwinner R528)" select CPU_V7A
- select CPU_V7_HAS_NONSEC
- select CPU_V7_HAS_VIRT
- select ARCH_SUPPORT_PSCI
- select SPL_ARMV7_SET_CORTEX_SMPEN select SUNXI_GEN_NCAT2 select SUNXI_NEW_PINCTRL select MMC_SUNXI_HAS_NEW_MODE

On Sun, 22 Oct 2023 01:49:49 +0100 Andre Przywara andre.przywara@arm.com wrote:
On Wed, 11 Oct 2023 19:47:56 -0600 Sam Edwards cfsworks@gmail.com wrote:
This patch adds the necessary code to make nonsec booting and PSCI secondary core management functional on the R528/T113.
Signed-off-by: Sam Edwards CFSworks@gmail.com Tested-by: Maksim Kiselev bigunclemax@gmail.com Tested-by: Kevin Amadiva kevin.amadiva@mec.at
Thanks, that looks good now. It's debatable whether the Kconfig depends on should be NCAT2 instead, but we can fix this when the need arises.
Reviewed-by: Andre Przywara andre.przywara@arm.com
For the records, this patch was missing the definition of SUNXI_R_CPUCFG_BASE, which broke the build of all other 32-bit sunxi boards. I fixed that here: https://lore.kernel.org/u-boot/20231023132449.813863-24-andre.przywara@arm.c... and this version was also merged.
Cheers, Andre
arch/arm/cpu/armv7/Kconfig | 3 ++- arch/arm/cpu/armv7/sunxi/psci.c | 47 ++++++++++++++++++++++++++++++++- arch/arm/mach-sunxi/Kconfig | 4 +++ 3 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig index f015d133cb..4eb34b7b44 100644 --- a/arch/arm/cpu/armv7/Kconfig +++ b/arch/arm/cpu/armv7/Kconfig @@ -61,8 +61,9 @@ config ARMV7_SECURE_MAX_SIZE config ARM_GIC_BASE_ADDRESS hex depends on ARMV7_NONSEC
- depends on ARCH_EXYNOS5
- depends on ARCH_EXYNOS5 || MACH_SUN8I_R528 default 0x10480000 if ARCH_EXYNOS5
- default 0x03020000 if MACH_SUN8I_R528 help Override the GIC base address if the Arm Cortex defined CBAR/PERIPHBASE system register holds the wrong value.
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 207aa6bc4b..b03a865483 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -47,6 +47,19 @@ #define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4) #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
+/*
- R528 is also different, as it has both cores powered up (but held in reset
- state) after the SoC is reset. Like the R40, it uses a "soft" entry point
- address register, but unlike the R40, it uses a newer "CPUX" block to manage
- CPU state, rather than the older CPUCFG system.
- */
+#define SUN8I_R528_SOFT_ENTRY (0x1c8) +#define SUN8I_R528_C0_RST_CTRL (0x0000) +#define SUN8I_R528_C0_CTRL_REG0 (0x0010) +#define SUN8I_R528_C0_CPU_STATUS (0x0080)
+#define SUN8I_R528_C0_STATUS_STANDBYWFI (16)
static void __secure cp15_write_cntp_tval(u32 tval) { asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); @@ -103,10 +116,12 @@ static void __secure clamp_set(u32 *clamp)
static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry) {
- /* secondary core entry address is programmed differently on R40 */ if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { writel((u32)entry, SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
- } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
writel((u32)entry,
} else { writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0); }SUNXI_R_CPUCFG_BASE + SUN8I_R528_SOFT_ENTRY);
@@ -125,6 +140,9 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) { clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu); pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF;
- } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
/* R528 leaves both cores powered up, manages them via reset */
} else { if (IS_ENABLED(CONFIG_MACH_SUN6I) || IS_ENABLED(CONFIG_MACH_SUN8I_H3))return;
@@ -152,11 +170,27 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
static void __secure sunxi_cpu_set_reset(int cpu, bool reset) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
if (reset)
clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL,
BIT(cpu));
else
setbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL,
BIT(cpu));
return;
- }
- writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu));
}
static void __secure sunxi_cpu_set_locking(int cpu, bool lock) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
/* Not required on R528 */
return;
- }
- if (lock) clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu)); else
@@ -165,11 +199,22 @@ static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
static bool __secure sunxi_cpu_poll_wfi(int cpu) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
return !!(readl(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CPU_STATUS) &
BIT(SUN8I_R528_C0_STATUS_STANDBYWFI + cpu));
- }
- return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2));
}
static void __secure sunxi_cpu_invalidate_cache(int cpu) {
- if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CTRL_REG0,
BIT(cpu));
return;
- }
- clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu));
}
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index e891e291f1..23b5b27b97 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -355,6 +355,10 @@ config MACH_SUN8I_R40 config MACH_SUN8I_R528 bool "sun8i (Allwinner R528)" select CPU_V7A
- select CPU_V7_HAS_NONSEC
- select CPU_V7_HAS_VIRT
- select ARCH_SUPPORT_PSCI
- select SPL_ARMV7_SET_CORTEX_SMPEN select SUNXI_GEN_NCAT2 select SUNXI_NEW_PINCTRL select MMC_SUNXI_HAS_NEW_MODE

On Wed, 11 Oct 2023 19:47:52 -0600 Sam Edwards cfsworks@gmail.com wrote:
Hi Sam,
Hi list,
This is the third, and hopefully final, version of my patchset for PSCI support on R528/T113-s3. This one, as always, depends on Andre Przywara's T113s support series (v2), available on the list and also located on a Git branch at: https://source.denx.de/u-boot/custodians/u-boot-sunxi.git t113s-v2
NOTE THAT THIS ALSO depends on the following commit on master: 3d5e52bd97 ("ARM: psci: move GIC address override to Kconfig")
For testing: I can confirm that patch 2/4 results in no change to machine code whatsoever on any supported target. Patch 1/4 results in a minor machine code change on R40 only. Patch 3/4 will likely require testing on each of the 4 "special case" sunxi targets (sun6i, sun7i, R40, H3) to ensure that register offsets are kept consistent. Patch 4/4 needs testing on R528 only.
For now I have included this series into the T113s support series and pushed this to sunxi/master, to trigger the CI.
I will do some final testing here on the MangoPi and other boards (for regressions), but I am hopeful to send a pull request in the next day to two.
Thanks again for your persistent work on this, much appreciated!
Cheers, Andre
Warm regards, Sam
Changes v3->v4:
- The GIC base address override is done through Kconfig, instead of in sunxi-common.h
Changes v2->v3:
- Fix missing `cpu=0;` for the sun7i power management case.
- Make sunxi_cpu_power_off() a static function, per feedback on v2.
- Kevin Amadiva of MEC electronics got in touch with me off-list,
reported success bringing up CPU1 of a T113 with this patchset, and kindly provided me with a Tested-by tag for patch 4/4.
- Remove a comment about R40/R528 being special, per feedback on v2.
- Simplify an if statement, per feedback on v2.
- Add missing 'select' directives to the R528 Kconfig, per feedback
on v2.
Changes v1->v2:
- Power clamp is now adjusted ONLY on sun{6,7}i, H3, R40. The
previous version was mistakenly doing this EXCEPT on those machines.
- Flattened sunxi_power_switch() into sunxi_cpu_set_power() for
simplicity's sake.
- Moved the "power clamp is not NULL" conditional into
sunxi_cpu_set_power().
- Removed unnecessary H6 special-case, since H6 is actually ARM64.
- Renamed SUNXI_CPUX_BASE to SUNXI_CPUCFG_BASE, to mirror expected
changes in Andre's v2 of the R528 series (we decided against using a new name for this block).
- Removed sunxi_cpucfg_reg struct, and stopped using the PRCM struct
in psci.c.
Sam Edwards (4): sunxi: psci: clean away preprocessor macros sunxi: psci: refactor register access to separate functions sunxi: psci: stop modeling register layout with C structs sunxi: psci: implement PSCI on R528
arch/arm/cpu/armv7/Kconfig | 3 +- arch/arm/cpu/armv7/sunxi/psci.c | 185 ++++++++++++++--------- arch/arm/include/asm/arch-sunxi/cpucfg.h | 67 -------- arch/arm/mach-sunxi/Kconfig | 4 + 4 files changed, 121 insertions(+), 138 deletions(-) delete mode 100644 arch/arm/include/asm/arch-sunxi/cpucfg.h
participants (2)
-
Andre Przywara
-
Sam Edwards