[v4,3/6] clk: rockchip: RK3288: add suspend and resume
diff mbox

Message ID 1413933902-25767-1-git-send-email-zyw@rock-chips.com
State New, archived
Headers show

Commit Message

Chris Zhong Oct. 21, 2014, 11:25 p.m. UTC
save and restore some clks, which might be changed in suspend.

Signed-off-by: Tony Xie <xxx@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- __raw_readl/__raw_writel replaced by readl_relaxed/writel_relaxed

 drivers/clk/rockchip/clk-rk3288.c |   63 +++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

Comments

Douglas Anderson Oct. 22, 2014, 4:58 a.m. UTC | #1
Chris,

On Tue, Oct 21, 2014 at 4:25 PM, Chris Zhong <zyw@rock-chips.com> wrote:
> +#ifdef CONFIG_PM_SLEEP
> +static void __iomem *rk3288_cru_base;
> +static const int rk3288_saved_cru_reg_ids[] = {
> +       RK3288_MODE_CON,
> +       RK3288_CLKSEL_CON(0),
> +       RK3288_CLKSEL_CON(1),
> +       RK3288_CLKSEL_CON(10),
> +       RK3288_CLKSEL_CON(33),
> +       RK3288_CLKSEL_CON(37),

I'm still not 100% certain why these registers were picked.  Are they
all needed?  Are we sure that no extras are needed?

I'll try to find some time to research, but if you happen to know the
answer that'd be nice.


> +};
> +
> +static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)];
> +
> +/*
> + * cru will be set in maskrom when system wake up from fastboot
> + * mode in suspend,
> + * so the operation is saving the changed regs.
> + * The apll/cpll/gpll will be set into slow mode in maskrom.
> + * It is mean that resume code run in 24m quit slowly!

s/quit/quite

> + * so we must resume these plls as soon as possible.

This function doesn't actually resume PLLs, it just restores dividers / etc.


I will say that with this patch the "clk_summary" doesn't change
before and after suspend/resume.  Without this patch I see this diff
before/after:

<                 l2ram                     0            0   600000000
         0 0
<                 aclk_core_m0              0            0   600000000
         0 0
<                 aclk_core_mp              0            0   360000000
         0 0
<                 atclk                     0            0   360000000
         0 0
<                 pclk_dbg_pre              0            0   360000000
         0 0
<                    pclk_core_niu           0            0
360000000          0 0
<                    cs_dbg                 0            0   360000000
         0 0
<                    pclk_dbg               0            0   360000000
         0 0
---
>                 l2ram                     0            0  1800000000          0 0
>                 aclk_core_m0              0            0  1800000000          0 0
>                 aclk_core_mp              0            0  1800000000          0 0
>                 atclk                     0            0  1800000000          0 0
>                 pclk_dbg_pre              0            0  1800000000          0 0
>                    pclk_core_niu           0            0  1800000000          0 0
>                    cs_dbg                 0            0  1800000000          0 0
>                    pclk_dbg               0            0  1800000000          0 0

Patch
diff mbox

diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 2327829..0731b18 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -16,6 +16,7 @@ 
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/syscore_ops.h>
 #include <dt-bindings/clock/rk3288-cru.h>
 #include "clk.h"
 
@@ -762,6 +763,67 @@  static const char *rk3288_critical_clocks[] __initconst = {
 	"hclk_peri",
 };
 
+#ifdef CONFIG_PM_SLEEP
+static void __iomem *rk3288_cru_base;
+static const int rk3288_saved_cru_reg_ids[] = {
+	RK3288_MODE_CON,
+	RK3288_CLKSEL_CON(0),
+	RK3288_CLKSEL_CON(1),
+	RK3288_CLKSEL_CON(10),
+	RK3288_CLKSEL_CON(33),
+	RK3288_CLKSEL_CON(37),
+};
+
+static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)];
+
+/*
+ * cru will be set in maskrom when system wake up from fastboot
+ * mode in suspend,
+ * so the operation is saving the changed regs.
+ * The apll/cpll/gpll will be set into slow mode in maskrom.
+ * It is mean that resume code run in 24m quit slowly!
+ * so we must resume these plls as soon as possible.
+ */
+static int rk3288_clk_suspend(void)
+{
+	int i, reg_id;
+
+	for (i = 0; i < ARRAY_SIZE(rk3288_saved_cru_reg_ids); i++) {
+		reg_id = rk3288_saved_cru_reg_ids[i];
+
+		rk3288_saved_cru_regs[i] =
+				readl_relaxed(rk3288_cru_base + reg_id);
+	}
+	return 0;
+}
+
+static void rk3288_clk_resume(void)
+{
+	int i, reg_id;
+
+	for (i = ARRAY_SIZE(rk3288_saved_cru_reg_ids) - 1; i >= 0; i--) {
+		reg_id = rk3288_saved_cru_reg_ids[i];
+
+		writel_relaxed(rk3288_saved_cru_regs[i] | 0xffff0000,
+			       rk3288_cru_base + reg_id);
+	}
+}
+
+static struct syscore_ops rk3288_clk_syscore_ops = {
+	.suspend = rk3288_clk_suspend,
+	.resume = rk3288_clk_resume,
+};
+
+static void rk3288_clk_sleep_init(void __iomem *reg_base)
+{
+	rk3288_cru_base = reg_base;
+	register_syscore_ops(&rk3288_clk_syscore_ops);
+}
+
+#else /* CONFIG_PM_SLEEP */
+static void rk3288_clk_sleep_init(void __iomem *reg_base) {}
+#endif
+
 static void __init rk3288_clk_init(struct device_node *np)
 {
 	void __iomem *reg_base;
@@ -810,5 +872,6 @@  static void __init rk3288_clk_init(struct device_node *np)
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
 	rockchip_register_restart_notifier(RK3288_GLB_SRST_FST);
+	rk3288_clk_sleep_init(reg_base);
 }
 CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);