• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2004-2008 Analog Devices Inc.
3 *
4 * Licensed under the GPL-2 or later.
5 */
6
7#include <linux/linkage.h>
8#include <asm/blackfin.h>
9#include <mach/irq.h>
10#include <asm/dpmc.h>
11
12.section .l1.text
13ENTRY(_sleep_mode)
14	[--SP] = (R7:4, P5:3);
15	[--SP] = RETS;
16
17	call _set_sic_iwr;
18
19	P0.H = hi(PLL_CTL);
20	P0.L = lo(PLL_CTL);
21	R1 = W[P0](z);
22	BITSET (R1, 3);
23	W[P0] = R1.L;
24
25	CLI R2;
26	SSYNC;
27	IDLE;
28	STI R2;
29
30	call _test_pll_locked;
31
32	R0 = IWR_ENABLE(0);
33	R1 = IWR_DISABLE_ALL;
34	R2 = IWR_DISABLE_ALL;
35
36	call _set_sic_iwr;
37
38	P0.H = hi(PLL_CTL);
39	P0.L = lo(PLL_CTL);
40	R7 = w[p0](z);
41	BITCLR (R7, 3);
42	BITCLR (R7, 5);
43	w[p0] = R7.L;
44	IDLE;
45
46	bfin_init_pm_bench_cycles;
47
48	call _test_pll_locked;
49
50	RETS = [SP++];
51	(R7:4, P5:3) = [SP++];
52	RTS;
53ENDPROC(_sleep_mode)
54
55/*
56 * This func never returns as it puts the part into hibernate, and
57 * is only called from do_hibernate, so we don't bother saving or
58 * restoring any of the normal C runtime state.  When we wake up,
59 * the entry point will be in do_hibernate and not here.
60 *
61 * We accept just one argument -- the value to write to VR_CTL.
62 */
63
64ENTRY(_hibernate_mode)
65	/* Save/setup the regs we need early for minor pipeline optimization */
66	R4 = R0;
67
68	P3.H = hi(VR_CTL);
69	P3.L = lo(VR_CTL);
70	/* Disable all wakeup sources */
71	R0 = IWR_DISABLE_ALL;
72	R1 = IWR_DISABLE_ALL;
73	R2 = IWR_DISABLE_ALL;
74	call _set_sic_iwr;
75	call _set_dram_srfs;
76	SSYNC;
77
78	/* Finally, we climb into our cave to hibernate */
79	W[P3] = R4.L;
80
81	bfin_init_pm_bench_cycles;
82
83	CLI R2;
84	IDLE;
85.Lforever:
86	jump .Lforever;
87ENDPROC(_hibernate_mode)
88
89ENTRY(_sleep_deeper)
90	[--SP] = (R7:4, P5:3);
91	[--SP] = RETS;
92
93	CLI R4;
94
95	P3 = R0;
96	P4 = R1;
97	P5 = R2;
98
99	R0 = IWR_ENABLE(0);
100	R1 = IWR_DISABLE_ALL;
101	R2 = IWR_DISABLE_ALL;
102
103	call _set_sic_iwr;
104	call _set_dram_srfs;	/* Set SDRAM Self Refresh */
105
106	P0.H = hi(PLL_DIV);
107	P0.L = lo(PLL_DIV);
108	R6 = W[P0](z);
109	R0.L = 0xF;
110	W[P0] = R0.l;		/* Set Max VCO to SCLK divider */
111
112	P0.H = hi(PLL_CTL);
113	P0.L = lo(PLL_CTL);
114	R5 = W[P0](z);
115	R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9;
116	W[P0] = R0.l;		/* Set Min CLKIN to VCO multiplier */
117
118	SSYNC;
119	IDLE;
120
121	call _test_pll_locked;
122
123	P0.H = hi(VR_CTL);
124	P0.L = lo(VR_CTL);
125	R7 = W[P0](z);
126	R1 = 0x6;
127	R1 <<= 16;
128	R2 = 0x0404(Z);
129	R1 = R1|R2;
130
131	R2 = DEPOSIT(R7, R1);
132	W[P0] = R2;		/* Set Min Core Voltage */
133
134	SSYNC;
135	IDLE;
136
137	call _test_pll_locked;
138
139	R0 = P3;
140	R1 = P4;
141	R3 = P5;
142	call _set_sic_iwr;	/* Set Awake from IDLE */
143
144	P0.H = hi(PLL_CTL);
145	P0.L = lo(PLL_CTL);
146	R0 = W[P0](z);
147	BITSET (R0, 3);
148	W[P0] = R0.L;		/* Turn CCLK OFF */
149	SSYNC;
150	IDLE;
151
152	call _test_pll_locked;
153
154	R0 = IWR_ENABLE(0);
155	R1 = IWR_DISABLE_ALL;
156	R2 = IWR_DISABLE_ALL;
157
158	call _set_sic_iwr;	/* Set Awake from IDLE PLL */
159
160	P0.H = hi(VR_CTL);
161	P0.L = lo(VR_CTL);
162	W[P0]= R7;
163
164	SSYNC;
165	IDLE;
166
167	bfin_init_pm_bench_cycles;
168
169	call _test_pll_locked;
170
171	P0.H = hi(PLL_DIV);
172	P0.L = lo(PLL_DIV);
173	W[P0]= R6;		/* Restore CCLK and SCLK divider */
174
175	P0.H = hi(PLL_CTL);
176	P0.L = lo(PLL_CTL);
177	w[p0] = R5;		/* Restore VCO multiplier */
178	IDLE;
179	call _test_pll_locked;
180
181	call _unset_dram_srfs;	/* SDRAM Self Refresh Off */
182
183	STI R4;
184
185	RETS = [SP++];
186	(R7:4, P5:3) = [SP++];
187	RTS;
188ENDPROC(_sleep_deeper)
189
190ENTRY(_set_dram_srfs)
191	/*  set the dram to self refresh mode */
192	SSYNC;
193#if defined(EBIU_RSTCTL)	/* DDR */
194	P0.H = hi(EBIU_RSTCTL);
195	P0.L = lo(EBIU_RSTCTL);
196	R2 = [P0];
197	BITSET(R2, 3); /* SRREQ enter self-refresh mode */
198	[P0] = R2;
199	SSYNC;
2001:
201	R2 = [P0];
202	CC = BITTST(R2, 4);
203	if !CC JUMP 1b;
204#else 				/* SDRAM */
205	P0.L = lo(EBIU_SDGCTL);
206	P0.H = hi(EBIU_SDGCTL);
207	P1.L = lo(EBIU_SDSTAT);
208	P1.H = hi(EBIU_SDSTAT);
209
210	R2 = [P0];
211	BITSET(R2, 24); /* SRFS enter self-refresh mode */
212	[P0] = R2;
213	SSYNC;
214
2151:
216	R2 = w[P1];
217	SSYNC;
218	cc = BITTST(R2, 1); /* SDSRA poll self-refresh status */
219	if !cc jump 1b;
220
221	R2 = [P0];
222	BITCLR(R2, 0); /* SCTLE disable CLKOUT */
223	[P0] = R2;
224#endif
225	RTS;
226ENDPROC(_set_dram_srfs)
227
228ENTRY(_unset_dram_srfs)
229	/*  set the dram out of self refresh mode */
230
231#if defined(EBIU_RSTCTL)	/* DDR */
232	P0.H = hi(EBIU_RSTCTL);
233	P0.L = lo(EBIU_RSTCTL);
234	R2 = [P0];
235	BITCLR(R2, 3); /* clear SRREQ bit */
236	[P0] = R2;
237#elif defined(EBIU_SDGCTL)	/* SDRAM */
238	/* release CLKOUT from self-refresh */
239	P0.L = lo(EBIU_SDGCTL);
240	P0.H = hi(EBIU_SDGCTL);
241
242	R2 = [P0];
243	BITSET(R2, 0); /* SCTLE enable CLKOUT */
244	[P0] = R2
245	SSYNC;
246
247	/* release SDRAM from self-refresh */
248	R2 = [P0];
249	BITCLR(R2, 24); /* clear SRFS bit */
250	[P0] = R2
251#endif
252
253	SSYNC;
254	RTS;
255ENDPROC(_unset_dram_srfs)
256
257ENTRY(_set_sic_iwr)
258#ifdef SIC_IWR0
259	P0.H = hi(SYSMMR_BASE);
260	P0.L = lo(SYSMMR_BASE);
261	[P0 + (SIC_IWR0 - SYSMMR_BASE)] = R0;
262	[P0 + (SIC_IWR1 - SYSMMR_BASE)] = R1;
263# ifdef SIC_IWR2
264	[P0 + (SIC_IWR2 - SYSMMR_BASE)] = R2;
265# endif
266#else
267	P0.H = hi(SIC_IWR);
268	P0.L = lo(SIC_IWR);
269	[P0] = R0;
270#endif
271
272	SSYNC;
273	RTS;
274ENDPROC(_set_sic_iwr)
275
276ENTRY(_test_pll_locked)
277	P0.H = hi(PLL_STAT);
278	P0.L = lo(PLL_STAT);
2791:
280	R0 = W[P0] (Z);
281	CC = BITTST(R0,5);
282	IF !CC JUMP 1b;
283	RTS;
284ENDPROC(_test_pll_locked)
285
286.section .text
287ENTRY(_do_hibernate)
288	bfin_cpu_reg_save;
289	bfin_sys_mmr_save;
290	bfin_core_mmr_save;
291
292	/* Setup args to hibernate mode early for pipeline optimization */
293	R0 = M3;
294	P1.H = _hibernate_mode;
295	P1.L = _hibernate_mode;
296
297	/* Save Magic, return address and Stack Pointer */
298	P0 = 0;
299	R1.H = 0xDEAD;	/* Hibernate Magic */
300	R1.L = 0xBEEF;
301	R2.H = .Lpm_resume_here;
302	R2.L = .Lpm_resume_here;
303	[P0++] = R1;	/* Store Hibernate Magic */
304	[P0++] = R2;	/* Save Return Address */
305	[P0++] = SP;	/* Save Stack Pointer */
306
307	/* Must use an indirect call as we need to jump to L1 */
308	call (P1); /* Goodbye */
309
310.Lpm_resume_here:
311
312	bfin_core_mmr_restore;
313	bfin_sys_mmr_restore;
314	bfin_cpu_reg_restore;
315
316	[--sp] = RETI;	/* Clear Global Interrupt Disable */
317	SP += 4;
318
319	RTS;
320ENDPROC(_do_hibernate)
321