diff options
Diffstat (limited to 'arch/mips/alchemy/common/power.c')
-rw-r--r-- | arch/mips/alchemy/common/power.c | 266 |
1 files changed, 151 insertions, 115 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 */ |