Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/mach-davinci/pm.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* DaVinci Power Management Routines
4
*
5
* Copyright (C) 2009 Texas Instruments, Inc. https://www.ti.com/
6
*/
7
8
#include <linux/pm.h>
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>
14
15
#include <asm/cacheflush.h>
16
#include <asm/delay.h>
17
#include <asm/io.h>
18
19
#include "common.h"
20
#include "da8xx.h"
21
#include "mux.h"
22
#include "pm.h"
23
#include "clock.h"
24
#include "psc.h"
25
#include "sram.h"
26
27
#define DA850_PLL1_BASE 0x01e1a000
28
#define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF
29
#define DEEPSLEEP_SLEEPCOUNT 128
30
31
static void (*davinci_sram_suspend) (struct davinci_pm_config *);
32
static struct davinci_pm_config pm_config = {
33
.sleepcount = DEEPSLEEP_SLEEPCOUNT,
34
.ddrpsc_num = DA8XX_LPSC1_EMIF3C,
35
};
36
37
static void davinci_sram_push(void *dest, void *src, unsigned int size)
38
{
39
memcpy(dest, src, size);
40
flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
41
}
42
43
static void davinci_pm_suspend(void)
44
{
45
unsigned val;
46
47
if (pm_config.cpupll_reg_base != pm_config.ddrpll_reg_base) {
48
49
/* Switch CPU PLL to bypass mode */
50
val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL);
51
val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
52
__raw_writel(val, pm_config.cpupll_reg_base + PLLCTL);
53
54
udelay(PLL_BYPASS_TIME);
55
56
/* Powerdown CPU PLL */
57
val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL);
58
val |= PLLCTL_PLLPWRDN;
59
__raw_writel(val, pm_config.cpupll_reg_base + PLLCTL);
60
}
61
62
/* Configure sleep count in deep sleep register */
63
val = __raw_readl(pm_config.deepsleep_reg);
64
val &= ~DEEPSLEEP_SLEEPCOUNT_MASK;
65
val |= pm_config.sleepcount;
66
__raw_writel(val, pm_config.deepsleep_reg);
67
68
/* System goes to sleep in this call */
69
davinci_sram_suspend(&pm_config);
70
71
if (pm_config.cpupll_reg_base != pm_config.ddrpll_reg_base) {
72
73
/* put CPU PLL in reset */
74
val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL);
75
val &= ~PLLCTL_PLLRST;
76
__raw_writel(val, pm_config.cpupll_reg_base + PLLCTL);
77
78
/* put CPU PLL in power down */
79
val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL);
80
val &= ~PLLCTL_PLLPWRDN;
81
__raw_writel(val, pm_config.cpupll_reg_base + PLLCTL);
82
83
/* wait for CPU PLL reset */
84
udelay(PLL_RESET_TIME);
85
86
/* bring CPU PLL out of reset */
87
val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL);
88
val |= PLLCTL_PLLRST;
89
__raw_writel(val, pm_config.cpupll_reg_base + PLLCTL);
90
91
/* Wait for CPU PLL to lock */
92
udelay(PLL_LOCK_TIME);
93
94
/* Remove CPU PLL from bypass mode */
95
val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL);
96
val &= ~PLLCTL_PLLENSRC;
97
val |= PLLCTL_PLLEN;
98
__raw_writel(val, pm_config.cpupll_reg_base + PLLCTL);
99
}
100
}
101
102
static int davinci_pm_enter(suspend_state_t state)
103
{
104
int ret = 0;
105
106
switch (state) {
107
case PM_SUSPEND_MEM:
108
davinci_pm_suspend();
109
break;
110
default:
111
ret = -EINVAL;
112
}
113
114
return ret;
115
}
116
117
static const struct platform_suspend_ops davinci_pm_ops = {
118
.enter = davinci_pm_enter,
119
.valid = suspend_valid_only_mem,
120
};
121
122
int __init davinci_pm_init(void)
123
{
124
int ret;
125
126
ret = davinci_cfg_reg(DA850_RTC_ALARM);
127
if (ret)
128
return ret;
129
130
pm_config.ddr2_ctlr_base = da8xx_get_mem_ctlr();
131
pm_config.deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG);
132
133
pm_config.cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K);
134
if (!pm_config.cpupll_reg_base)
135
return -ENOMEM;
136
137
pm_config.ddrpll_reg_base = ioremap(DA850_PLL1_BASE, SZ_4K);
138
if (!pm_config.ddrpll_reg_base) {
139
ret = -ENOMEM;
140
goto no_ddrpll_mem;
141
}
142
143
pm_config.ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K);
144
if (!pm_config.ddrpsc_reg_base) {
145
ret = -ENOMEM;
146
goto no_ddrpsc_mem;
147
}
148
149
davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
150
if (!davinci_sram_suspend) {
151
pr_err("PM: cannot allocate SRAM memory\n");
152
ret = -ENOMEM;
153
goto no_sram_mem;
154
}
155
156
davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
157
davinci_cpu_suspend_sz);
158
159
suspend_set_ops(&davinci_pm_ops);
160
161
return 0;
162
163
no_sram_mem:
164
iounmap(pm_config.ddrpsc_reg_base);
165
no_ddrpsc_mem:
166
iounmap(pm_config.ddrpll_reg_base);
167
no_ddrpll_mem:
168
iounmap(pm_config.cpupll_reg_base);
169
return ret;
170
}
171
172