[U-Boot] [PATCH 0/6] sunxi: sun5/7i: add the psci suspend function

Hi all,
This series adds an implementation of the psci suspend function for both sun5i and sun7i. This was tested on Nextthing's CHIP and on a A20, using cpuidle in Linux. My tests showed a power consumption reduced by a factor 2 on the CHIP when the system was idle. It went from ~1W without cpuidle enabled to ~0.45W.
The idea of this suspend function is to put the dram into self-refresh, cut off some plls and to switch cpuclk to a source with a lower frequency. Please note the sun7i implementation lacks some parts as putting the ram into self-refresh and coming back from this state seems a bit tricky. I made some tests but did not managed yet to have a stable solution.
As the sun5i does not have a GIC, I needed to remove some code from the generic psci code. To do this I added an ARM_GIC Kconfig option which needs to be selected by each SoC having a GIC. I already added the relevant lines regarding sunXi SoCs. As this Kconfig option is currently only used in the psci code, it should be safe to add it even of all the SoCs having a GIC do not select it, as long as they don't have psci functions.
Finally the series has a patch to enable the psci support for sun5i SoCs, and another patch to let sun5i SoCs boot the kernel in non-secure mode so that it can call psci functions.
Thanks!
Antoine
Antoine Tenart (6): ARM: add the ARM_GIC configuration option sunxi: select ARM_GIC for sun[6789]i ARM: PSCI: protect GIC specific code with ARM_GIC sun5/7i: add an implementation of the psci suspend function sun5i: enable PSCI sun5i: boot in HYP mode by default
arch/arm/Kconfig | 3 + arch/arm/cpu/armv7/nonsec_virt.S | 6 + arch/arm/cpu/armv7/sunxi/Makefile | 9 +- arch/arm/cpu/armv7/sunxi/psci_suspend.c | 175 ++++++++++++++++++++++++++ arch/arm/cpu/armv7/virt-v7.c | 38 +++--- arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 7 ++ arch/arm/include/asm/arch-sunxi/dram_sun4i.h | 11 ++ board/sunxi/Kconfig | 9 ++ include/configs/sun5i.h | 5 + 9 files changed, 248 insertions(+), 15 deletions(-) create mode 100644 arch/arm/cpu/armv7/sunxi/psci_suspend.c

Some SoC does not have a GIC. Adds a configuration option to denote this, allowing to remove code configuring the GIC when it's not possible.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com --- arch/arm/Kconfig | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c871eaf4e39a..dc3a99fc3251 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -13,6 +13,9 @@ config DMA_ADDR_T_64BIT bool default y if ARM64
+config ARM_GIC + bool + config HAS_VBAR bool

Select the newly introduced ARM_GIC option to the relevant sunxi MACH configurations.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com --- board/sunxi/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 1b30669230a3..c9b500e9390b 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -34,6 +34,7 @@ config MACH_SUN5I
config MACH_SUN6I bool "sun6i (Allwinner A31)" + select ARM_GIC select CPU_V7 select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT @@ -43,6 +44,7 @@ config MACH_SUN6I
config MACH_SUN7I bool "sun7i (Allwinner A20)" + select ARM_GIC select CPU_V7 select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT @@ -52,6 +54,7 @@ config MACH_SUN7I
config MACH_SUN8I_A23 bool "sun8i (Allwinner A23)" + select ARM_GIC select CPU_V7 select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT @@ -61,6 +64,7 @@ config MACH_SUN8I_A23
config MACH_SUN8I_A33 bool "sun8i (Allwinner A33)" + select ARM_GIC select CPU_V7 select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT @@ -70,12 +74,14 @@ config MACH_SUN8I_A33
config MACH_SUN8I_A83T bool "sun8i (Allwinner A83T)" + select ARM_GIC select CPU_V7 select SUNXI_GEN_SUN6I select SUPPORT_SPL
config MACH_SUN8I_H3 bool "sun8i (Allwinner H3)" + select ARM_GIC select CPU_V7 select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT @@ -85,6 +91,7 @@ config MACH_SUN8I_H3
config MACH_SUN9I bool "sun9i (Allwinner A80)" + select ARM_GIC select CPU_V7 select SUNXI_GEN_SUN6I

