diff options
author | Steven Miao <realmz6@gmail.com> | 2012-05-16 06:26:10 -0400 |
---|---|---|
committer | Bob Liu <lliubbo@gmail.com> | 2012-05-21 02:54:24 -0400 |
commit | 93f89519fd31c21e5d606faf4091f5905db38412 (patch) | |
tree | 642d8605e14281e8f69a54e2130a7898754289ba /arch/blackfin/mach-bf609 | |
parent | b2cfc653a513f347114c85ed8e75456ea0159c18 (diff) |
blackfin: bf60x: add power management support
Add bf60x cpu pm callbacks and change blackfin pm framework to support bf60x.
Signed-off-by: Steven Miao <realmz6@gmail.com>
Signed-off-by: Bob Liu <lliubbo@gmail.com>
Diffstat (limited to 'arch/blackfin/mach-bf609')
-rw-r--r-- | arch/blackfin/mach-bf609/hibernate.S | 62 | ||||
-rw-r--r-- | arch/blackfin/mach-bf609/include/mach/pm.h | 21 | ||||
-rw-r--r-- | arch/blackfin/mach-bf609/pm.c | 310 |
3 files changed, 393 insertions, 0 deletions
diff --git a/arch/blackfin/mach-bf609/hibernate.S b/arch/blackfin/mach-bf609/hibernate.S new file mode 100644 index 000000000000..baedd6e6abf4 --- /dev/null +++ b/arch/blackfin/mach-bf609/hibernate.S | |||
@@ -0,0 +1,62 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | #include <asm/blackfin.h> | ||
3 | #include <asm/dpmc.h> | ||
4 | |||
5 | #define PM_STACK (COREA_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12) | ||
6 | |||
7 | .section .l1.text | ||
8 | ENTRY(_enter_hibernate) | ||
9 | /* switch stack to L1 scratch, prepare for ddr srfr */ | ||
10 | P0.H = HI(PM_STACK); | ||
11 | P0.L = LO(PM_STACK); | ||
12 | SP = P0; | ||
13 | |||
14 | call _bf609_ddr_sr; | ||
15 | call _bfin_hibernate_syscontrol; | ||
16 | |||
17 | P0.H = HI(DPM0_RESTORE4); | ||
18 | P0.L = LO(DPM0_RESTORE4); | ||
19 | P1.H = _bf609_pm_data; | ||
20 | P1.L = _bf609_pm_data; | ||
21 | [P0] = P1; | ||
22 | |||
23 | P0.H = HI(DPM0_CTL); | ||
24 | P0.L = LO(DPM0_CTL); | ||
25 | R3.H = HI(0x00000010); | ||
26 | R3.L = LO(0x00000010); | ||
27 | [P0] = R3; | ||
28 | |||
29 | SSYNC; | ||
30 | ENDPROC(_enter_hibernate_mode) | ||
31 | |||
32 | .section .text | ||
33 | ENTRY(_bf609_hibernate) | ||
34 | bfin_cpu_reg_save; | ||
35 | bfin_core_mmr_save; | ||
36 | |||
37 | P0.H = _bf609_pm_data; | ||
38 | P0.L = _bf609_pm_data; | ||
39 | R1.H = 0xDEAD; | ||
40 | R1.L = 0xBEEF; | ||
41 | R2.H = .Lpm_resume_here; | ||
42 | R2.L = .Lpm_resume_here; | ||
43 | [P0++] = R1; | ||
44 | [P0++] = R2; | ||
45 | [P0++] = SP; | ||
46 | |||
47 | P1.H = _enter_hibernate; | ||
48 | P1.L = _enter_hibernate; | ||
49 | |||
50 | call (P1); | ||
51 | .Lpm_resume_here: | ||
52 | |||
53 | bfin_core_mmr_restore; | ||
54 | bfin_cpu_reg_restore; | ||
55 | |||
56 | [--sp] = RETI; /* Clear Global Interrupt Disable */ | ||
57 | SP += 4; | ||
58 | |||
59 | RTS; | ||
60 | |||
61 | ENDPROC(_bf609_hibernate) | ||
62 | |||
diff --git a/arch/blackfin/mach-bf609/include/mach/pm.h b/arch/blackfin/mach-bf609/include/mach/pm.h new file mode 100644 index 000000000000..036d9bdc889e --- /dev/null +++ b/arch/blackfin/mach-bf609/include/mach/pm.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * Blackfin bf609 power management | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 | ||
7 | */ | ||
8 | |||
9 | #ifndef __MACH_BF609_PM_H__ | ||
10 | #define __MACH_BF609_PM_H__ | ||
11 | |||
12 | #include <linux/suspend.h> | ||
13 | |||
14 | int bfin609_pm_enter(suspend_state_t state); | ||
15 | int bf609_pm_prepare(void); | ||
16 | void bf609_pm_finish(void); | ||
17 | |||
18 | void bf609_hibernate(void); | ||
19 | void bfin_sec_raise_irq(unsigned int sid); | ||
20 | void coreb_enable(void); | ||
21 | #endif | ||
diff --git a/arch/blackfin/mach-bf609/pm.c b/arch/blackfin/mach-bf609/pm.c new file mode 100644 index 000000000000..bbc5a79b5e22 --- /dev/null +++ b/arch/blackfin/mach-bf609/pm.c | |||
@@ -0,0 +1,310 @@ | |||
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> | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | |||
17 | #include <asm/dpmc.h> | ||
18 | #include <asm/pm.h> | ||
19 | #include <mach/pm.h> | ||
20 | #include <asm/blackfin.h> | ||
21 | |||
22 | /***********************************************************/ | ||
23 | /* */ | ||
24 | /* Wakeup Actions for DPM_RESTORE */ | ||
25 | /* */ | ||
26 | /***********************************************************/ | ||
27 | #define BITP_ROM_WUA_CHKHDR 24 | ||
28 | #define BITP_ROM_WUA_DDRLOCK 7 | ||
29 | #define BITP_ROM_WUA_DDRDLLEN 6 | ||
30 | #define BITP_ROM_WUA_DDR 5 | ||
31 | #define BITP_ROM_WUA_CGU 4 | ||
32 | #define BITP_ROM_WUA_MEMBOOT 2 | ||
33 | #define BITP_ROM_WUA_EN 1 | ||
34 | |||
35 | #define BITM_ROM_WUA_CHKHDR (0xFF000000) | ||
36 | #define ENUM_ROM_WUA_CHKHDR_AD 0xAD000000 | ||
37 | |||
38 | #define BITM_ROM_WUA_DDRLOCK (0x00000080) | ||
39 | #define BITM_ROM_WUA_DDRDLLEN (0x00000040) | ||
40 | #define BITM_ROM_WUA_DDR (0x00000020) | ||
41 | #define BITM_ROM_WUA_CGU (0x00000010) | ||
42 | #define BITM_ROM_WUA_MEMBOOT (0x00000002) | ||
43 | #define BITM_ROM_WUA_EN (0x00000001) | ||
44 | |||
45 | /***********************************************************/ | ||
46 | /* */ | ||
47 | /* Syscontrol */ | ||
48 | /* */ | ||
49 | /***********************************************************/ | ||
50 | #define BITP_ROM_SYSCTRL_CGU_LOCKINGEN 28 /* unlocks CGU_CTL register */ | ||
51 | #define BITP_ROM_SYSCTRL_WUA_OVERRIDE 24 | ||
52 | #define BITP_ROM_SYSCTRL_WUA_DDRDLLEN 20 /* Saves the DDR DLL and PADS registers to the DPM registers */ | ||
53 | #define BITP_ROM_SYSCTRL_WUA_DDR 19 /* Saves the DDR registers to the DPM registers */ | ||
54 | #define BITP_ROM_SYSCTRL_WUA_CGU 18 /* Saves the CGU registers into DPM registers */ | ||
55 | #define BITP_ROM_SYSCTRL_WUA_DPMWRITE 17 /* Saves the Syscontrol structure structure contents into DPM registers */ | ||
56 | #define BITP_ROM_SYSCTRL_WUA_EN 16 /* reads current PLL and DDR configuration into structure */ | ||
57 | #define BITP_ROM_SYSCTRL_DDR_WRITE 13 /* writes the DDR registers from Syscontrol structure for wakeup initialization of DDR */ | ||
58 | #define BITP_ROM_SYSCTRL_DDR_READ 12 /* Read the DDR registers into the Syscontrol structure for storing prior to hibernate */ | ||
59 | #define BITP_ROM_SYSCTRL_CGU_AUTODIS 11 /* Disables auto handling of UPDT and ALGN fields */ | ||
60 | #define BITP_ROM_SYSCTRL_CGU_CLKOUTSEL 7 /* access CGU_CLKOUTSEL register */ | ||
61 | #define BITP_ROM_SYSCTRL_CGU_DIV 6 /* access CGU_DIV register */ | ||
62 | #define BITP_ROM_SYSCTRL_CGU_STAT 5 /* access CGU_STAT register */ | ||
63 | #define BITP_ROM_SYSCTRL_CGU_CTL 4 /* access CGU_CTL register */ | ||
64 | #define BITP_ROM_SYSCTRL_CGU_RTNSTAT 2 /* Update structure STAT field upon error */ | ||
65 | #define BITP_ROM_SYSCTRL_WRITE 1 /* write registers */ | ||
66 | #define BITP_ROM_SYSCTRL_READ 0 /* read registers */ | ||
67 | |||
68 | #define BITM_ROM_SYSCTRL_CGU_READ (0x00000001) /* Read CGU registers */ | ||
69 | #define BITM_ROM_SYSCTRL_CGU_WRITE (0x00000002) /* Write registers */ | ||
70 | #define BITM_ROM_SYSCTRL_CGU_RTNSTAT (0x00000004) /* Update structure STAT field upon error or after a write operation */ | ||
71 | #define BITM_ROM_SYSCTRL_CGU_CTL (0x00000010) /* Access CGU_CTL register */ | ||
72 | #define BITM_ROM_SYSCTRL_CGU_STAT (0x00000020) /* Access CGU_STAT register */ | ||
73 | #define BITM_ROM_SYSCTRL_CGU_DIV (0x00000040) /* Access CGU_DIV register */ | ||
74 | #define BITM_ROM_SYSCTRL_CGU_CLKOUTSEL (0x00000080) /* Access CGU_CLKOUTSEL register */ | ||
75 | #define BITM_ROM_SYSCTRL_CGU_AUTODIS (0x00000800) /* Disables auto handling of UPDT and ALGN fields */ | ||
76 | #define BITM_ROM_SYSCTRL_DDR_READ (0x00001000) /* Reads the contents of the DDR registers and stores them into the structure */ | ||
77 | #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 */ | ||
78 | #define BITM_ROM_SYSCTRL_WUA_EN (0x00010000) /* Wakeup entry or exit opertation enable */ | ||
79 | #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 */ | ||
80 | #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 */ | ||
81 | #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 */ | ||
82 | #define BITM_ROM_SYSCTRL_WUA_DDRDLLEN (0x00100000) /* Enables saving/restoring of the DDR DLLCTL register */ | ||
83 | #define BITM_ROM_SYSCTRL_WUA_OVERRIDE (0x01000000) | ||
84 | #define BITM_ROM_SYSCTRL_CGU_LOCKINGEN (0x10000000) /* Unlocks the CGU_CTL register */ | ||
85 | |||
86 | |||
87 | /* Structures for the syscontrol() function */ | ||
88 | struct STRUCT_ROM_SYSCTRL { | ||
89 | uint32_t ulCGU_CTL; | ||
90 | uint32_t ulCGU_STAT; | ||
91 | uint32_t ulCGU_DIV; | ||
92 | uint32_t ulCGU_CLKOUTSEL; | ||
93 | uint32_t ulWUA_Flags; | ||
94 | uint32_t ulWUA_BootAddr; | ||
95 | uint32_t ulWUA_User; | ||
96 | uint32_t ulDDR_CTL; | ||
97 | uint32_t ulDDR_CFG; | ||
98 | uint32_t ulDDR_TR0; | ||
99 | uint32_t ulDDR_TR1; | ||
100 | uint32_t ulDDR_TR2; | ||
101 | uint32_t ulDDR_MR; | ||
102 | uint32_t ulDDR_EMR1; | ||
103 | uint32_t ulDDR_EMR2; | ||
104 | uint32_t ulDDR_PADCTL; | ||
105 | uint32_t ulDDR_DLLCTL; | ||
106 | uint32_t ulReserved; | ||
107 | }; | ||
108 | |||
109 | struct bfin_pm_data { | ||
110 | uint32_t magic; | ||
111 | uint32_t resume_addr; | ||
112 | uint32_t sp; | ||
113 | }; | ||
114 | |||
115 | struct bfin_pm_data bf609_pm_data; | ||
116 | |||
117 | struct STRUCT_ROM_SYSCTRL configvalues; | ||
118 | uint32_t dactionflags; | ||
119 | |||
120 | #define FUNC_ROM_SYSCONTROL 0xC8000080 | ||
121 | __attribute__((l1_data)) | ||
122 | static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, struct STRUCT_ROM_SYSCTRL *settings, void *reserved) = (void *)FUNC_ROM_SYSCONTROL; | ||
123 | |||
124 | __attribute__((l1_text)) | ||
125 | void bfin_cpu_suspend(void) | ||
126 | { | ||
127 | __asm__ __volatile__( \ | ||
128 | ".align 8;" \ | ||
129 | "idle;" \ | ||
130 | : : \ | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | __attribute__((l1_text)) | ||
135 | void bfin_deepsleep(unsigned long mask) | ||
136 | { | ||
137 | uint32_t dpm0_ctl; | ||
138 | |||
139 | bfin_write32(DPM0_WAKE_EN, 0x10); | ||
140 | bfin_write32(DPM0_WAKE_POL, 0x10); | ||
141 | dpm0_ctl = bfin_read32(DPM0_CTL); | ||
142 | dpm0_ctl = 0x00000008; | ||
143 | bfin_write32(DPM0_CTL, dpm0_ctl); | ||
144 | SSYNC(); | ||
145 | __asm__ __volatile__( \ | ||
146 | ".align 8;" \ | ||
147 | "idle;" \ | ||
148 | : : \ | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | __attribute__((l1_text)) | ||
153 | void bf609_ddr_sr(void) | ||
154 | { | ||
155 | uint32_t reg; | ||
156 | |||
157 | reg = bfin_read_DDR0_CTL(); | ||
158 | reg |= 0x8; | ||
159 | bfin_write_DDR0_CTL(reg); | ||
160 | |||
161 | while (!(bfin_read_DDR0_STAT() & 0x8)) | ||
162 | continue; | ||
163 | } | ||
164 | |||
165 | __attribute__((l1_text)) | ||
166 | void bf609_ddr_sr_exit(void) | ||
167 | { | ||
168 | uint32_t reg; | ||
169 | while (!(bfin_read_DDR0_STAT() & 0x1)) | ||
170 | continue; | ||
171 | |||
172 | reg = bfin_read_DDR0_CTL(); | ||
173 | reg &= ~0x8; | ||
174 | bfin_write_DDR0_CTL(reg); | ||
175 | |||
176 | while ((bfin_read_DDR0_STAT() & 0x8)) | ||
177 | continue; | ||
178 | } | ||
179 | |||
180 | __attribute__((l1_text)) | ||
181 | void bfin_hibernate_syscontrol(void) | ||
182 | { | ||
183 | configvalues.ulWUA_Flags = (0xAD000000 | BITM_ROM_WUA_EN | ||
184 | | BITM_ROM_WUA_CGU | BITM_ROM_WUA_DDR | BITM_ROM_WUA_DDRDLLEN); | ||
185 | |||
186 | dactionflags = (BITM_ROM_SYSCTRL_WUA_EN | ||
187 | | BITM_ROM_SYSCTRL_WUA_DPMWRITE | BITM_ROM_SYSCTRL_WUA_CGU | ||
188 | | BITM_ROM_SYSCTRL_WUA_DDR | BITM_ROM_SYSCTRL_WUA_DDRDLLEN); | ||
189 | |||
190 | bfrom_SysControl(dactionflags, &configvalues, NULL); | ||
191 | |||
192 | bfin_write32(DPM0_RESTORE5, bfin_read32(DPM0_RESTORE5) | 4); | ||
193 | } | ||
194 | |||
195 | #ifndef CONFIG_BF60x | ||
196 | # define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1)) | ||
197 | #else | ||
198 | # define SIC_SYSIRQ(irq) ((irq) - IVG15) | ||
199 | #endif | ||
200 | void bfin_hibernate(unsigned long mask) | ||
201 | { | ||
202 | bfin_write32(DPM0_WAKE_EN, 0x10); | ||
203 | bfin_write32(DPM0_WAKE_POL, 0x10); | ||
204 | bfin_write32(DPM0_PGCNTR, 0x0000FFFF); | ||
205 | bfin_write32(DPM0_HIB_DIS, 0xFFFF); | ||
206 | |||
207 | printk(KERN_DEBUG "hibernate: restore %x pgcnt %x\n", bfin_read32(DPM0_RESTORE0), bfin_read32(DPM0_PGCNTR)); | ||
208 | |||
209 | bf609_hibernate(); | ||
210 | } | ||
211 | |||
212 | void bf609_cpu_pm_enter(suspend_state_t state) | ||
213 | { | ||
214 | int error; | ||
215 | error = irq_set_irq_wake(255, 1); | ||
216 | if(error < 0) | ||
217 | printk(KERN_DEBUG "Unable to get irq wake\n"); | ||
218 | error = irq_set_irq_wake(231, 1); | ||
219 | if (error < 0) | ||
220 | printk(KERN_DEBUG "Unable to get irq wake\n"); | ||
221 | |||
222 | if (state == PM_SUSPEND_STANDBY) | ||
223 | bfin_deepsleep(0xffff); | ||
224 | else { | ||
225 | bfin_hibernate(0xffff); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | int bf609_cpu_pm_prepare(void) | ||
230 | { | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | void bf609_cpu_pm_finish(void) | ||
235 | { | ||
236 | |||
237 | } | ||
238 | |||
239 | static struct bfin_cpu_pm_fns bf609_cpu_pm = { | ||
240 | .enter = bf609_cpu_pm_enter, | ||
241 | .prepare = bf609_cpu_pm_prepare, | ||
242 | .finish = bf609_cpu_pm_finish, | ||
243 | }; | ||
244 | |||
245 | static irqreturn_t test_isr(int irq, void *dev_id) | ||
246 | { | ||
247 | printk(KERN_DEBUG "gpio irq %d\n", irq); | ||
248 | return IRQ_HANDLED; | ||
249 | } | ||
250 | |||
251 | static irqreturn_t dpm0_isr(int irq, void *dev_id) | ||
252 | { | ||
253 | uint32_t wake_stat; | ||
254 | |||
255 | wake_stat = bfin_read32(DPM0_WAKE_STAT); | ||
256 | printk(KERN_DEBUG "enter %s wake stat %08x\n", __func__, wake_stat); | ||
257 | |||
258 | bfin_write32(DPM0_WAKE_STAT, wake_stat); | ||
259 | return IRQ_HANDLED; | ||
260 | } | ||
261 | |||
262 | static int __init bf609_init_pm(void) | ||
263 | { | ||
264 | int irq; | ||
265 | int error; | ||
266 | error = gpio_request(GPIO_PG4, "gpiopg4"); | ||
267 | if (error < 0) { | ||
268 | printk(KERN_DEBUG "failed to request GPIO %d, error %d\n", | ||
269 | GPIO_PG4, error); | ||
270 | } | ||
271 | |||
272 | irq = gpio_to_irq(GPIO_PG4); | ||
273 | if (irq < 0) { | ||
274 | error = irq; | ||
275 | printk(KERN_DEBUG "Unable to get irq number for GPIO %d, error %d\n", | ||
276 | GPIO_PG4, error); | ||
277 | } | ||
278 | |||
279 | printk(KERN_DEBUG "%s gpio %d irq %d\n", __func__, GPIO_PG4, irq); | ||
280 | |||
281 | error = request_irq(irq, test_isr, IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND, "gpiopg4", NULL); | ||
282 | if(error < 0) | ||
283 | printk(KERN_DEBUG "Unable to get irq\n"); | ||
284 | |||
285 | #if 1 | ||
286 | irq = gpio_to_irq(GPIO_PE12); | ||
287 | if (irq < 0) { | ||
288 | error = irq; | ||
289 | printk(KERN_DEBUG "Unable to get irq number for GPIO %d, error %d\n", | ||
290 | GPIO_PE12, error); | ||
291 | } | ||
292 | |||
293 | error = request_irq(irq, test_isr, IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "gpiope12", NULL); | ||
294 | if(error < 0) | ||
295 | printk(KERN_DEBUG "Unable to get irq\n"); | ||
296 | #endif | ||
297 | |||
298 | error = request_irq(IRQ_CGU_EVT, dpm0_isr, IRQF_NO_SUSPEND, "cgu0 event", NULL); | ||
299 | if(error < 0) | ||
300 | printk(KERN_DEBUG "Unable to get irq\n"); | ||
301 | |||
302 | error = request_irq(IRQ_DPM, dpm0_isr, IRQF_NO_SUSPEND, "dpm0 event", NULL); | ||
303 | if (error < 0) | ||
304 | printk(KERN_DEBUG "Unable to get irq\n"); | ||
305 | |||
306 | bfin_cpu_pm = &bf609_cpu_pm; | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | late_initcall(bf609_init_pm); | ||