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
+
+       /* disable ldo */
+       clrbits_le32(&ccm->osc24m_cfg, OSC24M_LDO_EN);
+}
+
+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);
+
+       /* 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

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

Reply via email to