Introducing the ARM_GIC configuration option, use it to only use GIC specific code in ARM PSCI function when the SoC has a GIC.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com --- arch/arm/cpu/armv7/nonsec_virt.S | 6 ++++++ arch/arm/cpu/armv7/virt-v7.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index 95ce9387b83e..2a11d2e83b80 100644 --- a/arch/arm/cpu/armv7/nonsec_virt.S +++ b/arch/arm/cpu/armv7/nonsec_virt.S @@ -164,6 +164,7 @@ ENDPROC(_smp_pen) * though, but we check this in C before calling this function. */ ENTRY(_nonsec_init) +#ifdef CONFIG_ARM_GIC get_gicd_addr r3
mvn r1, #0 @ all bits to 1 @@ -175,6 +176,7 @@ ENTRY(_nonsec_init) str r1, [r3, #GICC_CTLR] @ and clear all other bits mov r1, #0xff str r1, [r3, #GICC_PMR] @ set priority mask register +#endif
mrc p15, 0, r0, c1, c1, 2 movw r1, #0x3fff @@ -200,7 +202,11 @@ ENTRY(_nonsec_init) mcr p15, 0, r1, c12, c0, 1 @ set MVBAR to secure vectors isb
+#ifdef CONFIG_ARM_GIC mov r0, r3 @ return GICC address +#else + mov r0, #0 +#endif bx lr ENDPROC(_nonsec_init)
diff --git a/arch/arm/cpu/armv7/virt-v7.c b/arch/arm/cpu/armv7/virt-v7.c index d33e5c61a9c2..925201e3f690 100644 --- a/arch/arm/cpu/armv7/virt-v7.c +++ b/arch/arm/cpu/armv7/virt-v7.c @@ -82,22 +82,11 @@ void __weak smp_kick_all_cpus(void) kick_secondary_cpus_gic(gic_dist_addr); }
-__weak void psci_board_init(void) -{ -} - -int armv7_init_nonsec(void) +#ifdef CONFIG_ARM_GIC +static void psci_gic_setup() { - unsigned int reg; - unsigned itlinesnr, i; unsigned long gic_dist_addr; - - /* check whether the CPU supports the security extensions */ - reg = read_id_pfr1(); - if ((reg & 0xF0) == 0) { - printf("nonsec: Security extensions not implemented.\n"); - return -1; - } + unsigned itlinesnr, i;
/* the SCR register will be set directly in the monitor mode handler, * according to the spec one should not tinker with it in secure state @@ -122,6 +111,27 @@ int armv7_init_nonsec(void) */ for (i = 1; i <= itlinesnr; i++) writel((unsigned)-1, gic_dist_addr + GICD_IGROUPRn + 4 * i); +} +#endif + +__weak void psci_board_init(void) +{ +} + +int armv7_init_nonsec(void) +{ + unsigned int reg; + + /* check whether the CPU supports the security extensions */ + reg = read_id_pfr1(); + if ((reg & 0xF0) == 0) { + printf("nonsec: Security extensions not implemented.\n"); + return -1; + } + +#ifdef CONFIG_ARM_GIC + psci_gic_setup(); +#endif
psci_board_init();

