Commit | Line | Data |
---|---|---|
93f89519 SM |
1 | /* |
2 | * Blackfin bf609 power management | |
3 | * | |
4 | * Copyright 2011 Analog Devices Inc. | |
5 | * | |
6 | * Licensed under the GPL-2 | |
7 | */ | |
8 | ||
9 | #include <linux/suspend.h> | |
10 | #include <linux/io.h> | |
11 | #include <linux/interrupt.h> | |
12 | #include <linux/gpio.h> | |
13 | #include <linux/irq.h> | |
93f89519 | 14 | #include <linux/delay.h> |
923680cb | 15 | #include <linux/syscore_ops.h> |
93f89519 SM |
16 | |
17 | #include <asm/dpmc.h> | |
18 | #include <asm/pm.h> | |
19 | #include <mach/pm.h> | |
20 | #include <asm/blackfin.h> | |
c7e48e1e | 21 | #include <asm/mem_init.h> |
93f89519 SM |
22 | |
23 | /***********************************************************/ | |
24 | /* */ | |
25 | /* Wakeup Actions for DPM_RESTORE */ | |
26 | /* */ | |
27 | /***********************************************************/ | |
28 | #define BITP_ROM_WUA_CHKHDR 24 | |
29 | #define BITP_ROM_WUA_DDRLOCK 7 | |
30 | #define BITP_ROM_WUA_DDRDLLEN 6 | |
31 | #define BITP_ROM_WUA_DDR 5 | |
32 | #define BITP_ROM_WUA_CGU 4 | |
33 | #define BITP_ROM_WUA_MEMBOOT 2 | |
34 | #define BITP_ROM_WUA_EN 1 | |
35 | ||
36 | #define BITM_ROM_WUA_CHKHDR (0xFF000000) | |
37 | #define ENUM_ROM_WUA_CHKHDR_AD 0xAD000000 | |
38 | ||
39 | #define BITM_ROM_WUA_DDRLOCK (0x00000080) | |
40 | #define BITM_ROM_WUA_DDRDLLEN (0x00000040) | |
41 | #define BITM_ROM_WUA_DDR (0x00000020) | |
42 | #define BITM_ROM_WUA_CGU (0x00000010) | |
43 | #define BITM_ROM_WUA_MEMBOOT (0x00000002) | |
44 | #define BITM_ROM_WUA_EN (0x00000001) | |
45 | ||
46 | /***********************************************************/ | |
47 | /* */ | |
48 | /* Syscontrol */ | |
49 | /* */ | |
50 | /***********************************************************/ | |
51 | #define BITP_ROM_SYSCTRL_CGU_LOCKINGEN 28 /* unlocks CGU_CTL register */ | |
52 | #define BITP_ROM_SYSCTRL_WUA_OVERRIDE 24 | |
53 | #define BITP_ROM_SYSCTRL_WUA_DDRDLLEN 20 /* Saves the DDR DLL and PADS registers to the DPM registers */ | |
54 | #define BITP_ROM_SYSCTRL_WUA_DDR 19 /* Saves the DDR registers to the DPM registers */ | |
55 | #define BITP_ROM_SYSCTRL_WUA_CGU 18 /* Saves the CGU registers into DPM registers */ | |
56 | #define BITP_ROM_SYSCTRL_WUA_DPMWRITE 17 /* Saves the Syscontrol structure structure contents into DPM registers */ | |
57 | #define BITP_ROM_SYSCTRL_WUA_EN 16 /* reads current PLL and DDR configuration into structure */ | |
58 | #define BITP_ROM_SYSCTRL_DDR_WRITE 13 /* writes the DDR registers from Syscontrol structure for wakeup initialization of DDR */ | |
59 | #define BITP_ROM_SYSCTRL_DDR_READ 12 /* Read the DDR registers into the Syscontrol structure for storing prior to hibernate */ | |
60 | #define BITP_ROM_SYSCTRL_CGU_AUTODIS 11 /* Disables auto handling of UPDT and ALGN fields */ | |
61 | #define BITP_ROM_SYSCTRL_CGU_CLKOUTSEL 7 /* access CGU_CLKOUTSEL register */ | |
62 | #define BITP_ROM_SYSCTRL_CGU_DIV 6 /* access CGU_DIV register */ | |
63 | #define BITP_ROM_SYSCTRL_CGU_STAT 5 /* access CGU_STAT register */ | |
64 | #define BITP_ROM_SYSCTRL_CGU_CTL 4 /* access CGU_CTL register */ | |
65 | #define BITP_ROM_SYSCTRL_CGU_RTNSTAT 2 /* Update structure STAT field upon error */ | |
66 | #define BITP_ROM_SYSCTRL_WRITE 1 /* write registers */ | |
67 | #define BITP_ROM_SYSCTRL_READ 0 /* read registers */ | |
68 | ||
69 | #define BITM_ROM_SYSCTRL_CGU_READ (0x00000001) /* Read CGU registers */ | |
70 | #define BITM_ROM_SYSCTRL_CGU_WRITE (0x00000002) /* Write registers */ | |
71 | #define BITM_ROM_SYSCTRL_CGU_RTNSTAT (0x00000004) /* Update structure STAT field upon error or after a write operation */ | |
72 | #define BITM_ROM_SYSCTRL_CGU_CTL (0x00000010) /* Access CGU_CTL register */ | |
73 | #define BITM_ROM_SYSCTRL_CGU_STAT (0x00000020) /* Access CGU_STAT register */ | |
74 | #define BITM_ROM_SYSCTRL_CGU_DIV (0x00000040) /* Access CGU_DIV register */ | |
75 | #define BITM_ROM_SYSCTRL_CGU_CLKOUTSEL (0x00000080) /* Access CGU_CLKOUTSEL register */ | |
76 | #define BITM_ROM_SYSCTRL_CGU_AUTODIS (0x00000800) /* Disables auto handling of UPDT and ALGN fields */ | |
77 | #define BITM_ROM_SYSCTRL_DDR_READ (0x00001000) /* Reads the contents of the DDR registers and stores them into the structure */ | |
78 | #define BITM_ROM_SYSCTRL_DDR_WRITE (0x00002000) /* Writes the DDR registers from the structure, only really intented for wakeup functionality and not for full DDR configuration */ | |
79 | #define BITM_ROM_SYSCTRL_WUA_EN (0x00010000) /* Wakeup entry or exit opertation enable */ | |
80 | #define BITM_ROM_SYSCTRL_WUA_DPMWRITE (0x00020000) /* When set indicates a restore of the PLL and DDR is to be performed otherwise a save is required */ | |
81 | #define BITM_ROM_SYSCTRL_WUA_CGU (0x00040000) /* Only applicable for a PLL and DDR save operation to the DPM, saves the current settings if cleared or the contents of the structure if set */ | |
82 | #define BITM_ROM_SYSCTRL_WUA_DDR (0x00080000) /* Only applicable for a PLL and DDR save operation to the DPM, saves the current settings if cleared or the contents of the structure if set */ | |
83 | #define BITM_ROM_SYSCTRL_WUA_DDRDLLEN (0x00100000) /* Enables saving/restoring of the DDR DLLCTL register */ | |
84 | #define BITM_ROM_SYSCTRL_WUA_OVERRIDE (0x01000000) | |
85 | #define BITM_ROM_SYSCTRL_CGU_LOCKINGEN (0x10000000) /* Unlocks the CGU_CTL register */ | |
86 | ||
87 | ||
88 | /* Structures for the syscontrol() function */ | |
89 | struct STRUCT_ROM_SYSCTRL { | |
90 | uint32_t ulCGU_CTL; | |
91 | uint32_t ulCGU_STAT; | |
92 | uint32_t ulCGU_DIV; | |
93 | uint32_t ulCGU_CLKOUTSEL; | |
94 | uint32_t ulWUA_Flags; | |
95 | uint32_t ulWUA_BootAddr; | |
96 | uint32_t ulWUA_User; | |
97 | uint32_t ulDDR_CTL; | |
98 | uint32_t ulDDR_CFG; | |
99 | uint32_t ulDDR_TR0; | |
100 | uint32_t ulDDR_TR1; | |
101 | uint32_t ulDDR_TR2; | |
102 | uint32_t ulDDR_MR; | |
103 | uint32_t ulDDR_EMR1; | |
104 | uint32_t ulDDR_EMR2; | |
105 | uint32_t ulDDR_PADCTL; | |
106 | uint32_t ulDDR_DLLCTL; | |
107 | uint32_t ulReserved; | |
108 | }; | |
109 | ||
110 | struct bfin_pm_data { | |
111 | uint32_t magic; | |
112 | uint32_t resume_addr; | |
113 | uint32_t sp; | |
114 | }; | |
115 | ||
116 | struct bfin_pm_data bf609_pm_data; | |
117 | ||
118 | struct STRUCT_ROM_SYSCTRL configvalues; | |
119 | uint32_t dactionflags; | |
120 | ||
121 | #define FUNC_ROM_SYSCONTROL 0xC8000080 | |
122 | __attribute__((l1_data)) | |
123 | static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, struct STRUCT_ROM_SYSCTRL *settings, void *reserved) = (void *)FUNC_ROM_SYSCONTROL; | |
124 | ||
125 | __attribute__((l1_text)) | |
126 | void bfin_cpu_suspend(void) | |
127 | { | |
128 | __asm__ __volatile__( \ | |
129 | ".align 8;" \ | |
130 | "idle;" \ | |
131 | : : \ | |
132 | ); | |
133 | } | |
134 | ||
135 | __attribute__((l1_text)) | |
c7e48e1e | 136 | void bf609_ddr_sr(void) |
93f89519 | 137 | { |
c7e48e1e | 138 | dmc_enter_self_refresh(); |
93f89519 SM |
139 | } |
140 | ||
141 | __attribute__((l1_text)) | |
c7e48e1e | 142 | void bf609_ddr_sr_exit(void) |
93f89519 | 143 | { |
c7e48e1e | 144 | dmc_exit_self_refresh(); |
93f89519 | 145 | |
c7e48e1e SZ |
146 | /* After wake up from deep sleep and exit DDR from self refress mode, |
147 | * should wait till CGU PLL is locked. | |
148 | */ | |
149 | while (bfin_read32(CGU0_STAT) & CLKSALGN) | |
93f89519 SM |
150 | continue; |
151 | } | |
152 | ||
153 | __attribute__((l1_text)) | |
c7e48e1e | 154 | void bf609_resume_ccbuf(void) |
93f89519 | 155 | { |
c7e48e1e SZ |
156 | bfin_write32(DPM0_CCBF_EN, 3); |
157 | bfin_write32(DPM0_CTL, 2); | |
93f89519 | 158 | |
c7e48e1e | 159 | while ((bfin_read32(DPM0_STAT) & 0xf) != 1); |
93f89519 SM |
160 | } |
161 | ||
162 | __attribute__((l1_text)) | |
163 | void bfin_hibernate_syscontrol(void) | |
164 | { | |
165 | configvalues.ulWUA_Flags = (0xAD000000 | BITM_ROM_WUA_EN | |
166 | | BITM_ROM_WUA_CGU | BITM_ROM_WUA_DDR | BITM_ROM_WUA_DDRDLLEN); | |
167 | ||
168 | dactionflags = (BITM_ROM_SYSCTRL_WUA_EN | |
169 | | BITM_ROM_SYSCTRL_WUA_DPMWRITE | BITM_ROM_SYSCTRL_WUA_CGU | |
170 | | BITM_ROM_SYSCTRL_WUA_DDR | BITM_ROM_SYSCTRL_WUA_DDRDLLEN); | |
171 | ||
172 | bfrom_SysControl(dactionflags, &configvalues, NULL); | |
173 | ||
174 | bfin_write32(DPM0_RESTORE5, bfin_read32(DPM0_RESTORE5) | 4); | |
175 | } | |
176 | ||
c7e48e1e SZ |
177 | asmlinkage void enter_deepsleep(void); |
178 | ||
179 | __attribute__((l1_text)) | |
6b6c37bf | 180 | void bfin_deepsleep(unsigned long mask, unsigned long pol_mask) |
c7e48e1e | 181 | { |
6b6c37bf SM |
182 | bfin_write32(DPM0_WAKE_EN, mask); |
183 | bfin_write32(DPM0_WAKE_POL, pol_mask); | |
c7e48e1e SZ |
184 | SSYNC(); |
185 | enter_deepsleep(); | |
186 | } | |
187 | ||
6b6c37bf | 188 | void bfin_hibernate(unsigned long mask, unsigned long pol_mask) |
93f89519 | 189 | { |
6b6c37bf SM |
190 | bfin_write32(DPM0_WAKE_EN, mask); |
191 | bfin_write32(DPM0_WAKE_POL, pol_mask); | |
93f89519 SM |
192 | bfin_write32(DPM0_PGCNTR, 0x0000FFFF); |
193 | bfin_write32(DPM0_HIB_DIS, 0xFFFF); | |
194 | ||
93f89519 SM |
195 | bf609_hibernate(); |
196 | } | |
197 | ||
198 | void bf609_cpu_pm_enter(suspend_state_t state) | |
199 | { | |
200 | int error; | |
0fbd88ca SM |
201 | unsigned long wakeup = 0; |
202 | unsigned long wakeup_pol = 0; | |
203 | ||
204 | #ifdef CONFIG_PM_BFIN_WAKE_PA15 | |
205 | wakeup |= PA15WE; | |
206 | # if CONFIG_PM_BFIN_WAKE_PA15_POL | |
207 | wakeup_pol |= PA15WE; | |
208 | # endif | |
209 | #endif | |
210 | ||
211 | #ifdef CONFIG_PM_BFIN_WAKE_PB15 | |
212 | wakeup |= PB15WE; | |
213 | # if CONFIG_PM_BFIN_WAKE_PA15_POL | |
214 | wakeup_pol |= PB15WE; | |
215 | # endif | |
216 | #endif | |
217 | ||
218 | #ifdef CONFIG_PM_BFIN_WAKE_PC15 | |
219 | wakeup |= PC15WE; | |
220 | # if CONFIG_PM_BFIN_WAKE_PC15_POL | |
221 | wakeup_pol |= PC15WE; | |
222 | # endif | |
223 | #endif | |
224 | ||
225 | #ifdef CONFIG_PM_BFIN_WAKE_PD06 | |
226 | wakeup |= PD06WE; | |
227 | # if CONFIG_PM_BFIN_WAKE_PD06_POL | |
228 | wakeup_pol |= PD06WE; | |
229 | # endif | |
230 | #endif | |
231 | ||
232 | #ifdef CONFIG_PM_BFIN_WAKE_PE12 | |
233 | wakeup |= PE12WE; | |
234 | # if CONFIG_PM_BFIN_WAKE_PE12_POL | |
235 | wakeup_pol |= PE12WE; | |
236 | # endif | |
237 | #endif | |
238 | ||
239 | #ifdef CONFIG_PM_BFIN_WAKE_PG04 | |
240 | wakeup |= PG04WE; | |
241 | # if CONFIG_PM_BFIN_WAKE_PG04_POL | |
242 | wakeup_pol |= PG04WE; | |
243 | # endif | |
244 | #endif | |
245 | ||
246 | #ifdef CONFIG_PM_BFIN_WAKE_PG13 | |
247 | wakeup |= PG13WE; | |
248 | # if CONFIG_PM_BFIN_WAKE_PG13_POL | |
249 | wakeup_pol |= PG13WE; | |
250 | # endif | |
251 | #endif | |
252 | ||
253 | #ifdef CONFIG_PM_BFIN_WAKE_USB | |
254 | wakeup |= USBWE; | |
255 | # if CONFIG_PM_BFIN_WAKE_USB_POL | |
256 | wakeup_pol |= USBWE; | |
257 | # endif | |
258 | #endif | |
259 | ||
93f89519 SM |
260 | error = irq_set_irq_wake(255, 1); |
261 | if(error < 0) | |
262 | printk(KERN_DEBUG "Unable to get irq wake\n"); | |
263 | error = irq_set_irq_wake(231, 1); | |
264 | if (error < 0) | |
265 | printk(KERN_DEBUG "Unable to get irq wake\n"); | |
266 | ||
267 | if (state == PM_SUSPEND_STANDBY) | |
6b6c37bf | 268 | bfin_deepsleep(wakeup, wakeup_pol); |
93f89519 | 269 | else { |
6b6c37bf | 270 | bfin_hibernate(wakeup, wakeup_pol); |
93f89519 | 271 | } |
c7e48e1e | 272 | |
93f89519 SM |
273 | } |
274 | ||
275 | int bf609_cpu_pm_prepare(void) | |
276 | { | |
277 | return 0; | |
278 | } | |
279 | ||
280 | void bf609_cpu_pm_finish(void) | |
281 | { | |
282 | ||
283 | } | |
284 | ||
285 | static struct bfin_cpu_pm_fns bf609_cpu_pm = { | |
286 | .enter = bf609_cpu_pm_enter, | |
287 | .prepare = bf609_cpu_pm_prepare, | |
288 | .finish = bf609_cpu_pm_finish, | |
289 | }; | |
290 | ||
923680cb | 291 | #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE) |
6b6c37bf | 292 | static int smc_pm_syscore_suspend(void) |
923680cb SM |
293 | { |
294 | bf609_nor_flash_exit(); | |
6b6c37bf | 295 | return 0; |
923680cb SM |
296 | } |
297 | ||
298 | static void smc_pm_syscore_resume(void) | |
299 | { | |
300 | bf609_nor_flash_init(); | |
301 | } | |
302 | ||
303 | static struct syscore_ops smc_pm_syscore_ops = { | |
304 | .suspend = smc_pm_syscore_suspend, | |
305 | .resume = smc_pm_syscore_resume, | |
306 | }; | |
307 | #endif | |
308 | ||
93f89519 SM |
309 | static irqreturn_t test_isr(int irq, void *dev_id) |
310 | { | |
311 | printk(KERN_DEBUG "gpio irq %d\n", irq); | |
719154c6 | 312 | if (irq == 231) |
86794b43 | 313 | bfin_sec_raise_irq(BFIN_SYSIRQ(IRQ_SOFT1)); |
93f89519 SM |
314 | return IRQ_HANDLED; |
315 | } | |
316 | ||
317 | static irqreturn_t dpm0_isr(int irq, void *dev_id) | |
318 | { | |
c7e48e1e SZ |
319 | bfin_write32(DPM0_WAKE_STAT, bfin_read32(DPM0_WAKE_STAT)); |
320 | bfin_write32(CGU0_STAT, bfin_read32(CGU0_STAT)); | |
93f89519 SM |
321 | return IRQ_HANDLED; |
322 | } | |
323 | ||
324 | static int __init bf609_init_pm(void) | |
325 | { | |
326 | int irq; | |
327 | int error; | |
93f89519 | 328 | |
923680cb SM |
329 | #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE) |
330 | register_syscore_ops(&smc_pm_syscore_ops); | |
331 | #endif | |
332 | ||
c7e48e1e | 333 | #ifdef CONFIG_PM_BFIN_WAKE_PE12 |
93f89519 SM |
334 | irq = gpio_to_irq(GPIO_PE12); |
335 | if (irq < 0) { | |
336 | error = irq; | |
337 | printk(KERN_DEBUG "Unable to get irq number for GPIO %d, error %d\n", | |
338 | GPIO_PE12, error); | |
339 | } | |
340 | ||
d49cdf84 SM |
341 | error = request_irq(irq, test_isr, IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND |
342 | | IRQF_FORCE_RESUME, "gpiope12", NULL); | |
93f89519 SM |
343 | if(error < 0) |
344 | printk(KERN_DEBUG "Unable to get irq\n"); | |
345 | #endif | |
346 | ||
d49cdf84 SM |
347 | error = request_irq(IRQ_CGU_EVT, dpm0_isr, IRQF_NO_SUSPEND | |
348 | IRQF_FORCE_RESUME, "cgu0 event", NULL); | |
93f89519 SM |
349 | if(error < 0) |
350 | printk(KERN_DEBUG "Unable to get irq\n"); | |
351 | ||
d49cdf84 SM |
352 | error = request_irq(IRQ_DPM, dpm0_isr, IRQF_NO_SUSPEND | |
353 | IRQF_FORCE_RESUME, "dpm0 event", NULL); | |
93f89519 SM |
354 | if (error < 0) |
355 | printk(KERN_DEBUG "Unable to get irq\n"); | |
356 | ||
357 | bfin_cpu_pm = &bf609_cpu_pm; | |
358 | return 0; | |
359 | } | |
360 | ||
361 | late_initcall(bf609_init_pm); |