aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2012-07-22 23:35:30 -0400
committerBob Liu <lliubbo@gmail.com>2012-07-24 01:39:49 -0400
commitc7e48e1e3e926de21605f959c31689d56fb639e3 (patch)
tree4a598fd55ed79fdcf63077318e04d6f39be594d0 /arch/blackfin
parenta5b4d4be6ce7939d1604fae05786833fffae02f9 (diff)
bfin: pm: add deepsleep for bf60x
Add add deepsleep for bf60x. 1. Call DMC init functions to enter and exit DDR self refresh mode. 2. Wait till CGU PLL is locked after wake up and exit DDR self refresh mode. 3. Make asessembly function enter_deepsleep comply with C funtion ABI in order to call other C functions. 4. Switch kernel stack by register EX_SCRATCH_REG. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Bob Liu <lliubbo@gmail.com>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/include/asm/context.S9
-rw-r--r--arch/blackfin/mach-bf609/Makefile2
-rw-r--r--arch/blackfin/mach-bf609/dpm.S155
-rw-r--r--arch/blackfin/mach-bf609/hibernate.S65
-rw-r--r--arch/blackfin/mach-bf609/include/mach/pm.h6
-rw-r--r--arch/blackfin/mach-bf609/pm.c80
-rw-r--r--arch/blackfin/mach-common/entry.S7
7 files changed, 197 insertions, 127 deletions
diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S
index 1f9060395a0a..507e7aa6a561 100644
--- a/arch/blackfin/include/asm/context.S
+++ b/arch/blackfin/include/asm/context.S
@@ -396,3 +396,12 @@
396 call \func; 396 call \func;
397#endif 397#endif
398.endm 398.endm
399
400#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
401# define EX_SCRATCH_REG RETN
402#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)
403# define EX_SCRATCH_REG RETE
404#else
405# define EX_SCRATCH_REG CYCLES
406#endif
407
diff --git a/arch/blackfin/mach-bf609/Makefile b/arch/blackfin/mach-bf609/Makefile
index 2a27f8174543..9a3d9f252c11 100644
--- a/arch/blackfin/mach-bf609/Makefile
+++ b/arch/blackfin/mach-bf609/Makefile
@@ -3,4 +3,4 @@
3# 3#
4 4
5obj-y := dma.o clock.o 5obj-y := dma.o clock.o
6obj-$(CONFIG_PM) += pm.o hibernate.o 6obj-$(CONFIG_PM) += pm.o dpm.o
diff --git a/arch/blackfin/mach-bf609/dpm.S b/arch/blackfin/mach-bf609/dpm.S
new file mode 100644
index 000000000000..62cc31994298
--- /dev/null
+++ b/arch/blackfin/mach-bf609/dpm.S
@@ -0,0 +1,155 @@
1#include <linux/linkage.h>
2#include <asm/blackfin.h>
3#include <asm/dpmc.h>
4
5#include <asm/context.S>
6
7#define PM_STACK (COREA_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
8
9.section .l1.text
10ENTRY(_enter_hibernate)
11 /* switch stack to L1 scratch, prepare for ddr srfr */
12 P0.H = HI(PM_STACK);
13 P0.L = LO(PM_STACK);
14 SP = P0;
15
16 call _bf609_ddr_sr;
17 call _bfin_hibernate_syscontrol;
18
19 P0.H = HI(DPM0_RESTORE4);
20 P0.L = LO(DPM0_RESTORE4);
21 P1.H = _bf609_pm_data;
22 P1.L = _bf609_pm_data;
23 [P0] = P1;
24
25 P0.H = HI(DPM0_CTL);
26 P0.L = LO(DPM0_CTL);
27 R3.H = HI(0x00000010);
28 R3.L = LO(0x00000010);
29
30 bfin_init_pm_bench_cycles;
31
32 [P0] = R3;
33
34 SSYNC;
35ENDPROC(_enter_hibernate)
36
37/* DPM wake up interrupt won't wake up core on bf60x if its core IMASK
38 * is disabled. This behavior differ from bf5xx serial processor.
39 */
40ENTRY(_dummy_deepsleep)
41 [--sp] = SYSCFG;
42 [--sp] = (R7:0,P5:0);
43 cli r0;
44
45 /* get wake up interrupt ID */
46 P0.l = LO(SEC_SCI_BASE + SEC_CSID);
47 P0.h = HI(SEC_SCI_BASE + SEC_CSID);
48 R0 = [P0];
49
50 /* ACK wake up interrupt in SEC */
51 P1.l = LO(SEC_END);
52 P1.h = HI(SEC_END);
53
54 [P1] = R0;
55 SSYNC;
56
57 /* restore EVT 11 entry */
58 p0.h = hi(EVT11);
59 p0.l = lo(EVT11);
60 p1.h = _evt_evt11;
61 p1.l = _evt_evt11;
62
63 [p0] = p1;
64 SSYNC;
65
66 (R7:0,P5:0) = [sp++];
67 SYSCFG = [sp++];
68 RTI;
69ENDPROC(_dummy_deepsleep)
70
71ENTRY(_enter_deepsleep)
72 LINK 0x0;
73 [--sp] = (R7:0,P5:0);
74
75 /* Change EVT 11 entry to dummy handler for wake up event */
76 p0.h = hi(EVT11);
77 p0.l = lo(EVT11);
78 p1.h = _dummy_deepsleep;
79 p1.l = _dummy_deepsleep;
80
81 [p0] = p1;
82
83 P0.H = HI(PM_STACK);
84 P0.L = LO(PM_STACK);
85
86 EX_SCRATCH_REG = SP;
87 SP = P0;
88
89 SSYNC;
90
91 /* should put ddr to self refresh mode before sleep */
92 call _bf609_ddr_sr;
93
94 /* Set DPM controller to deep sleep mode */
95 P0.H = HI(DPM0_CTL);
96 P0.L = LO(DPM0_CTL);
97 R3.H = HI(0x00000008);
98 R3.L = LO(0x00000008);
99 [P0] = R3;
100 CSYNC;
101
102 /* Enable evt 11 in IMASK before idle, otherwise core doesn't wake up. */
103 r0.l = 0x800;
104 r0.h = 0;
105 sti r0;
106 SSYNC;
107
108 /* Fall into deep sleep in idle*/
109 idle;
110 SSYNC;
111
112 /* Restore PLL after wake up from deep sleep */
113 call _bf609_resume_ccbuf;
114
115 /* turn ddr out of self refresh mode */
116 call _bf609_ddr_sr_exit;
117
118 SP = EX_SCRATCH_REG;
119
120 (R7:0,P5:0) = [SP++];
121 UNLINK;
122 RTS;
123ENDPROC(_enter_deepsleep)
124
125.section .text
126ENTRY(_bf609_hibernate)
127 bfin_cpu_reg_save;
128 bfin_core_mmr_save;
129
130 P0.H = _bf609_pm_data;
131 P0.L = _bf609_pm_data;
132 R1.H = 0xDEAD;
133 R1.L = 0xBEEF;
134 R2.H = .Lpm_resume_here;
135 R2.L = .Lpm_resume_here;
136 [P0++] = R1;
137 [P0++] = R2;
138 [P0++] = SP;
139
140 P1.H = _enter_hibernate;
141 P1.L = _enter_hibernate;
142
143 call (P1);
144.Lpm_resume_here:
145
146 bfin_core_mmr_restore;
147 bfin_cpu_reg_restore;
148
149 [--sp] = RETI; /* Clear Global Interrupt Disable */
150 SP += 4;
151
152 RTS;
153
154ENDPROC(_bf609_hibernate)
155
diff --git a/arch/blackfin/mach-bf609/hibernate.S b/arch/blackfin/mach-bf609/hibernate.S
deleted file mode 100644
index d37a532519c8..000000000000
--- a/arch/blackfin/mach-bf609/hibernate.S
+++ /dev/null
@@ -1,65 +0,0 @@
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
8ENTRY(_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
28 bfin_init_pm_bench_cycles;
29
30 [P0] = R3;
31
32 SSYNC;
33ENDPROC(_enter_hibernate_mode)
34
35.section .text
36ENTRY(_bf609_hibernate)
37 bfin_cpu_reg_save;
38 bfin_core_mmr_save;
39
40 P0.H = _bf609_pm_data;
41 P0.L = _bf609_pm_data;
42 R1.H = 0xDEAD;
43 R1.L = 0xBEEF;
44 R2.H = .Lpm_resume_here;
45 R2.L = .Lpm_resume_here;
46 [P0++] = R1;
47 [P0++] = R2;
48 [P0++] = SP;
49
50 P1.H = _enter_hibernate;
51 P1.L = _enter_hibernate;
52
53 call (P1);
54.Lpm_resume_here:
55
56 bfin_core_mmr_restore;
57 bfin_cpu_reg_restore;
58
59 [--sp] = RETI; /* Clear Global Interrupt Disable */
60 SP += 4;
61
62 RTS;
63
64ENDPROC(_bf609_hibernate)
65
diff --git a/arch/blackfin/mach-bf609/include/mach/pm.h b/arch/blackfin/mach-bf609/include/mach/pm.h
index 036d9bdc889e..68435f9bafca 100644
--- a/arch/blackfin/mach-bf609/include/mach/pm.h
+++ b/arch/blackfin/mach-bf609/include/mach/pm.h
@@ -11,9 +11,9 @@
11 11
12#include <linux/suspend.h> 12#include <linux/suspend.h>
13 13
14int bfin609_pm_enter(suspend_state_t state); 14extern int bfin609_pm_enter(suspend_state_t state);
15int bf609_pm_prepare(void); 15extern int bf609_pm_prepare(void);
16void bf609_pm_finish(void); 16extern void bf609_pm_finish(void);
17 17
18void bf609_hibernate(void); 18void bf609_hibernate(void);
19void bfin_sec_raise_irq(unsigned int sid); 19void bfin_sec_raise_irq(unsigned int sid);
diff --git a/arch/blackfin/mach-bf609/pm.c b/arch/blackfin/mach-bf609/pm.c
index b76966eb16ad..6094c7d3b1f2 100644
--- a/arch/blackfin/mach-bf609/pm.c
+++ b/arch/blackfin/mach-bf609/pm.c
@@ -18,6 +18,7 @@
18#include <asm/pm.h> 18#include <asm/pm.h>
19#include <mach/pm.h> 19#include <mach/pm.h>
20#include <asm/blackfin.h> 20#include <asm/blackfin.h>
21#include <asm/mem_init.h>
21 22
22/***********************************************************/ 23/***********************************************************/
23/* */ 24/* */
@@ -132,60 +133,30 @@ void bfin_cpu_suspend(void)
132} 133}
133 134
134__attribute__((l1_text)) 135__attribute__((l1_text))
135void bfin_deepsleep(unsigned long mask) 136void bf609_ddr_sr(void)
136{ 137{
137 uint32_t dpm0_ctl; 138 dmc_enter_self_refresh();
138
139 bfin_write32(DPM0_WAKE_EN, 0x10);
140 bfin_write32(DPM0_WAKE_POL, 0x10);
141 dpm0_ctl = 0x00000008;
142 bfin_write32(DPM0_CTL, dpm0_ctl);
143 SSYNC();
144 __asm__ __volatile__( \
145 ".align 8;" \
146 "idle;" \
147 : : \
148 );
149#ifdef CONFIG_BFIN_PM_WAKEUP_TIME_BENCH
150 __asm__ __volatile__(
151 "R0 = 0;"
152 "CYCLES = R0;"
153 "CYCLES2 = R0;"
154 "R0 = SYSCFG;"
155 "BITSET(R0, 1);"
156 "SYSCFG = R0;"
157 : : : "R0"
158 );
159#endif
160
161} 139}
162 140
163__attribute__((l1_text)) 141__attribute__((l1_text))
164void bf609_ddr_sr(void) 142void bf609_ddr_sr_exit(void)
165{ 143{
166 uint32_t reg; 144 dmc_exit_self_refresh();
167
168 reg = bfin_read_DMC0_CTL();
169 reg |= 0x8;
170 bfin_write_DMC0_CTL(reg);
171 145
172 while (!(bfin_read_DMC0_STAT() & 0x8)) 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)
173 continue; 150 continue;
174} 151}
175 152
176__attribute__((l1_text)) 153__attribute__((l1_text))
177void bf609_ddr_sr_exit(void) 154void bf609_resume_ccbuf(void)
178{ 155{
179 uint32_t reg; 156 bfin_write32(DPM0_CCBF_EN, 3);
180 while (!(bfin_read_DMC0_STAT() & 0x1)) 157 bfin_write32(DPM0_CTL, 2);
181 continue;
182 158
183 reg = bfin_read_DMC0_CTL(); 159 while ((bfin_read32(DPM0_STAT) & 0xf) != 1);
184 reg &= ~0x8;
185 bfin_write_DMC0_CTL(reg);
186
187 while ((bfin_read_DMC0_STAT() & 0x8))
188 continue;
189} 160}
190 161
191__attribute__((l1_text)) 162__attribute__((l1_text))
@@ -208,6 +179,17 @@ void bfin_hibernate_syscontrol(void)
208#else 179#else
209# define SIC_SYSIRQ(irq) ((irq) - IVG15) 180# define SIC_SYSIRQ(irq) ((irq) - IVG15)
210#endif 181#endif
182asmlinkage void enter_deepsleep(void);
183
184__attribute__((l1_text))
185void bfin_deepsleep(unsigned long mask)
186{
187 bfin_write32(DPM0_WAKE_EN, 0x10);
188 bfin_write32(DPM0_WAKE_POL, 0x10);
189 SSYNC();
190 enter_deepsleep();
191}
192
211void bfin_hibernate(unsigned long mask) 193void bfin_hibernate(unsigned long mask)
212{ 194{
213 bfin_write32(DPM0_WAKE_EN, 0x10); 195 bfin_write32(DPM0_WAKE_EN, 0x10);
@@ -215,8 +197,6 @@ void bfin_hibernate(unsigned long mask)
215 bfin_write32(DPM0_PGCNTR, 0x0000FFFF); 197 bfin_write32(DPM0_PGCNTR, 0x0000FFFF);
216 bfin_write32(DPM0_HIB_DIS, 0xFFFF); 198 bfin_write32(DPM0_HIB_DIS, 0xFFFF);
217 199
218 printk(KERN_DEBUG "hibernate: restore %x pgcnt %x\n", bfin_read32(DPM0_RESTORE0), bfin_read32(DPM0_PGCNTR));
219
220 bf609_hibernate(); 200 bf609_hibernate();
221} 201}
222 202
@@ -294,6 +274,7 @@ void bf609_cpu_pm_enter(suspend_state_t state)
294 else { 274 else {
295 bfin_hibernate(wakeup); 275 bfin_hibernate(wakeup);
296 } 276 }
277
297} 278}
298 279
299int bf609_cpu_pm_prepare(void) 280int bf609_cpu_pm_prepare(void)
@@ -320,21 +301,18 @@ static irqreturn_t test_isr(int irq, void *dev_id)
320 301
321static irqreturn_t dpm0_isr(int irq, void *dev_id) 302static irqreturn_t dpm0_isr(int irq, void *dev_id)
322{ 303{
323 uint32_t wake_stat; 304 bfin_write32(DPM0_WAKE_STAT, bfin_read32(DPM0_WAKE_STAT));
324 305 bfin_write32(CGU0_STAT, bfin_read32(CGU0_STAT));
325 wake_stat = bfin_read32(DPM0_WAKE_STAT);
326 printk(KERN_DEBUG "enter %s wake stat %08x\n", __func__, wake_stat);
327
328 bfin_write32(DPM0_WAKE_STAT, wake_stat);
329 return IRQ_HANDLED; 306 return IRQ_HANDLED;
330} 307}
308#endif
331 309
332static int __init bf609_init_pm(void) 310static int __init bf609_init_pm(void)
333{ 311{
334 int irq; 312 int irq;
335 int error; 313 int error;
336 314
337#if CONFIG_PM_BFIN_WAKE_PE12 315#ifdef CONFIG_PM_BFIN_WAKE_PE12
338 irq = gpio_to_irq(GPIO_PE12); 316 irq = gpio_to_irq(GPIO_PE12);
339 if (irq < 0) { 317 if (irq < 0) {
340 error = irq; 318 error = irq;
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 04c2fbe41a7f..1c3d2c5bb0bb 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -25,13 +25,6 @@
25 25
26#include <asm/context.S> 26#include <asm/context.S>
27 27
28#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
29# define EX_SCRATCH_REG RETN
30#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)
31# define EX_SCRATCH_REG RETE
32#else
33# define EX_SCRATCH_REG CYCLES
34#endif
35 28
36#ifdef CONFIG_EXCPT_IRQ_SYSC_L1 29#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
37.section .l1.text 30.section .l1.text