1 // SPDX-License-Identifier: GPL-2.0-only
3 * DaVinci Power Management Routines
5 * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/
9 #include <linux/suspend.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/clk.h>
13 #include <linux/spinlock.h>
15 #include <asm/cacheflush.h>
16 #include <asm/delay.h>
19 #include <mach/common.h>
20 #include <mach/da8xx.h>
28 #define DA850_PLL1_BASE 0x01e1a000
29 #define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF
30 #define DEEPSLEEP_SLEEPCOUNT 128
32 static void (*davinci_sram_suspend
) (struct davinci_pm_config
*);
33 static struct davinci_pm_config pm_config
= {
34 .sleepcount
= DEEPSLEEP_SLEEPCOUNT
,
35 .ddrpsc_num
= DA8XX_LPSC1_EMIF3C
,
38 static void davinci_sram_push(void *dest
, void *src
, unsigned int size
)
40 memcpy(dest
, src
, size
);
41 flush_icache_range((unsigned long)dest
, (unsigned long)(dest
+ size
));
44 static void davinci_pm_suspend(void)
48 if (pm_config
.cpupll_reg_base
!= pm_config
.ddrpll_reg_base
) {
50 /* Switch CPU PLL to bypass mode */
51 val
= __raw_readl(pm_config
.cpupll_reg_base
+ PLLCTL
);
52 val
&= ~(PLLCTL_PLLENSRC
| PLLCTL_PLLEN
);
53 __raw_writel(val
, pm_config
.cpupll_reg_base
+ PLLCTL
);
55 udelay(PLL_BYPASS_TIME
);
57 /* Powerdown CPU PLL */
58 val
= __raw_readl(pm_config
.cpupll_reg_base
+ PLLCTL
);
59 val
|= PLLCTL_PLLPWRDN
;
60 __raw_writel(val
, pm_config
.cpupll_reg_base
+ PLLCTL
);
63 /* Configure sleep count in deep sleep register */
64 val
= __raw_readl(pm_config
.deepsleep_reg
);
65 val
&= ~DEEPSLEEP_SLEEPCOUNT_MASK
,
66 val
|= pm_config
.sleepcount
;
67 __raw_writel(val
, pm_config
.deepsleep_reg
);
69 /* System goes to sleep in this call */
70 davinci_sram_suspend(&pm_config
);
72 if (pm_config
.cpupll_reg_base
!= pm_config
.ddrpll_reg_base
) {
74 /* put CPU PLL in reset */
75 val
= __raw_readl(pm_config
.cpupll_reg_base
+ PLLCTL
);
76 val
&= ~PLLCTL_PLLRST
;
77 __raw_writel(val
, pm_config
.cpupll_reg_base
+ PLLCTL
);
79 /* put CPU PLL in power down */
80 val
= __raw_readl(pm_config
.cpupll_reg_base
+ PLLCTL
);
81 val
&= ~PLLCTL_PLLPWRDN
;
82 __raw_writel(val
, pm_config
.cpupll_reg_base
+ PLLCTL
);
84 /* wait for CPU PLL reset */
85 udelay(PLL_RESET_TIME
);
87 /* bring CPU PLL out of reset */
88 val
= __raw_readl(pm_config
.cpupll_reg_base
+ PLLCTL
);
90 __raw_writel(val
, pm_config
.cpupll_reg_base
+ PLLCTL
);
92 /* Wait for CPU PLL to lock */
93 udelay(PLL_LOCK_TIME
);
95 /* Remove CPU PLL from bypass mode */
96 val
= __raw_readl(pm_config
.cpupll_reg_base
+ PLLCTL
);
97 val
&= ~PLLCTL_PLLENSRC
;
99 __raw_writel(val
, pm_config
.cpupll_reg_base
+ PLLCTL
);
103 static int davinci_pm_enter(suspend_state_t state
)
109 davinci_pm_suspend();
118 static const struct platform_suspend_ops davinci_pm_ops
= {
119 .enter
= davinci_pm_enter
,
120 .valid
= suspend_valid_only_mem
,
123 int __init
davinci_pm_init(void)
127 ret
= davinci_cfg_reg(DA850_RTC_ALARM
);
131 pm_config
.ddr2_ctlr_base
= da8xx_get_mem_ctlr();
132 pm_config
.deepsleep_reg
= DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG
);
134 pm_config
.cpupll_reg_base
= ioremap(DA8XX_PLL0_BASE
, SZ_4K
);
135 if (!pm_config
.cpupll_reg_base
)
138 pm_config
.ddrpll_reg_base
= ioremap(DA850_PLL1_BASE
, SZ_4K
);
139 if (!pm_config
.ddrpll_reg_base
) {
144 pm_config
.ddrpsc_reg_base
= ioremap(DA8XX_PSC1_BASE
, SZ_4K
);
145 if (!pm_config
.ddrpsc_reg_base
) {
150 davinci_sram_suspend
= sram_alloc(davinci_cpu_suspend_sz
, NULL
);
151 if (!davinci_sram_suspend
) {
152 pr_err("PM: cannot allocate SRAM memory\n");
157 davinci_sram_push(davinci_sram_suspend
, davinci_cpu_suspend
,
158 davinci_cpu_suspend_sz
);
160 suspend_set_ops(&davinci_pm_ops
);
165 iounmap(pm_config
.ddrpsc_reg_base
);
167 iounmap(pm_config
.ddrpll_reg_base
);
169 iounmap(pm_config
.cpupll_reg_base
);