diff options
author | Manuel Lauss <mano@roarinelk.homelinux.net> | 2008-12-21 03:26:25 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-01-11 04:57:27 -0500 |
commit | 564365b0fc3395ed55501ef25705664888cebdbc (patch) | |
tree | ed2228df7ea13585f014937b4fc0a6cd7138a674 /arch | |
parent | 2699cdfb765c3b7d77d28ea3bc7d84e486697177 (diff) |
MIPS: Alchemy: Fix up PM code on Au1550/Au1200
Au1550/Au1200 have a different memory controller which requires additi-
onal code to properly put memory to sleep (code taken from AMD/RMI's
Linux-2.6.11 source package).
Also fix up the remaining pm-related paths to compile on Au1200/Au1550
platforms.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/alchemy/common/power.c | 266 | ||||
-rw-r--r-- | arch/mips/alchemy/common/reset.c | 2 | ||||
-rw-r--r-- | arch/mips/alchemy/common/sleeper.S | 118 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-au1x00/au1000.h | 6 |
4 files changed, 225 insertions, 167 deletions
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index 997dd56bcc5e..f08312b10d04 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | 36 | ||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/cacheflush.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | 38 | #include <asm/mach-au1x00/au1000.h> |
40 | 39 | ||
41 | #ifdef CONFIG_PM | 40 | #ifdef CONFIG_PM |
@@ -47,8 +46,6 @@ | |||
47 | #define DPRINTK(fmt, args...) | 46 | #define DPRINTK(fmt, args...) |
48 | #endif | 47 | #endif |
49 | 48 | ||
50 | static void au1000_calibrate_delay(void); | ||
51 | |||
52 | extern unsigned long save_local_and_disable(int controller); | 49 | extern unsigned long save_local_and_disable(int controller); |
53 | extern void restore_local_and_enable(int controller, unsigned long mask); | 50 | extern void restore_local_and_enable(int controller, unsigned long mask); |
54 | 51 | ||
@@ -64,17 +61,15 @@ static DEFINE_SPINLOCK(pm_lock); | |||
64 | * We only have to save/restore registers that aren't otherwise | 61 | * We only have to save/restore registers that aren't otherwise |
65 | * done as part of a driver pm_* function. | 62 | * done as part of a driver pm_* function. |
66 | */ | 63 | */ |
67 | static unsigned int sleep_aux_pll_cntrl; | 64 | static unsigned int sleep_uart0_inten; |
68 | static unsigned int sleep_cpu_pll_cntrl; | 65 | static unsigned int sleep_uart0_fifoctl; |
69 | static unsigned int sleep_pin_function; | 66 | static unsigned int sleep_uart0_linectl; |
70 | static unsigned int sleep_uart0_inten; | 67 | static unsigned int sleep_uart0_clkdiv; |
71 | static unsigned int sleep_uart0_fifoctl; | 68 | static unsigned int sleep_uart0_enable; |
72 | static unsigned int sleep_uart0_linectl; | 69 | static unsigned int sleep_usb[2]; |
73 | static unsigned int sleep_uart0_clkdiv; | 70 | static unsigned int sleep_sys_clocks[5]; |
74 | static unsigned int sleep_uart0_enable; | 71 | static unsigned int sleep_sys_pinfunc; |
75 | static unsigned int sleep_usbhost_enable; | 72 | static unsigned int sleep_static_memctlr[4][3]; |
76 | static unsigned int sleep_usbdev_enable; | ||
77 | static unsigned int sleep_static_memctlr[4][3]; | ||
78 | 73 | ||
79 | /* | 74 | /* |
80 | * Define this to cause the value you write to /proc/sys/pm/sleep to | 75 | * Define this to cause the value you write to /proc/sys/pm/sleep to |
@@ -108,31 +103,45 @@ static void save_core_regs(void) | |||
108 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); | 103 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); |
109 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); | 104 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); |
110 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); | 105 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); |
106 | au_sync(); | ||
111 | 107 | ||
108 | #ifndef CONFIG_SOC_AU1200 | ||
112 | /* Shutdown USB host/device. */ | 109 | /* Shutdown USB host/device. */ |
113 | sleep_usbhost_enable = au_readl(USB_HOST_CONFIG); | 110 | sleep_usb[0] = au_readl(USB_HOST_CONFIG); |
114 | 111 | ||
115 | /* There appears to be some undocumented reset register.... */ | 112 | /* There appears to be some undocumented reset register.... */ |
116 | au_writel(0, 0xb0100004); au_sync(); | 113 | au_writel(0, 0xb0100004); |
117 | au_writel(0, USB_HOST_CONFIG); au_sync(); | 114 | au_sync(); |
115 | au_writel(0, USB_HOST_CONFIG); | ||
116 | au_sync(); | ||
117 | |||
118 | sleep_usb[1] = au_readl(USBD_ENABLE); | ||
119 | au_writel(0, USBD_ENABLE); | ||
120 | au_sync(); | ||
121 | |||
122 | #else /* AU1200 */ | ||
118 | 123 | ||
119 | sleep_usbdev_enable = au_readl(USBD_ENABLE); | 124 | /* enable access to OTG mmio so we can save OTG CAP/MUX. |
120 | au_writel(0, USBD_ENABLE); au_sync(); | 125 | * FIXME: write an OTG driver and move this stuff there! |
126 | */ | ||
127 | au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); | ||
128 | au_sync(); | ||
129 | sleep_usb[0] = au_readl(0xb4020020); /* OTG_CAP */ | ||
130 | sleep_usb[1] = au_readl(0xb4020024); /* OTG_MUX */ | ||
131 | #endif | ||
121 | 132 | ||
122 | /* Save interrupt controller state. */ | 133 | /* Save interrupt controller state. */ |
123 | save_au1xxx_intctl(); | 134 | save_au1xxx_intctl(); |
124 | 135 | ||
125 | /* Clocks and PLLs. */ | 136 | /* Clocks and PLLs. */ |
126 | sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL); | 137 | sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0); |
138 | sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1); | ||
139 | sleep_sys_clocks[2] = au_readl(SYS_CLKSRC); | ||
140 | sleep_sys_clocks[3] = au_readl(SYS_CPUPLL); | ||
141 | sleep_sys_clocks[4] = au_readl(SYS_AUXPLL); | ||
127 | 142 | ||
128 | /* | 143 | /* pin mux config */ |
129 | * We don't really need to do this one, but unless we | 144 | sleep_sys_pinfunc = au_readl(SYS_PINFUNC); |
130 | * write it again it won't have a valid value if we | ||
131 | * happen to read it. | ||
132 | */ | ||
133 | sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL); | ||
134 | |||
135 | sleep_pin_function = au_readl(SYS_PINFUNC); | ||
136 | 145 | ||
137 | /* Save the static memory controller configuration. */ | 146 | /* Save the static memory controller configuration. */ |
138 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); | 147 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); |
@@ -151,12 +160,37 @@ static void save_core_regs(void) | |||
151 | 160 | ||
152 | static void restore_core_regs(void) | 161 | static void restore_core_regs(void) |
153 | { | 162 | { |
154 | extern void restore_au1xxx_intctl(void); | 163 | /* restore clock configuration. Writing CPUPLL last will |
155 | extern void wakeup_counter0_adjust(void); | 164 | * stall a bit and stabilize other clocks (unless this is |
165 | * one of those Au1000 with a write-only PLL, where we dont | ||
166 | * have a valid value) | ||
167 | */ | ||
168 | au_writel(sleep_sys_clocks[0], SYS_FREQCTRL0); | ||
169 | au_writel(sleep_sys_clocks[1], SYS_FREQCTRL1); | ||
170 | au_writel(sleep_sys_clocks[2], SYS_CLKSRC); | ||
171 | au_writel(sleep_sys_clocks[4], SYS_AUXPLL); | ||
172 | if (!au1xxx_cpu_has_pll_wo()) | ||
173 | au_writel(sleep_sys_clocks[3], SYS_CPUPLL); | ||
174 | au_sync(); | ||
175 | |||
176 | au_writel(sleep_sys_pinfunc, SYS_PINFUNC); | ||
177 | au_sync(); | ||
178 | |||
179 | #ifndef CONFIG_SOC_AU1200 | ||
180 | au_writel(sleep_usb[0], USB_HOST_CONFIG); | ||
181 | au_writel(sleep_usb[1], USBD_ENABLE); | ||
182 | au_sync(); | ||
183 | #else | ||
184 | /* enable accces to OTG memory */ | ||
185 | au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); | ||
186 | au_sync(); | ||
156 | 187 | ||
157 | au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); | 188 | /* restore OTG caps and port mux. */ |
158 | au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync(); | 189 | au_writel(sleep_usb[0], 0xb4020020 + 0); /* OTG_CAP */ |
159 | au_writel(sleep_pin_function, SYS_PINFUNC); au_sync(); | 190 | au_sync(); |
191 | au_writel(sleep_usb[1], 0xb4020020 + 4); /* OTG_MUX */ | ||
192 | au_sync(); | ||
193 | #endif | ||
160 | 194 | ||
161 | /* Restore the static memory controller configuration. */ | 195 | /* Restore the static memory controller configuration. */ |
162 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); | 196 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); |
@@ -196,16 +230,45 @@ void wakeup_from_suspend(void) | |||
196 | suspend_mode = 0; | 230 | suspend_mode = 0; |
197 | } | 231 | } |
198 | 232 | ||
199 | int au_sleep(void) | 233 | void au_sleep(void) |
234 | { | ||
235 | save_core_regs(); | ||
236 | au1xxx_save_and_sleep(); | ||
237 | restore_core_regs(); | ||
238 | } | ||
239 | |||
240 | static int pm_do_sleep(ctl_table *ctl, int write, struct file *file, | ||
241 | void __user *buffer, size_t *len, loff_t *ppos) | ||
200 | { | 242 | { |
201 | unsigned long wakeup, flags; | 243 | unsigned long wakeup, flags; |
202 | extern void save_and_sleep(void); | 244 | int ret; |
245 | #ifdef SLEEP_TEST_TIMEOUT | ||
246 | #define TMPBUFLEN2 16 | ||
247 | char buf[TMPBUFLEN2], *p; | ||
248 | #endif | ||
203 | 249 | ||
204 | spin_lock_irqsave(&pm_lock, flags); | 250 | spin_lock_irqsave(&pm_lock, flags); |
205 | 251 | ||
206 | save_core_regs(); | 252 | if (!write) { |
253 | *len = 0; | ||
254 | ret = 0; | ||
255 | goto out_unlock; | ||
256 | }; | ||
207 | 257 | ||
208 | flush_cache_all(); | 258 | #ifdef SLEEP_TEST_TIMEOUT |
259 | if (*len > TMPBUFLEN2 - 1) { | ||
260 | ret = -EFAULT; | ||
261 | goto out_unlock; | ||
262 | } | ||
263 | if (copy_from_user(buf, buffer, *len)) { | ||
264 | return -EFAULT; | ||
265 | goto out_unlock; | ||
266 | } | ||
267 | buf[*len] = 0; | ||
268 | p = buf; | ||
269 | sleep_ticks = simple_strtoul(p, &p, 0); | ||
270 | wakeup_counter0_set(sleep_ticks); | ||
271 | #endif | ||
209 | 272 | ||
210 | /** | 273 | /** |
211 | ** The code below is all system dependent and we should probably | 274 | ** The code below is all system dependent and we should probably |
@@ -223,9 +286,6 @@ int au_sleep(void) | |||
223 | wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */ | 286 | wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */ |
224 | #else | 287 | #else |
225 | /* For testing, allow match20 to wake us up. */ | 288 | /* For testing, allow match20 to wake us up. */ |
226 | #ifdef SLEEP_TEST_TIMEOUT | ||
227 | wakeup_counter0_set(sleep_ticks); | ||
228 | #endif | ||
229 | wakeup = 1 << 8; /* turn on match20 wakeup */ | 289 | wakeup = 1 << 8; /* turn on match20 wakeup */ |
230 | wakeup = 0; | 290 | wakeup = 0; |
231 | #endif | 291 | #endif |
@@ -234,41 +294,62 @@ int au_sleep(void) | |||
234 | au_writel(wakeup, SYS_WAKEMSK); | 294 | au_writel(wakeup, SYS_WAKEMSK); |
235 | au_sync(); | 295 | au_sync(); |
236 | 296 | ||
237 | save_and_sleep(); | 297 | au_sleep(); |
298 | ret = 0; | ||
238 | 299 | ||
239 | /* | 300 | out_unlock: |
240 | * After a wakeup, the cpu vectors back to 0x1fc00000, so | ||
241 | * it's up to the boot code to get us back here. | ||
242 | */ | ||
243 | restore_core_regs(); | ||
244 | spin_unlock_irqrestore(&pm_lock, flags); | 301 | spin_unlock_irqrestore(&pm_lock, flags); |
245 | return 0; | 302 | return ret; |
246 | } | 303 | } |
247 | 304 | ||
248 | static int pm_do_sleep(ctl_table *ctl, int write, struct file *file, | 305 | #if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550) |
249 | void __user *buffer, size_t *len, loff_t *ppos) | 306 | |
307 | /* | ||
308 | * This is right out of init/main.c | ||
309 | */ | ||
310 | |||
311 | /* | ||
312 | * This is the number of bits of precision for the loops_per_jiffy. | ||
313 | * Each bit takes on average 1.5/HZ seconds. This (like the original) | ||
314 | * is a little better than 1%. | ||
315 | */ | ||
316 | #define LPS_PREC 8 | ||
317 | |||
318 | static void au1000_calibrate_delay(void) | ||
250 | { | 319 | { |
251 | #ifdef SLEEP_TEST_TIMEOUT | 320 | unsigned long ticks, loopbit; |
252 | #define TMPBUFLEN2 16 | 321 | int lps_precision = LPS_PREC; |
253 | char buf[TMPBUFLEN2], *p; | ||
254 | #endif | ||
255 | 322 | ||
256 | if (!write) | 323 | loops_per_jiffy = 1 << 12; |
257 | *len = 0; | ||
258 | else { | ||
259 | #ifdef SLEEP_TEST_TIMEOUT | ||
260 | if (*len > TMPBUFLEN2 - 1) | ||
261 | return -EFAULT; | ||
262 | if (copy_from_user(buf, buffer, *len)) | ||
263 | return -EFAULT; | ||
264 | buf[*len] = 0; | ||
265 | p = buf; | ||
266 | sleep_ticks = simple_strtoul(p, &p, 0); | ||
267 | #endif | ||
268 | 324 | ||
269 | au_sleep(); | 325 | while (loops_per_jiffy <<= 1) { |
326 | /* Wait for "start of" clock tick */ | ||
327 | ticks = jiffies; | ||
328 | while (ticks == jiffies) | ||
329 | /* nothing */ ; | ||
330 | /* Go ... */ | ||
331 | ticks = jiffies; | ||
332 | __delay(loops_per_jiffy); | ||
333 | ticks = jiffies - ticks; | ||
334 | if (ticks) | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * Do a binary approximation to get loops_per_jiffy set to be equal | ||
340 | * one clock (up to lps_precision bits) | ||
341 | */ | ||
342 | loops_per_jiffy >>= 1; | ||
343 | loopbit = loops_per_jiffy; | ||
344 | while (lps_precision-- && (loopbit >>= 1)) { | ||
345 | loops_per_jiffy |= loopbit; | ||
346 | ticks = jiffies; | ||
347 | while (ticks == jiffies); | ||
348 | ticks = jiffies; | ||
349 | __delay(loops_per_jiffy); | ||
350 | if (jiffies != ticks) /* longer than 1 tick */ | ||
351 | loops_per_jiffy &= ~loopbit; | ||
270 | } | 352 | } |
271 | return 0; | ||
272 | } | 353 | } |
273 | 354 | ||
274 | static int pm_do_freq(ctl_table *ctl, int write, struct file *file, | 355 | static int pm_do_freq(ctl_table *ctl, int write, struct file *file, |
@@ -377,7 +458,7 @@ static int pm_do_freq(ctl_table *ctl, int write, struct file *file, | |||
377 | 458 | ||
378 | return retval; | 459 | return retval; |
379 | } | 460 | } |
380 | 461 | #endif | |
381 | 462 | ||
382 | static struct ctl_table pm_table[] = { | 463 | static struct ctl_table pm_table[] = { |
383 | { | 464 | { |
@@ -388,6 +469,7 @@ static struct ctl_table pm_table[] = { | |||
388 | .mode = 0600, | 469 | .mode = 0600, |
389 | .proc_handler = &pm_do_sleep | 470 | .proc_handler = &pm_do_sleep |
390 | }, | 471 | }, |
472 | #if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550) | ||
391 | { | 473 | { |
392 | .ctl_name = CTL_UNNUMBERED, | 474 | .ctl_name = CTL_UNNUMBERED, |
393 | .procname = "freq", | 475 | .procname = "freq", |
@@ -396,6 +478,7 @@ static struct ctl_table pm_table[] = { | |||
396 | .mode = 0600, | 478 | .mode = 0600, |
397 | .proc_handler = &pm_do_freq | 479 | .proc_handler = &pm_do_freq |
398 | }, | 480 | }, |
481 | #endif | ||
399 | {} | 482 | {} |
400 | }; | 483 | }; |
401 | 484 | ||
@@ -429,51 +512,4 @@ static int __init pm_init(void) | |||
429 | 512 | ||
430 | __initcall(pm_init); | 513 | __initcall(pm_init); |
431 | 514 | ||
432 | /* | ||
433 | * This is right out of init/main.c | ||
434 | */ | ||
435 | |||
436 | /* | ||
437 | * This is the number of bits of precision for the loops_per_jiffy. | ||
438 | * Each bit takes on average 1.5/HZ seconds. This (like the original) | ||
439 | * is a little better than 1%. | ||
440 | */ | ||
441 | #define LPS_PREC 8 | ||
442 | |||
443 | static void au1000_calibrate_delay(void) | ||
444 | { | ||
445 | unsigned long ticks, loopbit; | ||
446 | int lps_precision = LPS_PREC; | ||
447 | |||
448 | loops_per_jiffy = 1 << 12; | ||
449 | |||
450 | while (loops_per_jiffy <<= 1) { | ||
451 | /* Wait for "start of" clock tick */ | ||
452 | ticks = jiffies; | ||
453 | while (ticks == jiffies) | ||
454 | /* nothing */ ; | ||
455 | /* Go ... */ | ||
456 | ticks = jiffies; | ||
457 | __delay(loops_per_jiffy); | ||
458 | ticks = jiffies - ticks; | ||
459 | if (ticks) | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * Do a binary approximation to get loops_per_jiffy set to be equal | ||
465 | * one clock (up to lps_precision bits) | ||
466 | */ | ||
467 | loops_per_jiffy >>= 1; | ||
468 | loopbit = loops_per_jiffy; | ||
469 | while (lps_precision-- && (loopbit >>= 1)) { | ||
470 | loops_per_jiffy |= loopbit; | ||
471 | ticks = jiffies; | ||
472 | while (ticks == jiffies); | ||
473 | ticks = jiffies; | ||
474 | __delay(loops_per_jiffy); | ||
475 | if (jiffies != ticks) /* longer than 1 tick */ | ||
476 | loops_per_jiffy &= ~loopbit; | ||
477 | } | ||
478 | } | ||
479 | #endif /* CONFIG_PM */ | 515 | #endif /* CONFIG_PM */ |
diff --git a/arch/mips/alchemy/common/reset.c b/arch/mips/alchemy/common/reset.c index d555429c8d6f..0191c936cb5e 100644 --- a/arch/mips/alchemy/common/reset.c +++ b/arch/mips/alchemy/common/reset.c | |||
@@ -31,8 +31,6 @@ | |||
31 | 31 | ||
32 | #include <asm/mach-au1x00/au1000.h> | 32 | #include <asm/mach-au1x00/au1000.h> |
33 | 33 | ||
34 | extern int au_sleep(void); | ||
35 | |||
36 | void au1000_restart(char *command) | 34 | void au1000_restart(char *command) |
37 | { | 35 | { |
38 | /* Set all integrated peripherals to disabled states */ | 36 | /* Set all integrated peripherals to disabled states */ |
diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S index 3006e270c8bc..4f4b16741d12 100644 --- a/arch/mips/alchemy/common/sleeper.S +++ b/arch/mips/alchemy/common/sleeper.S | |||
@@ -15,16 +15,17 @@ | |||
15 | #include <asm/regdef.h> | 15 | #include <asm/regdef.h> |
16 | #include <asm/stackframe.h> | 16 | #include <asm/stackframe.h> |
17 | 17 | ||
18 | .extern __flush_cache_all | ||
19 | |||
18 | .text | 20 | .text |
19 | .set macro | 21 | .set noreorder |
20 | .set noat | 22 | .set noat |
21 | .align 5 | 23 | .align 5 |
22 | 24 | ||
23 | /* Save all of the processor general registers and go to sleep. | 25 | /* Save all of the processor general registers and go to sleep. |
24 | * A wakeup condition will get us back here to restore the registers. | 26 | * A wakeup condition will get us back here to restore the registers. |
25 | */ | 27 | */ |
26 | LEAF(save_and_sleep) | 28 | LEAF(au1xxx_save_and_sleep) |
27 | |||
28 | subu sp, PT_SIZE | 29 | subu sp, PT_SIZE |
29 | sw $1, PT_R1(sp) | 30 | sw $1, PT_R1(sp) |
30 | sw $2, PT_R2(sp) | 31 | sw $2, PT_R2(sp) |
@@ -33,14 +34,6 @@ LEAF(save_and_sleep) | |||
33 | sw $5, PT_R5(sp) | 34 | sw $5, PT_R5(sp) |
34 | sw $6, PT_R6(sp) | 35 | sw $6, PT_R6(sp) |
35 | sw $7, PT_R7(sp) | 36 | sw $7, PT_R7(sp) |
36 | sw $8, PT_R8(sp) | ||
37 | sw $9, PT_R9(sp) | ||
38 | sw $10, PT_R10(sp) | ||
39 | sw $11, PT_R11(sp) | ||
40 | sw $12, PT_R12(sp) | ||
41 | sw $13, PT_R13(sp) | ||
42 | sw $14, PT_R14(sp) | ||
43 | sw $15, PT_R15(sp) | ||
44 | sw $16, PT_R16(sp) | 37 | sw $16, PT_R16(sp) |
45 | sw $17, PT_R17(sp) | 38 | sw $17, PT_R17(sp) |
46 | sw $18, PT_R18(sp) | 39 | sw $18, PT_R18(sp) |
@@ -49,12 +42,9 @@ LEAF(save_and_sleep) | |||
49 | sw $21, PT_R21(sp) | 42 | sw $21, PT_R21(sp) |
50 | sw $22, PT_R22(sp) | 43 | sw $22, PT_R22(sp) |
51 | sw $23, PT_R23(sp) | 44 | sw $23, PT_R23(sp) |
52 | sw $24, PT_R24(sp) | ||
53 | sw $25, PT_R25(sp) | ||
54 | sw $26, PT_R26(sp) | 45 | sw $26, PT_R26(sp) |
55 | sw $27, PT_R27(sp) | 46 | sw $27, PT_R27(sp) |
56 | sw $28, PT_R28(sp) | 47 | sw $28, PT_R28(sp) |
57 | sw $29, PT_R29(sp) | ||
58 | sw $30, PT_R30(sp) | 48 | sw $30, PT_R30(sp) |
59 | sw $31, PT_R31(sp) | 49 | sw $31, PT_R31(sp) |
60 | mfc0 k0, CP0_STATUS | 50 | mfc0 k0, CP0_STATUS |
@@ -66,20 +56,26 @@ LEAF(save_and_sleep) | |||
66 | mfc0 k0, CP0_CONFIG | 56 | mfc0 k0, CP0_CONFIG |
67 | sw k0, 0x14(sp) | 57 | sw k0, 0x14(sp) |
68 | 58 | ||
59 | /* flush caches to make sure context is in memory */ | ||
60 | la t1, __flush_cache_all | ||
61 | lw t0, 0(t1) | ||
62 | jalr t0 | ||
63 | nop | ||
64 | |||
69 | /* Now set up the scratch registers so the boot rom will | 65 | /* Now set up the scratch registers so the boot rom will |
70 | * return to this point upon wakeup. | 66 | * return to this point upon wakeup. |
67 | * sys_scratch0 : SP | ||
68 | * sys_scratch1 : RA | ||
71 | */ | 69 | */ |
72 | la k0, 1f | 70 | lui t3, 0xb190 /* sys_xxx */ |
73 | lui k1, 0xb190 | 71 | sw sp, 0x0018(t3) |
74 | ori k1, 0x18 | 72 | la k0, 3f /* resume path */ |
75 | sw sp, 0(k1) | 73 | sw k0, 0x001c(t3) |
76 | ori k1, 0x1c | ||
77 | sw k0, 0(k1) | ||
78 | 74 | ||
79 | /* Put SDRAM into self refresh. Preload instructions into cache, | 75 | /* Put SDRAM into self refresh: Preload instructions into cache, |
80 | * issue a precharge, then auto refresh, then sleep commands to it. | 76 | * issue a precharge, auto/self refresh, then sleep commands to it. |
81 | */ | 77 | */ |
82 | la t0, sdsleep | 78 | la t0, 1f |
83 | .set mips3 | 79 | .set mips3 |
84 | cache 0x14, 0(t0) | 80 | cache 0x14, 0(t0) |
85 | cache 0x14, 32(t0) | 81 | cache 0x14, 32(t0) |
@@ -87,24 +83,57 @@ LEAF(save_and_sleep) | |||
87 | cache 0x14, 96(t0) | 83 | cache 0x14, 96(t0) |
88 | .set mips0 | 84 | .set mips0 |
89 | 85 | ||
90 | sdsleep: | 86 | 1: lui a0, 0xb400 /* mem_xxx */ |
91 | lui k0, 0xb400 | 87 | #if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100) || \ |
92 | sw zero, 0x001c(k0) /* Precharge */ | 88 | defined(CONFIG_SOC_AU1500) |
93 | sw zero, 0x0020(k0) /* Auto refresh */ | 89 | sw zero, 0x001c(a0) /* Precharge */ |
94 | sw zero, 0x0030(k0) /* SDRAM sleep */ | 90 | sync |
91 | sw zero, 0x0020(a0) /* Auto Refresh */ | ||
92 | sync | ||
93 | sw zero, 0x0030(a0) /* Sleep */ | ||
94 | sync | ||
95 | #endif | ||
96 | |||
97 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) | ||
98 | sw zero, 0x08c0(a0) /* Precharge */ | ||
95 | sync | 99 | sync |
100 | sw zero, 0x08d0(a0) /* Self Refresh */ | ||
101 | sync | ||
102 | |||
103 | /* wait for sdram to enter self-refresh mode */ | ||
104 | lui t0, 0x0100 | ||
105 | 2: lw t1, 0x0850(a0) /* mem_sdstat */ | ||
106 | and t2, t1, t0 | ||
107 | beq t2, zero, 2b | ||
108 | nop | ||
96 | 109 | ||
97 | lui k1, 0xb190 | 110 | /* disable SDRAM clocks */ |
98 | sw zero, 0x0078(k1) /* get ready to sleep */ | 111 | lui t0, 0xcfff |
112 | ori t0, t0, 0xffff | ||
113 | lw t1, 0x0840(a0) /* mem_sdconfiga */ | ||
114 | and t1, t0, t1 /* clear CE[1:0] */ | ||
115 | sw t1, 0x0840(a0) /* mem_sdconfiga */ | ||
99 | sync | 116 | sync |
100 | sw zero, 0x007c(k1) /* Put processor to sleep */ | 117 | #endif |
118 | |||
119 | /* put power supply and processor to sleep */ | ||
120 | sw zero, 0x0078(t3) /* sys_slppwr */ | ||
121 | sync | ||
122 | sw zero, 0x007c(t3) /* sys_sleep */ | ||
101 | sync | 123 | sync |
124 | nop | ||
125 | nop | ||
126 | nop | ||
127 | nop | ||
128 | nop | ||
129 | nop | ||
130 | nop | ||
131 | nop | ||
102 | 132 | ||
103 | /* This is where we return upon wakeup. | 133 | /* This is where we return upon wakeup. |
104 | * Reload all of the registers and return. | 134 | * Reload all of the registers and return. |
105 | */ | 135 | */ |
106 | 1: nop | 136 | 3: lw k0, 0x20(sp) |
107 | lw k0, 0x20(sp) | ||
108 | mtc0 k0, CP0_STATUS | 137 | mtc0 k0, CP0_STATUS |
109 | lw k0, 0x1c(sp) | 138 | lw k0, 0x1c(sp) |
110 | mtc0 k0, CP0_CONTEXT | 139 | mtc0 k0, CP0_CONTEXT |
@@ -113,10 +142,11 @@ sdsleep: | |||
113 | lw k0, 0x14(sp) | 142 | lw k0, 0x14(sp) |
114 | mtc0 k0, CP0_CONFIG | 143 | mtc0 k0, CP0_CONFIG |
115 | 144 | ||
116 | /* We need to catch the ealry Alchemy SOCs with | 145 | /* We need to catch the early Alchemy SOCs with |
117 | * the write-only Config[OD] bit and set it back to one... | 146 | * the write-only Config[OD] bit and set it back to one... |
118 | */ | 147 | */ |
119 | jal au1x00_fixup_config_od | 148 | jal au1x00_fixup_config_od |
149 | nop | ||
120 | lw $1, PT_R1(sp) | 150 | lw $1, PT_R1(sp) |
121 | lw $2, PT_R2(sp) | 151 | lw $2, PT_R2(sp) |
122 | lw $3, PT_R3(sp) | 152 | lw $3, PT_R3(sp) |
@@ -124,14 +154,6 @@ sdsleep: | |||
124 | lw $5, PT_R5(sp) | 154 | lw $5, PT_R5(sp) |
125 | lw $6, PT_R6(sp) | 155 | lw $6, PT_R6(sp) |
126 | lw $7, PT_R7(sp) | 156 | lw $7, PT_R7(sp) |
127 | lw $8, PT_R8(sp) | ||
128 | lw $9, PT_R9(sp) | ||
129 | lw $10, PT_R10(sp) | ||
130 | lw $11, PT_R11(sp) | ||
131 | lw $12, PT_R12(sp) | ||
132 | lw $13, PT_R13(sp) | ||
133 | lw $14, PT_R14(sp) | ||
134 | lw $15, PT_R15(sp) | ||
135 | lw $16, PT_R16(sp) | 157 | lw $16, PT_R16(sp) |
136 | lw $17, PT_R17(sp) | 158 | lw $17, PT_R17(sp) |
137 | lw $18, PT_R18(sp) | 159 | lw $18, PT_R18(sp) |
@@ -140,15 +162,11 @@ sdsleep: | |||
140 | lw $21, PT_R21(sp) | 162 | lw $21, PT_R21(sp) |
141 | lw $22, PT_R22(sp) | 163 | lw $22, PT_R22(sp) |
142 | lw $23, PT_R23(sp) | 164 | lw $23, PT_R23(sp) |
143 | lw $24, PT_R24(sp) | ||
144 | lw $25, PT_R25(sp) | ||
145 | lw $26, PT_R26(sp) | 165 | lw $26, PT_R26(sp) |
146 | lw $27, PT_R27(sp) | 166 | lw $27, PT_R27(sp) |
147 | lw $28, PT_R28(sp) | 167 | lw $28, PT_R28(sp) |
148 | lw $29, PT_R29(sp) | ||
149 | lw $30, PT_R30(sp) | 168 | lw $30, PT_R30(sp) |
150 | lw $31, PT_R31(sp) | 169 | lw $31, PT_R31(sp) |
151 | addiu sp, PT_SIZE | ||
152 | |||
153 | jr ra | 170 | jr ra |
154 | END(save_and_sleep) | 171 | addiu sp, PT_SIZE |
172 | END(au1xxx_save_and_sleep) | ||
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index 2b88c2982cb0..515373c6d4a1 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h | |||
@@ -137,6 +137,12 @@ extern void set_au1x00_uart_baud_base(unsigned long new_baud_base); | |||
137 | extern unsigned long get_au1x00_uart_baud_base(void); | 137 | extern unsigned long get_au1x00_uart_baud_base(void); |
138 | extern unsigned long au1xxx_calc_clock(void); | 138 | extern unsigned long au1xxx_calc_clock(void); |
139 | 139 | ||
140 | /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */ | ||
141 | void au1xxx_save_and_sleep(void); | ||
142 | void au_sleep(void); | ||
143 | void save_au1xxx_intctl(void); | ||
144 | void restore_au1xxx_intctl(void); | ||
145 | |||
140 | /* | 146 | /* |
141 | * Every board describes its IRQ mapping with this table. | 147 | * Every board describes its IRQ mapping with this table. |
142 | */ | 148 | */ |