From mboxrd@z Thu Jan 1 00:00:00 1970 From: Chen-Yu Tsai Date: Wed, 7 Jun 2017 12:53:34 +0800 Subject: [U-Boot] [linux-sunxi] [RFC PATCH 7/8] sunxi: Add basic PSCI implementation for multi-cluster SoCs In-Reply-To: <20170607004721.24194-8-icenowy@aosc.io> References: <20170607004721.24194-1-icenowy@aosc.io> <20170607004721.24194-8-icenowy@aosc.io> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On Wed, Jun 7, 2017 at 8:47 AM, Icenowy Zheng wrote: > From: Chen-Yu Tsai > > Allwinner A80 and A83T SoCs have two clusters of CPU, each cluster > contains 4 cores. A80 is Cortex-A15 + Cortex-A7 configuration, while > A83T has two clusters of Cortex-A7. > > This patch adds a basic version that allows bringing up the four cores > in the first cluster. The structure is based on existing sunxi PSCI code. > > Signed-off-by: Chen-Yu Tsai > [Icenowy: adapt for A83T] > Signed-off-by: Icenowy Zheng > --- > arch/arm/cpu/armv7/sunxi/Makefile | 4 + > arch/arm/cpu/armv7/sunxi/psci-mcpm.c | 258 +++++++++++++++++++++++++++++++++++ > 2 files changed, 262 insertions(+) > create mode 100644 arch/arm/cpu/armv7/sunxi/psci-mcpm.c > I suggest using --find-copies and --find-copies-harder when you generate the patch. It should limit the patch to differences between psci.c and psci-mcpm.c. > diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile > index 8c026ff052..c789f686fd 100644 > --- a/arch/arm/cpu/armv7/sunxi/Makefile > +++ b/arch/arm/cpu/armv7/sunxi/Makefile > @@ -14,8 +14,12 @@ obj-$(CONFIG_MACH_SUN8I_H3) += tzpc.o > obj-$(CONFIG_MACH_SUN8I_A83T) += tzpc.o > > ifndef CONFIG_SPL_BUILD > +ifdef CONFIG_MACH_SUN8I_A83T > +obj-$(CONFIG_ARMV7_PSCI) += psci-mcpm.o > +else > obj-$(CONFIG_ARMV7_PSCI) += psci.o > endif > +endif > > ifdef CONFIG_SPL_BUILD > obj-y += fel_utils.o > diff --git a/arch/arm/cpu/armv7/sunxi/psci-mcpm.c b/arch/arm/cpu/armv7/sunxi/psci-mcpm.c > new file mode 100644 > index 0000000000..ba8d669c7e > --- /dev/null > +++ b/arch/arm/cpu/armv7/sunxi/psci-mcpm.c > @@ -0,0 +1,258 @@ > +/* > + * Copyright (C) 2016 > + * Author: Chen-Yu Tsai > + * > + * Based on assembly code by Marc Zyngier , > + * which was based on code by Carl van Schaik . > + * > + * SPDX-License-Identifier: GPL-2.0 > + */ > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +/* > + * NOTE dense CPU IDs (0~3 for first cluster of 4 cores, 4~7 for the > + * second cluster) are used throughout the PSCI code. Any MPIDR style > + * values must be converted. > + */ > + > +/* > + * Provide a dense CPU ID for 2-cluster systems. This must be coded in > + * assembly as it gets called from psci_stack_setup, when the stack isn't > + * available yet. > + * > + * Only r0 and r3 is usable. r8 - r12 are available if this function is > + * only called from psci_stack_setup, which we cannot guarantee. > + */ > +u32 __secure __naked psci_get_cpu_id(void) > +{ > + asm volatile ( > + "mrc p15, 0, r3, c0, c0, 5 @ Get MPIDR\n" > + "lsr r0, r3, #6\n" > + "and r3, r3, #3\n" > + "and r0, r0, #4\n" > + "orr r0, r0, r3\n" > + "bx lr\n" > + ); > + > + /* > + * The last five lines are the compiler generated assembly code for > + * > + * return (reg & 0x3) | (((reg >> 8) & 0x1) << 2); > + * > + * We can't guarantee that all compilers correctly use only r0 and > + * r3, so we use inline assembly here. > + */ > +} > + > +static void __secure cp15_write_cntp_tval(u32 tval) > +{ > + asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); > +} > + > +static void __secure cp15_write_cntp_ctl(u32 val) > +{ > + asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val)); > +} > + > +static u32 __secure cp15_read_cntp_ctl(void) > +{ > + u32 val; > + > + asm volatile ("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); > + > + return val; > +} > + > +#define ONE_US (COUNTER_FREQUENCY / 1000000) > + > +/* Use a different name to avoid clashing with the non-secure function */ > +static void __secure __udelay_sec(unsigned long us) > +{ > + u32 reg = ONE_US * us; > + > + cp15_write_cntp_tval(reg); > + isb(); > + cp15_write_cntp_ctl(3); > + > + do { > + isb(); > + reg = cp15_read_cntp_ctl(); > + } while (!(reg & BIT(2))); > + > + cp15_write_cntp_ctl(0); > + isb(); > +} > + > +static void __secure clamp_release(u32 *clamp) > +{ > + writel(0xff, clamp); > + __udelay_sec(10); > + writel(0xfe, clamp); > + __udelay_sec(10); > + writel(0xf8, clamp); > + __udelay_sec(10); > + writel(0xf0, clamp); > + __udelay_sec(10); > + writel(0x00, clamp); > +} > + > +static void __secure clamp_set(u32 *clamp) > +{ > + writel(0xff, clamp); > +} > + > +static void __secure sunxi_core_power_switch(u32 *clamp, u32 *pwroff, > + bool on, int cpu) > +{ > + if (on) { > + /* Release power clamp */ > + clamp_release(clamp); > + > + __udelay_sec(20); > + > + /* Clear power gating */ > + clrbits_le32(pwroff, BIT(cpu)); > + } else { > + /* Set power gating */ > + setbits_le32(pwroff, BIT(cpu)); > + > + __udelay_sec(20); > + > + /* Activate power clamp */ > + clamp_set(clamp); > + } > +} > + > +static int __secure sunxi_cluster_is_a7(int cluster) > +{ > +#ifdef CONFIG_MACH_SUN8I_A83T > + return 1; > +#else > + return (clustter == 0); > +#endif > +} > + > +static void __secure sunxi_cpu_set_power(int cluster, int cpu, bool on) > +{ > + struct sunxi_prcm_reg *prcm = > + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; > + > + sunxi_core_power_switch(&prcm->cpu_pwr_clamp[cluster][cpu], > + &prcm->cpu_pwroff[cluster], on, cpu); > +} > + > +static u32 __secure cp15_read_scr(void) > +{ > + u32 scr; > + > + asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (scr)); > + > + return scr; > +} > + > +static void __secure cp15_write_scr(u32 scr) > +{ > + asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (scr)); > + isb(); > +} > + > +int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc) > +{ > + struct sunxi_cpucfg_reg *cpucfg = > + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; > +#ifdef CONFIG_MACH_SUN8I_A83T > + struct sunxi_r_cpucfg_reg *r_cpucfg = > + (struct sunxi_r_cpucfg_reg *)SUNXI_R_CPUCFG_BASE; > +#else > + struct sunxi_prcm_reg *prcm = > + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; > +#endif > + u32 cluster = (mpidr >> 8) & 0x1; > + u32 cpu = mpidr & 0x3; > + u32 cpuid = cpu | (cluster << 2); > + > + /* TODO We don't support multi-cluster yet */ > + if (cluster > 0) > + return ARM_PSCI_RET_INVAL; > + > + /* store target PC */ > + psci_save_target_pc(cpuid, pc); > + > + /* Set secondary core power on PC */ > +#ifdef CONFIG_MACH_SUN8I_A83T > + writel((u32)&psci_cpu_entry, &r_cpucfg->priv0); > +#else > + writel((u32)&psci_cpu_entry, &prcm->cpu_soft_entry); > +#endif Could you take a look at the non-MCPM version and move the #ifdefs into separate functions? Basically we want the main functions to be as clean and descriptive as possible. You could also structure it as two patches: the first adding the original A80 version, and the second modifying it to support the A83T as well. I'll send a fix for the non-MCPM version fixing the entry address. Regards ChenYu > + > + /* Assert power-on reset on target CPU */ > +#ifdef CONFIG_MACH_SUN8I_A83T > + clrbits_le32(&r_cpucfg->cpu_rst[cluster], BIT(cpu)); > +#else > + clrbits_le32(&prcm->cpu_rst[cluster], BIT(cpu)); > +#endif > + > + /* Cortex-A7: hold L1 cache reset disable signal low */ > + if (sunxi_cluster_is_a7(cluster)) > + clrbits_le32(&cpucfg->cluster[cluster].ctrl0, > + CPUCFG_CX_CTRL0_L1_RST_DISABLE(cpu)); > + > + /* Lock CPU (Disable external debug access) */ > + clrbits_le32(&cpucfg->cluster_reset[cluster], > + CPUCFG_CX_RST_DBG(cpu)); > + > + /* Cortex-A7: Assert ETM reset */ > + if (sunxi_cluster_is_a7(cluster)) > + clrbits_le32(&cpucfg->cluster_reset[cluster], > + CPUCFG_CX_RST_ETM(cpu)); > + > + /* > + * Allwinner code also asserts resets for NEON on A15. According > + * to ARM manuals, asserting power-on reset is sufficient. > + */ > + > + /* Power up target CPU */ > + sunxi_cpu_set_power(cluster, cpu, true); > + > + /* De-assert power-on reset on target CPU */ > +#ifdef CONFIG_MACH_SUN8I_A83T > + setbits_le32(&r_cpucfg->cpu_rst[cluster], BIT(cpu)); > +#else > + setbits_le32(&prcm->cpu_rst[cluster], BIT(cpu)); > +#endif > + > + /* De-assert core reset on target CPU */ > + setbits_le32(&cpucfg->cluster_reset[cluster], > + CPUCFG_CX_RST_CORE(cpu)); > + > + /* Cortex-A7: De-assert ETM reset */ > + if (sunxi_cluster_is_a7(cluster)) > + setbits_le32(&cpucfg->cluster_reset[cluster], > + CPUCFG_CX_RST_ETM(cpu)); > + > + /* Unlock CPU (Disable external debug access) */ > + setbits_le32(&cpucfg->cluster_reset[cluster], > + CPUCFG_CX_RST_DBG(cpu)); > + > + return ARM_PSCI_RET_SUCCESS; > +} > + > +void __secure psci_arch_init(void) > +{ > + u32 reg; > + > + reg = cp15_read_scr(); > + reg &= ~BIT(0); /* Secure mode */ > + cp15_write_scr(reg); > +} > -- > 2.12.2 > > -- > You received this message because you are subscribed to the Google Groups "linux-sunxi" group. > To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout.