
Hi folks,
On 5/26/23 13:27, Maksim Kiselev wrote:
There is a Linux patch that allows to bring up the second core. https://github.com/szemzoa/awboot/blob/6ea4ae4ad7a558ad952fefee1942e260aea1a...
I think this could be useful for adding PSCI support for T113.
I'm a little surprised that apparently all that is necessary is to set the entry point and deassert reset. I've been trying essentially that so far with no success (entirely possible I made a mistake somewhere). Perhaps this patch assumes that power to the core is enabled before kernel boot? I haven't yet figured out what in the PRCM I need to poke to get power to the core, and the PRCM for this chip is not well-documented.
On 5/26/23 04:50, Andre Przywara wrote:
I checked the manuals, and it seems the required bits are documented, but IIRC they differ from the other (much older) 32-bit parts. So it would require some refactoring of the existing sunxi PSCI code to accommodate the T113.
Yeah, I decided to factor out the register-manipulating bits to a handful of sunxi_cpu_set_* functions, which can be switched out to suit the specific SoC in use. psci.c is growing way too many #ifdef branches, so I might refactor this yet again to the "weak symbols with strong overrides in e.g. psci-r528.c" pattern, unless you find that pattern particularly distasteful.
I have my WIP diff below. Before inclusion, I'll split it into multiple patches (refactoring -> adding R528 support) but it's definitely not ready for that yet. However if you could, it would help if you checked my changes to cpu_sunxi_ncat2.h and squashed them into your own series if they look good to you.
Cheers, Sam
--- diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index e1d3638b5c..02c5c56c86 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -38,6 +38,8 @@ #define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4) #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
+#define SUN8I_R528_SOFT_ENTRY (0x1c8) + static void __secure cp15_write_cntp_tval(u32 tval) { asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); @@ -125,6 +127,13 @@ static void __secure sunxi_set_entry_address(void *entry) writel((u32)entry, SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); } +#elif defined CONFIG_MACH_SUN8I_R528 +/* secondary core entry address is programmed differently on R528 */ +static void __secure sunxi_set_entry_address(void *entry) +{ + writel((u32)entry, + SUNXI_R_CPUCFG_BASE + SUN8I_R528_SOFT_ENTRY); +} #else static void __secure sunxi_set_entry_address(void *entry) { @@ -155,6 +164,10 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) (void *)cpucfg + SUN8I_R40_PWROFF, on, cpu); } +#elif defined CONFIG_MACH_SUN8I_R528 +static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool __always_unused on) +{ +} #else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */ static void __secure sunxi_cpu_set_power(int cpu, bool on) { @@ -166,30 +179,91 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on) } #endif /* CONFIG_MACH_SUN7I */
-void __secure sunxi_cpu_power_off(u32 cpuid) +#ifdef CONFIG_MACH_SUN8I_R528 +#define C0_RST_CTRL 0x0000 +#define C0_CTRL_REG0 0x0010 +#define C0_CPU_STATUS 0x0080 + +#define C0_BIT_WFI 16 + +static void __secure sunxi_cpu_set_reset(int cpu, bool active) +{ + if (active) + clrbits_le32(SUNXI_CPUX_BASE + C0_RST_CTRL, BIT(cpu)); + else + setbits_le32(SUNXI_CPUX_BASE + C0_RST_CTRL, BIT(cpu)); +} + +static void __secure sunxi_cpu_set_locking(int cpu, bool lock) +{ + /* TODO: I don't know what this is or how to do it */ +} + +static bool __secure sunxi_cpu_poll_wfi(int cpu) +{ + return !!(readl(SUNXI_CPUX_BASE + C0_CPU_STATUS) & BIT(C0_BIT_WFI + cpu)); +} + +static void __secure sunxi_cpu_invalidate_cache(int cpu) +{ + clrbits_le32(SUNXI_CPUX_BASE + C0_CTRL_REG0, BIT(cpu)); +} +#else /* ! CONFIG_MACH_SUN8I_R528 */ +static void __secure sunxi_cpu_set_reset(int cpu, bool active) +{ + struct sunxi_cpucfg_reg *cpucfg = + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + + writel(active ? 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)); +} +#endif + +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) @@ -246,8 +320,6 @@ 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 */ @@ -257,22 +329,22 @@ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc, sunxi_set_entry_address(&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; } 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 d01508517c..629d761aa6 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h @@ -17,6 +17,8 @@ #define SUNXI_SIDC_BASE 0x03006000 #define SUNXI_SID_BASE 0x03006200 #define SUNXI_TIMER_BASE 0x02050000 +#define SUNXI_GIC400_BASE 0x03020000 +#define SUNXI_CPUX_BASE 0x09010000
#ifdef CONFIG_MACH_SUN50I_H6 #define SUNXI_DRAM_COM_BASE 0x04002000 @@ -34,11 +36,11 @@ #define SUNXI_SPI0_BASE 0x04025000 #define SUNXI_SPI1_BASE 0x04026000
-#define SUNXI_RTC_BASE 0x07000000 #define SUNXI_R_CPUCFG_BASE 0x07000400 #define SUNXI_PRCM_BASE 0x07010000 #define SUNXI_R_WDOG_BASE 0x07020400 -#define SUNXI_R_TWI_BASE 0x07081400 +#define SUNXI_R_TWI_BASE 0x07020800 +#define SUNXI_RTC_BASE 0x07090000
#ifndef __ASSEMBLY__ void sunxi_board_init(void); diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index bb9b863d2c..a5d312d377 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -366,6 +366,8 @@ config MACH_SUN8I_R40 config MACH_SUN8I_R528 bool "sun8i (Allwinner R528)" select CPU_V7A + select CPU_V7_HAS_NONSEC + select ARCH_SUPPORT_PSCI select SUNXI_GEN_NCAT2 select SUNXI_NEW_PINCTRL select MMC_SUNXI_HAS_NEW_MODE