Hi,

On Wed, Oct 26, 2016 at 02:10:31PM +0200, Antoine Tenart wrote:
> Add the suspend psci function for sun5i and sun7i. Thus function
> switches the cpu clk source to osc24M or to losc depending on the
> SoC family.
> 
> Signed-off-by: Antoine Tenart <antoine.ten...@free-electrons.com>
> ---
>  arch/arm/cpu/armv7/sunxi/Makefile             |   9 ++-
>  arch/arm/cpu/armv7/sunxi/psci.c               |   2 +-
>  arch/arm/cpu/armv7/sunxi/psci_suspend.c       | 108 
> ++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-sunxi/clock_sun4i.h |   6 ++
>  4 files changed, 123 insertions(+), 2 deletions(-)
>  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.c b/arch/arm/cpu/armv7/sunxi/psci.c
> index 766b8c79d93d..4525bc7bf26b 100644
> --- a/arch/arm/cpu/armv7/sunxi/psci.c
> +++ b/arch/arm/cpu/armv7/sunxi/psci.c
> @@ -48,7 +48,7 @@ static u32 __secure cp15_read_cntp_ctl(void)
>  
>  #define ONE_MS (CONFIG_TIMER_CLK_FREQ / 1000)
>  
> -static void __secure __mdelay(u32 ms)
> +void __secure __mdelay(u32 ms)
>  {
>       u32 reg = ONE_MS * ms;
>  
> 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..e5c000ff2d3d
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/sunxi/psci_suspend.c
> @@ -0,0 +1,108 @@
> +/*
> + * Copyright (C) 2016 Antoine Tenart <antoine.ten...@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/atomic.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>
> +
> +void __mdelay(u32);
> +
> +#if defined(CONFIG_MACH_SUN5I)
> +#define NR_CPUS              1
> +#elif defined(CONFIG_MACH_SUN7I)
> +#define NR_CPUS              2
> +#endif
> +
> +/*
> + * The PSCI suspend function switch cpuclk to another source and disable
> + * pll1. As this function is called per-CPU, it should only do this when
> + * all the CPUs are in idle state.
> + *
> + * The 'cnt' variable keeps track of the number of CPU which are in the idle
> + * state. The last one setup cpuclk for idle.
> + *
> + * The 'clk_state' varibale holds the cpu clk state (idle or normal).
> + */
> +atomic_t __secure_data cnt, clk_state;
> +
> +#define CLK_NORMAL   0
> +#define CLK_IDLE     1
> +
> +static void __secure sunxi_clock_enter_idle(struct sunxi_ccm_reg *ccm)
> +{
> +     /* 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 pll1 */
> +     clrbits_le32(&ccm->pll1_cfg, CCM_PLL1_CTRL_EN);
> +
> +#ifndef CONFIG_MACH_SUN7I
> +     /* switch cpuclk to losc */
> +     clrbits_le32(&ccm->cpu_ahb_apb0_cfg, 0x3 << CPU_CLK_SRC_SHIFT);
> +#endif

Some kind of comment here would be nice.

> +
> +     /* disable ldo */
> +     clrbits_le32(&ccm->osc24m_cfg, OSC24M_LDO_EN);

I realise I'm the one who suggested doing this, but that might turn
out to be wrong. Have you tested devices that use the oscillator
directly, like the PWM?

> +}
> +
> +static void __secure sunxi_clock_leave_idle(struct sunxi_ccm_reg *ccm)
> +{
> +     /* enable ldo */
> +     setbits_le32(&ccm->osc24m_cfg, OSC24M_LDO_EN);
> +
> +#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 pll1 */
> +     setbits_le32(&ccm->pll1_cfg, CCM_PLL1_CTRL_EN);

It might be worth waiting for the PLL to lock by polling the bit 28
before switching the mux to it.

> +
> +     /* switch cpuclk to pll1 */
> +     clrsetbits_le32(&ccm->cpu_ahb_apb0_cfg, 0x3 << CPU_CLK_SRC_SHIFT,
> +                     CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT);
> +}
> +
> +void __secure psci_cpu_suspend(void)
> +{
> +     struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +
> +     if (atomic_inc_return(&cnt) == NR_CPUS) {
> +             /* wait for any sunxi_clock_leave_idle() to finish */
> +             while (atomic_read(&clk_state) != CLK_NORMAL)
> +                     __mdelay(1);
> +
> +             sunxi_clock_enter_idle(ccm);
> +             atomic_set(&clk_state, CLK_IDLE);
> +     }
> +
> +     /* idle */
> +     DSB;
> +     wfi();
> +
> +     if (atomic_dec_return(&cnt) == NR_CPUS - 1) {
> +             /* wait for any sunxi_clock_enter_idle() to finish */
> +             while (atomic_read(&clk_state) != CLK_IDLE)
> +                     __mdelay(1);
> +
> +             sunxi_clock_leave_idle(ccm);
> +             atomic_set(&clk_state, CLK_NORMAL);
> +     }
> +}
> diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h 
> b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
> index d1c5ad0a739b..0d7df5bba543 100644
> --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
> +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
> @@ -90,6 +90,10 @@ struct sunxi_ccm_reg {
>       u32 gmac_clk_cfg;       /* 0x164 */
>  };
>  
> +/* osc24m_cfg bit field */
> +#define OSC24M_EN            (0x1 << 0)
> +#define OSC24M_LDO_EN                (0x1 << 16)
> +
>  /* apb1 bit field */
>  #define APB1_CLK_SRC_OSC24M          (0x0 << 24)
>  #define APB1_CLK_SRC_PLL6            (0x1 << 24)
> @@ -208,6 +212,8 @@ 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_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)
> -- 
> 2.10.1

Looks good otherwise,
Thanks!

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Attachment: signature.asc
Description: PGP signature

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to