Re: [RFC PATCH 10/17] clk: sunxi: Add support for the D1 CCU

Sam Edwards
2023-05-26T20:22:41Z

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/6ea4ae4ad7a558ad952fefee1942e260aea1a69f/linux/second_core_support_in_platsmp.patch#L10
>
> 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