Hi,
On 01-09-16 09:57, Antoine Tenart wrote:
Introducing the ARM_GIC configuration option, use it to only use GIC specific code in ARM PSCI function when the SoC has a GIC.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com
AFAIK sunxi is not the only user of these files, so before you can do this you should also select ARM_GIC in the other users I believe.
Regards,
Hans
arch/arm/cpu/armv7/nonsec_virt.S | 6 ++++++ arch/arm/cpu/armv7/virt-v7.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index 95ce9387b83e..2a11d2e83b80 100644 --- a/arch/arm/cpu/armv7/nonsec_virt.S +++ b/arch/arm/cpu/armv7/nonsec_virt.S @@ -164,6 +164,7 @@ ENDPROC(_smp_pen)
- though, but we check this in C before calling this function.
*/ ENTRY(_nonsec_init) +#ifdef CONFIG_ARM_GIC get_gicd_addr r3
mvn r1, #0 @ all bits to 1 @@ -175,6 +176,7 @@ ENTRY(_nonsec_init) str r1, [r3, #GICC_CTLR] @ and clear all other bits mov r1, #0xff str r1, [r3, #GICC_PMR] @ set priority mask register +#endif
mrc p15, 0, r0, c1, c1, 2 movw r1, #0x3fff @@ -200,7 +202,11 @@ ENTRY(_nonsec_init) mcr p15, 0, r1, c12, c0, 1 @ set MVBAR to secure vectors isb
+#ifdef CONFIG_ARM_GIC mov r0, r3 @ return GICC address +#else
- mov r0, #0
+#endif bx lr ENDPROC(_nonsec_init)
diff --git a/arch/arm/cpu/armv7/virt-v7.c b/arch/arm/cpu/armv7/virt-v7.c index d33e5c61a9c2..925201e3f690 100644 --- a/arch/arm/cpu/armv7/virt-v7.c +++ b/arch/arm/cpu/armv7/virt-v7.c @@ -82,22 +82,11 @@ void __weak smp_kick_all_cpus(void) kick_secondary_cpus_gic(gic_dist_addr); }
-__weak void psci_board_init(void) -{ -}
-int armv7_init_nonsec(void) +#ifdef CONFIG_ARM_GIC +static void psci_gic_setup() {
- unsigned int reg;
- unsigned itlinesnr, i; unsigned long gic_dist_addr;
- /* check whether the CPU supports the security extensions */
- reg = read_id_pfr1();
- if ((reg & 0xF0) == 0) {
printf("nonsec: Security extensions not implemented.\n");
return -1;
- }
unsigned itlinesnr, i;
/* the SCR register will be set directly in the monitor mode handler,
- according to the spec one should not tinker with it in secure state
@@ -122,6 +111,27 @@ int armv7_init_nonsec(void) */ for (i = 1; i <= itlinesnr; i++) writel((unsigned)-1, gic_dist_addr + GICD_IGROUPRn + 4 * i); +} +#endif
+__weak void psci_board_init(void) +{ +}
+int armv7_init_nonsec(void) +{
- unsigned int reg;
- /* check whether the CPU supports the security extensions */
- reg = read_id_pfr1();
- if ((reg & 0xF0) == 0) {
printf("nonsec: Security extensions not implemented.\n");
return -1;
- }
+#ifdef CONFIG_ARM_GIC
- psci_gic_setup();
+#endif
psci_board_init();

Hi,
On Thu, Sep 01, 2016 at 10:44:13AM +0200, Hans de Goede wrote:
On 01-09-16 09:57, Antoine Tenart wrote:
Introducing the ARM_GIC configuration option, use it to only use GIC specific code in ARM PSCI function when the SoC has a GIC.
AFAIK sunxi is not the only user of these files, so before you can do this you should also select ARM_GIC in the other users I believe.
Yes sure, I had this in mind but forgot to mention it in the cover-letter. I'll make a patch for each of them in the v2.
Thanks!
Antoine

Add the suspend psci function for sun5i and sun7i. When running on a sun5i, this function put the ram into self-refresh, cut off some PLLs and switch cpuclk to losc. When on a sun7i the suspend function currently only cut off a few PLLs and switch cpuclk to osc24m. This should be improved later.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com --- arch/arm/cpu/armv7/sunxi/Makefile | 9 +- arch/arm/cpu/armv7/sunxi/psci_suspend.c | 175 ++++++++++++++++++++++++++ arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 7 ++ arch/arm/include/asm/arch-sunxi/dram_sun4i.h | 11 ++ 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/sunxi/psci_suspend.c
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index b35b9df4a9d6..80667268a0fc 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -13,7 +13,14 @@ obj-$(CONFIG_MACH_SUN6I) += tzpc.o obj-$(CONFIG_MACH_SUN8I_H3) += tzpc.o
ifndef CONFIG_SPL_BUILD -obj-$(CONFIG_ARMV7_PSCI) += psci.o +ifdef CONFIG_ARMV7_PSCI +obj-$(CONFIG_MACH_SUN6I) += psci.o +obj-$(CONFIG_MACH_SUN7I) += psci.o +obj-$(CONFIG_MACH_SUN8I) += psci.o + +obj-$(CONFIG_MACH_SUN5I) += psci_suspend.o +obj-$(CONFIG_MACH_SUN7I) += psci_suspend.o +endif endif
ifdef CONFIG_SPL_BUILD diff --git a/arch/arm/cpu/armv7/sunxi/psci_suspend.c b/arch/arm/cpu/armv7/sunxi/psci_suspend.c new file mode 100644 index 000000000000..6526cb51cd1c --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/psci_suspend.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Antoine Tenart antoine.tenart@free-electrons.com + * + * Based on Allwinner code. + * Copyright 2007-2012 (C) Allwinner Technology Co., Ltd. + * + * SPDX-License-Identifier: GPL-2.0 + */ +#include <config.h> +#include <common.h> + +#include <asm/arch/clock.h> +#include <asm/arch/dram.h> +#include <asm/armv7.h> +#include <asm/io.h> +#include <asm/psci.h> +#include <asm/secure.h> +#include <asm/system.h> + +#include <linux/bitops.h> + +#ifndef CONFIG_MACH_SUN7I +static void __secure sunxi_enter_selfrefresh(struct sunxi_dram_reg *dram) +{ + int i; + + /* disable all dram host ports */ + for (i = 0; i < 32; i++) + clrbits_le32(&dram->hpcr[i], DRAM_HPCR_PORT_EN); + + /* disable auto-refresh */ + setbits_le32(&dram->drr, DRAM_DRR_AUTO_REFRESH_OFF); + + /* precharge all commands */ + clrsetbits_le32(&dram->dcr, DRAM_DCR_CMD_MASK, + DRAM_DCR_CMD_PRECHARGE_ALL | DRAM_DCR_CMD_EXEC); + + /* enter into self-refresh */ + clrsetbits_le32(&dram->dcr, DRAM_DCR_CMD_MASK, + DRAM_DCR_CMD_SELF_REFRESH | DRAM_DCR_CMD_EXEC); + + /* disable ITM */ + setbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF); + + /* disable DRAM clock */ + clrbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT); + + /* disable all DLLs */ + for (i = 0; i < 5; i++) + clrsetbits_le32(&dram->dllcr[i], + DRAM_DLLCR_DISABLE | DRAM_DLLCR_NRESET, + DRAM_DLLCR_DISABLE); +} + +static void __secure sunxi_enable_dll(struct sunxi_dram_reg *dram, u32 pll) +{ + clrsetbits_le32(&dram->dllcr[pll], + DRAM_DLLCR_DISABLE | DRAM_DLLCR_NRESET, + DRAM_DLLCR_DISABLE); + + clrbits_le32(&dram->dllcr[pll], + DRAM_DLLCR_DISABLE | DRAM_DLLCR_NRESET); + + clrsetbits_le32(&dram->dllcr[pll], + DRAM_DLLCR_DISABLE | DRAM_DLLCR_NRESET, + DRAM_DLLCR_NRESET); +} + +static void __secure sunxi_leave_selfrefresh(struct sunxi_dram_reg *dram) +{ + int i; + + /* enable DLL0 */ + sunxi_enable_dll(dram, 0); + + /* enable DRAM clock */ + setbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT); + + /* enable all other DLLs */ + for (i = 1; i < 5; i++) + sunxi_enable_dll(dram, i); + + /* enable ITM */ + clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF); + + /* leave self-refresh */ + clrsetbits_le32(&dram->dcr, DRAM_DCR_CMD_MASK, + DRAM_DCR_CMD_EXIT | DRAM_DCR_CMD_EXEC); + + /* manually refresh */ + clrsetbits_le32(&dram->dcr, DRAM_DCR_CMD_MASK, + DRAM_DCR_CMD_REFRESH | DRAM_DCR_CMD_EXEC); + + /* enable auto-refresh */ + clrbits_le32(&dram->drr, DRAM_DRR_AUTO_REFRESH_OFF); + + /* enable all host ports */ + for (i = 0; i < 32; i++) + setbits_le32(&dram->hpcr[i], DRAM_HPCR_PORT_EN); +} +#else +static void __secure sunxi_enter_selfrefresh(struct sunxi_dram_reg *dram) +{ +} + +static void __secure sunxi_leave_selfrefresh(struct sunxi_dram_reg *dram) +{ +} +#endif + +static void __secure sunxi_clock_enter_suspend(struct sunxi_ccm_reg *ccm) +{ +#ifndef CONFIG_MACH_SUN7I + /* gate off DRAM clock */ + clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_DDR_CLK); +#endif + + /* switch cpuclk to osc24m */ + clrsetbits_le32(&ccm->cpu_ahb_apb0_cfg, 0x3 << CPU_CLK_SRC_SHIFT, + CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT); + + /* disable PLLs */ + clrbits_le32(&ccm->pll1_cfg, CCM_PLL1_CTRL_EN); + clrbits_le32(&ccm->pll2_cfg, CCM_PLL2_CTRL_EN); + clrbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN); + clrbits_le32(&ccm->pll4_cfg, CCM_PLL4_CTRL_EN); + clrbits_le32(&ccm->pll7_cfg, CCM_PLL7_CTRL_EN); + +#ifndef CONFIG_MACH_SUN7I + /* switch cpuclk to losc */ + clrbits_le32(&ccm->cpu_ahb_apb0_cfg, 0x3 << CPU_CLK_SRC_SHIFT); +#endif +} + +static void __secure sunxi_clock_leave_suspend(struct sunxi_ccm_reg *ccm) +{ +#ifndef CONFIG_MACH_SUN7I + /* switch cpuclk to osc24m */ + clrsetbits_le32(&ccm->cpu_ahb_apb0_cfg, 0x3 << CPU_CLK_SRC_SHIFT, + CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT); +#endif + + /* enable PLLs */ + setbits_le32(&ccm->pll1_cfg, CCM_PLL1_CTRL_EN); + setbits_le32(&ccm->pll2_cfg, CCM_PLL2_CTRL_EN); + setbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN); + setbits_le32(&ccm->pll4_cfg, CCM_PLL4_CTRL_EN); + setbits_le32(&ccm->pll7_cfg, CCM_PLL7_CTRL_EN); + + /* switch cpuclk to pll */ + clrsetbits_le32(&ccm->cpu_ahb_apb0_cfg, 0x3 << CPU_CLK_SRC_SHIFT, + CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT); + +#ifndef CONFIG_MACH_SUN7I + /* gate on DRAM clock */ + setbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_DDR_CLK); +#endif +} + +void __secure psci_cpu_suspend(void) +{ + struct sunxi_dram_reg *dram = + (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + sunxi_enter_selfrefresh(dram); + sunxi_clock_enter_suspend(ccm); + + /* idle */ + DSB; + wfi(); + + sunxi_clock_leave_suspend(ccm); + sunxi_leave_selfrefresh(dram); +} diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h index d1c5ad0a739b..0e59781dcf8d 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h @@ -208,12 +208,17 @@ struct sunxi_ccm_reg { #define CCM_AHB_GATE_DLL (0x1 << 15) #define CCM_AHB_GATE_ACE (0x1 << 16)
+#define CCM_PLL1_CTRL_EN (0x1 << 31) +#define CCM_PLL2_CTRL_EN (0x1 << 31) + #define CCM_PLL3_CTRL_M_SHIFT 0 #define CCM_PLL3_CTRL_M_MASK (0x7f << CCM_PLL3_CTRL_M_SHIFT) #define CCM_PLL3_CTRL_M(n) (((n) & 0x7f) << 0) #define CCM_PLL3_CTRL_INTEGER_MODE (0x1 << 15) #define CCM_PLL3_CTRL_EN (0x1 << 31)
+#define CCM_PLL4_CTRL_EN (0x1 << 31) + #define CCM_PLL5_CTRL_M(n) (((n) & 0x3) << 0) #define CCM_PLL5_CTRL_M_MASK CCM_PLL5_CTRL_M(0x3) #define CCM_PLL5_CTRL_M_X(n) ((n) - 1) @@ -251,6 +256,8 @@ struct sunxi_ccm_reg { #define CCM_PLL6_CTRL_K_SHIFT 4 #define CCM_PLL6_CTRL_K_MASK (0x3 << CCM_PLL6_CTRL_K_SHIFT)
+#define CCM_PLL7_CTRL_EN (0x1 << 31) + #define CCM_GPS_CTRL_RESET (0x1 << 0) #define CCM_GPS_CTRL_GATE (0x1 << 1)
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun4i.h b/arch/arm/include/asm/arch-sunxi/dram_sun4i.h index 139e3366a633..115d6697b94a 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun4i.h @@ -130,6 +130,14 @@ struct dram_para { #define DRAM_DCR_MODE_SEQ 0x0 #define DRAM_DCR_MODE_INTERLEAVE 0x1
+#define DRAM_DCR_CMD(n) ((n) << 27) +#define DRAM_DCR_CMD_MASK DRAM_DCR_CMD(0xf) +#define DRAM_DCR_CMD_SELF_REFRESH DRAM_DCR_CMD(0x2) +#define DRAM_DCR_CMD_REFRESH DRAM_DCR_CMD(0x3) +#define DRAM_DCR_CMD_PRECHARGE_ALL DRAM_DCR_CMD(0x5) +#define DRAM_DCR_CMD_EXIT DRAM_DCR_CMD(0x7) +#define DRAM_DCR_CMD_EXEC (0x1 << 31) + #define DRAM_CSR_DTERR (0x1 << 20) #define DRAM_CSR_DTIERR (0x1 << 21) #define DRAM_CSR_FAILED (DRAM_CSR_DTERR | DRAM_CSR_DTIERR) @@ -137,6 +145,7 @@ struct dram_para { #define DRAM_DRR_TRFC(n) ((n) & 0xff) #define DRAM_DRR_TREFI(n) (((n) & 0xffff) << 8) #define DRAM_DRR_BURST(n) ((((n) - 1) & 0xf) << 24) +#define DRAM_DRR_AUTO_REFRESH_OFF (0x1 << 31)
#define DRAM_MCR_MODE_NORM(n) (((n) & 0x3) << 0) #define DRAM_MCR_MODE_NORM_MASK DRAM_MCR_MOD_NORM(0x3) @@ -176,6 +185,8 @@ struct dram_para {
#define DRAM_CSEL_MAGIC 0x16237495
+#define DRAM_HPCR_PORT_EN 0x1 + unsigned long dramc_init(struct dram_para *para);
#endif /* _SUNXI_DRAM_SUN4I_H */

The sun5i SoCs can take advantage of the newly introduce PSCI suspend function. Enable the PSCI support to denote this.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com --- include/configs/sun5i.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h index d2576599036a..7d754e6625fe 100644 --- a/include/configs/sun5i.h +++ b/include/configs/sun5i.h @@ -19,6 +19,11 @@
#define CONFIG_SUNXI_USB_PHYS 2
+#define CONFIG_ARMV7_PSCI 1 +#define CONFIG_ARMV7_PSCI_NR_CPUS 1 +#define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_A1_BASE +#define CONFIG_TIMER_CLK_FREQ 24000000 + /* * Include common sunxi configuration where most the settings are */

sun5i now implements the psci suspend function. In order to be used by the kernel, we should now boot in non-secure mode. Enable it by default.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com --- board/sunxi/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index c9b500e9390b..6f4b4b2ab065 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -29,8 +29,10 @@ config MACH_SUN4I config MACH_SUN5I bool "sun5i (Allwinner A13)" select CPU_V7 + select CPU_V7_HAS_NONSEC select SUNXI_GEN_SUN4I select SUPPORT_SPL + select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN6I bool "sun6i (Allwinner A31)"

Hi,
On 01-09-16 09:57, Antoine Tenart wrote:
sun5i now implements the psci suspend function. In order to be used by the kernel, we should now boot in non-secure mode. Enable it by default.
Signed-off-by: Antoine Tenart antoine.tenart@free-electrons.com
The sun5i has a cortex a8, which does not do HYP mode, please fix the commit msg subject to reflect this.
Regards,
Hans
board/sunxi/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index c9b500e9390b..6f4b4b2ab065 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -29,8 +29,10 @@ config MACH_SUN4I config MACH_SUN5I bool "sun5i (Allwinner A13)" select CPU_V7
- select CPU_V7_HAS_NONSEC select SUNXI_GEN_SUN4I select SUPPORT_SPL
- select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN6I bool "sun6i (Allwinner A31)"

Hi,
On Thu, Sep 01, 2016 at 10:47:28AM +0200, Hans de Goede wrote:
On 01-09-16 09:57, Antoine Tenart wrote:
sun5i now implements the psci suspend function. In order to be used by the kernel, we should now boot in non-secure mode. Enable it by default.
The sun5i has a cortex a8, which does not do HYP mode, please fix the commit msg subject to reflect this.
Oops. Will do.
Thanks!
Antoine

Hi,
On 01-09-16 09:57, Antoine Tenart wrote:
Hi all,
This series adds an implementation of the psci suspend function for both sun5i and sun7i. This was tested on Nextthing's CHIP and on a A20, using cpuidle in Linux. My tests showed a power consumption reduced by a factor 2 on the CHIP when the system was idle. It went from ~1W without cpuidle enabled to ~0.45W.
The idea of this suspend function is to put the dram into self-refresh, cut off some plls and to switch cpuclk to a source with a lower frequency. Please note the sun7i implementation lacks some parts as putting the ram into self-refresh and coming back from this state seems a bit tricky. I made some tests but did not managed yet to have a stable solution.
As the sun5i does not have a GIC, I needed to remove some code from the generic psci code. To do this I added an ARM_GIC Kconfig option which needs to be selected by each SoC having a GIC. I already added the relevant lines regarding sunXi SoCs. As this Kconfig option is currently only used in the psci code, it should be safe to add it even of all the SoCs having a GIC do not select it, as long as they don't have psci functions.
Finally the series has a patch to enable the psci support for sun5i SoCs, and another patch to let sun5i SoCs boot the kernel in non-secure mode so that it can call psci functions.
Cool stuff. I've some minor remarks to some of the patches I'll reply to them separately. I also hope someone who knows this stuff better then me can also take a look, but if not then I'm just going to take it for the next u-boot cycle (with the remarks fixed).
Regards,
Hans
Thanks!
Antoine
Antoine Tenart (6): ARM: add the ARM_GIC configuration option sunxi: select ARM_GIC for sun[6789]i ARM: PSCI: protect GIC specific code with ARM_GIC sun5/7i: add an implementation of the psci suspend function sun5i: enable PSCI sun5i: boot in HYP mode by default
arch/arm/Kconfig | 3 + arch/arm/cpu/armv7/nonsec_virt.S | 6 + arch/arm/cpu/armv7/sunxi/Makefile | 9 +- arch/arm/cpu/armv7/sunxi/psci_suspend.c | 175 ++++++++++++++++++++++++++ arch/arm/cpu/armv7/virt-v7.c | 38 +++--- arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 7 ++ arch/arm/include/asm/arch-sunxi/dram_sun4i.h | 11 ++ board/sunxi/Kconfig | 9 ++ include/configs/sun5i.h | 5 + 9 files changed, 248 insertions(+), 15 deletions(-) create mode 100644 arch/arm/cpu/armv7/sunxi/psci_suspend.c
participants (2)
-
Antoine Tenart
-
Hans de Goede