aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/pm-domain.c
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2006-06-26 19:16:18 -0400
committerTony Lindgren <tony@atomide.com>2006-06-26 19:16:18 -0400
commit22a16f39e36e62f7bd221e5b279ea02fb3c43425 (patch)
tree53921cd85f8a351363cecc790f40e4fd9b5770ef /arch/arm/mach-omap2/pm-domain.c
parenta7ca9d2b0199f79480800e18f643328bb43f521d (diff)
ARM: OMAP: Add initial 24xx suspend support
This patch adds support for omap24xx power domains and allows suspend to work. Please note that for some reason core power domain still does not seem to idle. Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/pm-domain.c')
-rw-r--r--arch/arm/mach-omap2/pm-domain.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c
new file mode 100644
index 000000000000..5e20e740cde5
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-domain.c
@@ -0,0 +1,300 @@
1/*
2 * linux/arch/arm/mach-omap2/pm-domain.c
3 *
4 * Power domain functions for OMAP2
5 *
6 * Copyright (C) 2006 Nokia Corporation
7 * Tony Lindgren <tony@atomide.com>
8 *
9 * Some code based on earlier OMAP2 sample PM code
10 * Copyright (C) 2005 Texas Instruments, Inc.
11 * Richard Woodruff <r-woodruff2@ti.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#include <linux/config.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/clk.h>
22
23#include <asm/io.h>
24
25#include "prcm-regs.h"
26
27/* Power domain offsets */
28#define PM_MPU_OFFSET 0x100
29#define PM_CORE_OFFSET 0x200
30#define PM_GFX_OFFSET 0x300
31#define PM_WKUP_OFFSET 0x400 /* Autoidle only */
32#define PM_PLL_OFFSET 0x500 /* Autoidle only */
33#define PM_DSP_OFFSET 0x800
34#define PM_MDM_OFFSET 0xc00
35
36/* Power domain wake-up dependency control register */
37#define PM_WKDEP_OFFSET 0xc8
38#define EN_MDM (1 << 5)
39#define EN_WKUP (1 << 4)
40#define EN_GFX (1 << 3)
41#define EN_DSP (1 << 2)
42#define EN_MPU (1 << 1)
43#define EN_CORE (1 << 0)
44
45/* Core power domain state transition control register */
46#define PM_PWSTCTRL_OFFSET 0xe0
47#define FORCESTATE (1 << 18) /* Only for DSP & GFX */
48#define MEM4RETSTATE (1 << 6)
49#define MEM3RETSTATE (1 << 5)
50#define MEM2RETSTATE (1 << 4)
51#define MEM1RETSTATE (1 << 3)
52#define LOGICRETSTATE (1 << 2) /* Logic is retained */
53#define POWERSTATE_OFF 0x3
54#define POWERSTATE_RETENTION 0x1
55#define POWERSTATE_ON 0x0
56
57/* Power domain state register */
58#define PM_PWSTST_OFFSET 0xe4
59
60/* Hardware supervised state transition control register */
61#define CM_CLKSTCTRL_OFFSET 0x48
62#define AUTOSTAT_MPU (1 << 0) /* MPU */
63#define AUTOSTAT_DSS (1 << 2) /* Core */
64#define AUTOSTAT_L4 (1 << 1) /* Core */
65#define AUTOSTAT_L3 (1 << 0) /* Core */
66#define AUTOSTAT_GFX (1 << 0) /* GFX */
67#define AUTOSTAT_IVA (1 << 8) /* 2420 IVA in DSP domain */
68#define AUTOSTAT_DSP (1 << 0) /* DSP */
69#define AUTOSTAT_MDM (1 << 0) /* MDM */
70
71/* Automatic control of interface clock idling */
72#define CM_AUTOIDLE1_OFFSET 0x30
73#define CM_AUTOIDLE2_OFFSET 0x34 /* Core only */
74#define CM_AUTOIDLE3_OFFSET 0x38 /* Core only */
75#define CM_AUTOIDLE4_OFFSET 0x3c /* Core only */
76#define AUTO_54M(x) (((x) & 0x3) << 6)
77#define AUTO_96M(x) (((x) & 0x3) << 2)
78#define AUTO_DPLL(x) (((x) & 0x3) << 0)
79#define AUTO_STOPPED 0x3
80#define AUTO_BYPASS_FAST 0x2 /* DPLL only */
81#define AUTO_BYPASS_LOW_POWER 0x1 /* DPLL only */
82#define AUTO_DISABLED 0x0
83
84/* Voltage control PRCM_VOLTCTRL bits */
85#define AUTO_EXTVOLT (1 << 15)
86#define FORCE_EXTVOLT (1 << 14)
87#define SETOFF_LEVEL(x) (((x) & 0x3) << 12)
88#define MEMRETCTRL (1 << 8)
89#define SETRET_LEVEL(x) (((x) & 0x3) << 6)
90#define VOLT_LEVEL(x) (((x) & 0x3) << 0)
91
92#define OMAP24XX_PRCM_VBASE IO_ADDRESS(OMAP24XX_PRCM_BASE)
93#define prcm_readl(r) __raw_readl(OMAP24XX_PRCM_VBASE + (r))
94#define prcm_writel(v, r) __raw_writel((v), OMAP24XX_PRCM_VBASE + (r))
95
96static u32 pmdomain_get_wakeup_dependencies(int domain_offset)
97{
98 return prcm_readl(domain_offset + PM_WKDEP_OFFSET);
99}
100
101static void pmdomain_set_wakeup_dependencies(u32 state, int domain_offset)
102{
103 prcm_writel(state, domain_offset + PM_WKDEP_OFFSET);
104}
105
106static u32 pmdomain_get_powerstate(int domain_offset)
107{
108 return prcm_readl(domain_offset + PM_PWSTCTRL_OFFSET);
109}
110
111static void pmdomain_set_powerstate(u32 state, int domain_offset)
112{
113 prcm_writel(state, domain_offset + PM_PWSTCTRL_OFFSET);
114}
115
116static u32 pmdomain_get_clock_autocontrol(int domain_offset)
117{
118 return prcm_readl(domain_offset + CM_CLKSTCTRL_OFFSET);
119}
120
121static void pmdomain_set_clock_autocontrol(u32 state, int domain_offset)
122{
123 prcm_writel(state, domain_offset + CM_CLKSTCTRL_OFFSET);
124}
125
126static u32 pmdomain_get_clock_autoidle1(int domain_offset)
127{
128 return prcm_readl(domain_offset + CM_AUTOIDLE1_OFFSET);
129}
130
131/* Core domain only */
132static u32 pmdomain_get_clock_autoidle2(int domain_offset)
133{
134 return prcm_readl(domain_offset + CM_AUTOIDLE2_OFFSET);
135}
136
137/* Core domain only */
138static u32 pmdomain_get_clock_autoidle3(int domain_offset)
139{
140 return prcm_readl(domain_offset + CM_AUTOIDLE3_OFFSET);
141}
142
143/* Core domain only */
144static u32 pmdomain_get_clock_autoidle4(int domain_offset)
145{
146 return prcm_readl(domain_offset + CM_AUTOIDLE4_OFFSET);
147}
148
149static void pmdomain_set_clock_autoidle1(u32 state, int domain_offset)
150{
151 prcm_writel(state, CM_AUTOIDLE1_OFFSET + domain_offset);
152}
153
154/* Core domain only */
155static void pmdomain_set_clock_autoidle2(u32 state, int domain_offset)
156{
157 prcm_writel(state, CM_AUTOIDLE2_OFFSET + domain_offset);
158}
159
160/* Core domain only */
161static void pmdomain_set_clock_autoidle3(u32 state, int domain_offset)
162{
163 prcm_writel(state, CM_AUTOIDLE3_OFFSET + domain_offset);
164}
165
166/* Core domain only */
167static void pmdomain_set_clock_autoidle4(u32 state, int domain_offset)
168{
169 prcm_writel(state, CM_AUTOIDLE4_OFFSET + domain_offset);
170}
171
172/*
173 * Configures power management domains to idle clocks automatically.
174 */
175void pmdomain_set_autoidle(void)
176{
177 u32 val;
178
179 /* Set PLL auto stop for 54M, 96M & DPLL */
180 pmdomain_set_clock_autoidle1(AUTO_54M(AUTO_STOPPED) |
181 AUTO_96M(AUTO_STOPPED) |
182 AUTO_DPLL(AUTO_STOPPED), PM_PLL_OFFSET);
183
184 /* External clock input control
185 * REVISIT: Should this be in clock framework?
186 */
187 PRCM_CLKSRC_CTRL |= (0x3 << 3);
188
189 /* Configure number of 32KHz clock cycles for sys_clk */
190 PRCM_CLKSSETUP = 0x00ff;
191
192 /* Configure automatic voltage transition */
193 PRCM_VOLTSETUP = 0;
194 val = PRCM_VOLTCTRL;
195 val &= ~(SETOFF_LEVEL(0x3) | VOLT_LEVEL(0x3));
196 val |= SETOFF_LEVEL(1) | VOLT_LEVEL(1) | AUTO_EXTVOLT;
197 PRCM_VOLTCTRL = val;
198
199 /* Disable emulation tools functional clock */
200 PRCM_CLKEMUL_CTRL = 0x0;
201
202 /* Set core memory retention state */
203 val = pmdomain_get_powerstate(PM_CORE_OFFSET);
204 if (cpu_is_omap2420()) {
205 val &= ~(0x7 << 3);
206 val |= (MEM3RETSTATE | MEM2RETSTATE | MEM1RETSTATE);
207 } else {
208 val &= ~(0xf << 3);
209 val |= (MEM4RETSTATE | MEM3RETSTATE | MEM2RETSTATE |
210 MEM1RETSTATE);
211 }
212 pmdomain_set_powerstate(val, PM_CORE_OFFSET);
213
214 /* OCP interface smart idle. REVISIT: Enable autoidle bit0 ? */
215 val = SMS_SYSCONFIG;
216 val &= ~(0x3 << 3);
217 val |= (0x2 << 3) | (1 << 0);
218 SMS_SYSCONFIG |= val;
219
220 val = SDRC_SYSCONFIG;
221 val &= ~(0x3 << 3);
222 val |= (0x2 << 3);
223 SDRC_SYSCONFIG = val;
224
225 /* Configure L3 interface for smart idle.
226 * REVISIT: Enable autoidle bit0 ?
227 */
228 val = GPMC_SYSCONFIG;
229 val &= ~(0x3 << 3);
230 val |= (0x2 << 3) | (1 << 0);
231 GPMC_SYSCONFIG = val;
232
233 pmdomain_set_powerstate(LOGICRETSTATE | POWERSTATE_RETENTION,
234 PM_MPU_OFFSET);
235 pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_CORE_OFFSET);
236 if (!cpu_is_omap2420())
237 pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_MDM_OFFSET);
238
239 /* Assume suspend function has saved the state for DSP and GFX */
240 pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_DSP_OFFSET);
241 pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_GFX_OFFSET);
242
243#if 0
244 /* REVISIT: Internal USB needs special handling */
245 force_standby_usb();
246 if (cpu_is_omap2430())
247 force_hsmmc();
248 sdram_self_refresh_on_idle_req(1);
249#endif
250
251 /* Enable clock auto control for all domains.
252 * Note that CORE domain includes also DSS, L4 & L3.
253 */
254 pmdomain_set_clock_autocontrol(AUTOSTAT_MPU, PM_MPU_OFFSET);
255 pmdomain_set_clock_autocontrol(AUTOSTAT_GFX, PM_GFX_OFFSET);
256 pmdomain_set_clock_autocontrol(AUTOSTAT_DSS | AUTOSTAT_L4 | AUTOSTAT_L3,
257 PM_CORE_OFFSET);
258 if (cpu_is_omap2420())
259 pmdomain_set_clock_autocontrol(AUTOSTAT_IVA | AUTOSTAT_DSP,
260 PM_DSP_OFFSET);
261 else {
262 pmdomain_set_clock_autocontrol(AUTOSTAT_DSP, PM_DSP_OFFSET);
263 pmdomain_set_clock_autocontrol(AUTOSTAT_MDM, PM_MDM_OFFSET);
264 }
265
266 /* Enable clock autoidle for all domains */
267 pmdomain_set_clock_autoidle1(0x2, PM_DSP_OFFSET);
268 if (cpu_is_omap2420()) {
269 pmdomain_set_clock_autoidle1(0xfffffff9, PM_CORE_OFFSET);
270 pmdomain_set_clock_autoidle2(0x7, PM_CORE_OFFSET);
271 pmdomain_set_clock_autoidle1(0x3f, PM_WKUP_OFFSET);
272 } else {
273 pmdomain_set_clock_autoidle1(0xeafffff1, PM_CORE_OFFSET);
274 pmdomain_set_clock_autoidle2(0xfff, PM_CORE_OFFSET);
275 pmdomain_set_clock_autoidle1(0x7f, PM_WKUP_OFFSET);
276 pmdomain_set_clock_autoidle1(0x3, PM_MDM_OFFSET);
277 }
278 pmdomain_set_clock_autoidle3(0x7, PM_CORE_OFFSET);
279 pmdomain_set_clock_autoidle4(0x1f, PM_CORE_OFFSET);
280}
281
282/*
283 * Initializes power domains by removing wake-up dependencies and powering
284 * down DSP and GFX. Gets called from PM init. Note that DSP and IVA code
285 * must re-enable DSP and GFX when used.
286 */
287void __init pmdomain_init(void)
288{
289 /* Remove all domain wakeup dependencies */
290 pmdomain_set_wakeup_dependencies(EN_WKUP | EN_CORE, PM_MPU_OFFSET);
291 pmdomain_set_wakeup_dependencies(0, PM_DSP_OFFSET);
292 pmdomain_set_wakeup_dependencies(0, PM_GFX_OFFSET);
293 pmdomain_set_wakeup_dependencies(EN_WKUP | EN_MPU, PM_CORE_OFFSET);
294 if (cpu_is_omap2430())
295 pmdomain_set_wakeup_dependencies(0, PM_MDM_OFFSET);
296
297 /* Power down DSP and GFX */
298 pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_DSP_OFFSET);
299 pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_GFX_OFFSET);
300}