diff options
Diffstat (limited to 'arch/mips/alchemy/common/power.c')
-rw-r--r-- | arch/mips/alchemy/common/power.c | 406 |
1 files changed, 79 insertions, 327 deletions
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index bd854a6d1d89..6ab7b42aa1be 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c | |||
@@ -35,25 +35,12 @@ | |||
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 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) | |
41 | #ifdef CONFIG_PM | 40 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
42 | |||
43 | #define DEBUG 1 | ||
44 | #ifdef DEBUG | ||
45 | #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args) | ||
46 | #else | ||
47 | #define DPRINTK(fmt, args...) | ||
48 | #endif | 41 | #endif |
49 | 42 | ||
50 | static void au1000_calibrate_delay(void); | 43 | #ifdef CONFIG_PM |
51 | |||
52 | extern unsigned long save_local_and_disable(int controller); | ||
53 | extern void restore_local_and_enable(int controller, unsigned long mask); | ||
54 | extern void local_enable_irq(unsigned int irq_nr); | ||
55 | |||
56 | static DEFINE_SPINLOCK(pm_lock); | ||
57 | 44 | ||
58 | /* | 45 | /* |
59 | * We need to save/restore a bunch of core registers that are | 46 | * We need to save/restore a bunch of core registers that are |
@@ -65,29 +52,16 @@ static DEFINE_SPINLOCK(pm_lock); | |||
65 | * We only have to save/restore registers that aren't otherwise | 52 | * We only have to save/restore registers that aren't otherwise |
66 | * done as part of a driver pm_* function. | 53 | * done as part of a driver pm_* function. |
67 | */ | 54 | */ |
68 | static unsigned int sleep_aux_pll_cntrl; | 55 | static unsigned int sleep_uart0_inten; |
69 | static unsigned int sleep_cpu_pll_cntrl; | 56 | static unsigned int sleep_uart0_fifoctl; |
70 | static unsigned int sleep_pin_function; | 57 | static unsigned int sleep_uart0_linectl; |
71 | static unsigned int sleep_uart0_inten; | 58 | static unsigned int sleep_uart0_clkdiv; |
72 | static unsigned int sleep_uart0_fifoctl; | 59 | static unsigned int sleep_uart0_enable; |
73 | static unsigned int sleep_uart0_linectl; | 60 | static unsigned int sleep_usb[2]; |
74 | static unsigned int sleep_uart0_clkdiv; | 61 | static unsigned int sleep_sys_clocks[5]; |
75 | static unsigned int sleep_uart0_enable; | 62 | static unsigned int sleep_sys_pinfunc; |
76 | static unsigned int sleep_usbhost_enable; | 63 | static unsigned int sleep_static_memctlr[4][3]; |
77 | static unsigned int sleep_usbdev_enable; | ||
78 | static unsigned int sleep_static_memctlr[4][3]; | ||
79 | 64 | ||
80 | /* | ||
81 | * Define this to cause the value you write to /proc/sys/pm/sleep to | ||
82 | * set the TOY timer for the amount of time you want to sleep. | ||
83 | * This is done mainly for testing, but may be useful in other cases. | ||
84 | * The value is number of 32KHz ticks to sleep. | ||
85 | */ | ||
86 | #define SLEEP_TEST_TIMEOUT 1 | ||
87 | #ifdef SLEEP_TEST_TIMEOUT | ||
88 | static int sleep_ticks; | ||
89 | void wakeup_counter0_set(int ticks); | ||
90 | #endif | ||
91 | 65 | ||
92 | static void save_core_regs(void) | 66 | static void save_core_regs(void) |
93 | { | 67 | { |
@@ -105,31 +79,45 @@ static void save_core_regs(void) | |||
105 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); | 79 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); |
106 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); | 80 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); |
107 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); | 81 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); |
82 | au_sync(); | ||
108 | 83 | ||
84 | #ifndef CONFIG_SOC_AU1200 | ||
109 | /* Shutdown USB host/device. */ | 85 | /* Shutdown USB host/device. */ |
110 | sleep_usbhost_enable = au_readl(USB_HOST_CONFIG); | 86 | sleep_usb[0] = au_readl(USB_HOST_CONFIG); |
111 | 87 | ||
112 | /* There appears to be some undocumented reset register.... */ | 88 | /* There appears to be some undocumented reset register.... */ |
113 | au_writel(0, 0xb0100004); au_sync(); | 89 | au_writel(0, 0xb0100004); |
114 | au_writel(0, USB_HOST_CONFIG); au_sync(); | 90 | au_sync(); |
91 | au_writel(0, USB_HOST_CONFIG); | ||
92 | au_sync(); | ||
115 | 93 | ||
116 | sleep_usbdev_enable = au_readl(USBD_ENABLE); | 94 | sleep_usb[1] = au_readl(USBD_ENABLE); |
117 | au_writel(0, USBD_ENABLE); au_sync(); | 95 | au_writel(0, USBD_ENABLE); |
96 | au_sync(); | ||
97 | |||
98 | #else /* AU1200 */ | ||
99 | |||
100 | /* enable access to OTG mmio so we can save OTG CAP/MUX. | ||
101 | * FIXME: write an OTG driver and move this stuff there! | ||
102 | */ | ||
103 | au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); | ||
104 | au_sync(); | ||
105 | sleep_usb[0] = au_readl(0xb4020020); /* OTG_CAP */ | ||
106 | sleep_usb[1] = au_readl(0xb4020024); /* OTG_MUX */ | ||
107 | #endif | ||
118 | 108 | ||
119 | /* Save interrupt controller state. */ | 109 | /* Save interrupt controller state. */ |
120 | save_au1xxx_intctl(); | 110 | save_au1xxx_intctl(); |
121 | 111 | ||
122 | /* Clocks and PLLs. */ | 112 | /* Clocks and PLLs. */ |
123 | sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL); | 113 | sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0); |
114 | sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1); | ||
115 | sleep_sys_clocks[2] = au_readl(SYS_CLKSRC); | ||
116 | sleep_sys_clocks[3] = au_readl(SYS_CPUPLL); | ||
117 | sleep_sys_clocks[4] = au_readl(SYS_AUXPLL); | ||
124 | 118 | ||
125 | /* | 119 | /* pin mux config */ |
126 | * We don't really need to do this one, but unless we | 120 | sleep_sys_pinfunc = au_readl(SYS_PINFUNC); |
127 | * write it again it won't have a valid value if we | ||
128 | * happen to read it. | ||
129 | */ | ||
130 | sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL); | ||
131 | |||
132 | sleep_pin_function = au_readl(SYS_PINFUNC); | ||
133 | 121 | ||
134 | /* Save the static memory controller configuration. */ | 122 | /* Save the static memory controller configuration. */ |
135 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); | 123 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); |
@@ -144,16 +132,45 @@ static void save_core_regs(void) | |||
144 | sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); | 132 | sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); |
145 | sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); | 133 | sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); |
146 | sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); | 134 | sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); |
135 | |||
136 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) | ||
137 | au1xxx_dbdma_suspend(); | ||
138 | #endif | ||
147 | } | 139 | } |
148 | 140 | ||
149 | static void restore_core_regs(void) | 141 | static void restore_core_regs(void) |
150 | { | 142 | { |
151 | extern void restore_au1xxx_intctl(void); | 143 | /* restore clock configuration. Writing CPUPLL last will |
152 | extern void wakeup_counter0_adjust(void); | 144 | * stall a bit and stabilize other clocks (unless this is |
145 | * one of those Au1000 with a write-only PLL, where we dont | ||
146 | * have a valid value) | ||
147 | */ | ||
148 | au_writel(sleep_sys_clocks[0], SYS_FREQCTRL0); | ||
149 | au_writel(sleep_sys_clocks[1], SYS_FREQCTRL1); | ||
150 | au_writel(sleep_sys_clocks[2], SYS_CLKSRC); | ||
151 | au_writel(sleep_sys_clocks[4], SYS_AUXPLL); | ||
152 | if (!au1xxx_cpu_has_pll_wo()) | ||
153 | au_writel(sleep_sys_clocks[3], SYS_CPUPLL); | ||
154 | au_sync(); | ||
153 | 155 | ||
154 | au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); | 156 | au_writel(sleep_sys_pinfunc, SYS_PINFUNC); |
155 | au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync(); | 157 | au_sync(); |
156 | au_writel(sleep_pin_function, SYS_PINFUNC); au_sync(); | 158 | |
159 | #ifndef CONFIG_SOC_AU1200 | ||
160 | au_writel(sleep_usb[0], USB_HOST_CONFIG); | ||
161 | au_writel(sleep_usb[1], USBD_ENABLE); | ||
162 | au_sync(); | ||
163 | #else | ||
164 | /* enable accces to OTG memory */ | ||
165 | au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); | ||
166 | au_sync(); | ||
167 | |||
168 | /* restore OTG caps and port mux. */ | ||
169 | au_writel(sleep_usb[0], 0xb4020020 + 0); /* OTG_CAP */ | ||
170 | au_sync(); | ||
171 | au_writel(sleep_usb[1], 0xb4020020 + 4); /* OTG_MUX */ | ||
172 | au_sync(); | ||
173 | #endif | ||
157 | 174 | ||
158 | /* Restore the static memory controller configuration. */ | 175 | /* Restore the static memory controller configuration. */ |
159 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); | 176 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); |
@@ -184,282 +201,17 @@ static void restore_core_regs(void) | |||
184 | } | 201 | } |
185 | 202 | ||
186 | restore_au1xxx_intctl(); | 203 | restore_au1xxx_intctl(); |
187 | wakeup_counter0_adjust(); | ||
188 | } | ||
189 | |||
190 | unsigned long suspend_mode; | ||
191 | 204 | ||
192 | void wakeup_from_suspend(void) | 205 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) |
193 | { | 206 | au1xxx_dbdma_resume(); |
194 | suspend_mode = 0; | 207 | #endif |
195 | } | 208 | } |
196 | 209 | ||
197 | int au_sleep(void) | 210 | void au_sleep(void) |
198 | { | 211 | { |
199 | unsigned long wakeup, flags; | ||
200 | extern void save_and_sleep(void); | ||
201 | |||
202 | spin_lock_irqsave(&pm_lock, flags); | ||
203 | |||
204 | save_core_regs(); | 212 | save_core_regs(); |
205 | 213 | au1xxx_save_and_sleep(); | |
206 | flush_cache_all(); | ||
207 | |||
208 | /** | ||
209 | ** The code below is all system dependent and we should probably | ||
210 | ** have a function call out of here to set this up. You need | ||
211 | ** to configure the GPIO or timer interrupts that will bring | ||
212 | ** you out of sleep. | ||
213 | ** For testing, the TOY counter wakeup is useful. | ||
214 | **/ | ||
215 | #if 0 | ||
216 | au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD); | ||
217 | |||
218 | /* GPIO 6 can cause a wake up event */ | ||
219 | wakeup = au_readl(SYS_WAKEMSK); | ||
220 | wakeup &= ~(1 << 8); /* turn off match20 wakeup */ | ||
221 | wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */ | ||
222 | #else | ||
223 | /* For testing, allow match20 to wake us up. */ | ||
224 | #ifdef SLEEP_TEST_TIMEOUT | ||
225 | wakeup_counter0_set(sleep_ticks); | ||
226 | #endif | ||
227 | wakeup = 1 << 8; /* turn on match20 wakeup */ | ||
228 | wakeup = 0; | ||
229 | #endif | ||
230 | au_writel(1, SYS_WAKESRC); /* clear cause */ | ||
231 | au_sync(); | ||
232 | au_writel(wakeup, SYS_WAKEMSK); | ||
233 | au_sync(); | ||
234 | |||
235 | save_and_sleep(); | ||
236 | |||
237 | /* | ||
238 | * After a wakeup, the cpu vectors back to 0x1fc00000, so | ||
239 | * it's up to the boot code to get us back here. | ||
240 | */ | ||
241 | restore_core_regs(); | 214 | restore_core_regs(); |
242 | spin_unlock_irqrestore(&pm_lock, flags); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int pm_do_sleep(ctl_table *ctl, int write, struct file *file, | ||
247 | void __user *buffer, size_t *len, loff_t *ppos) | ||
248 | { | ||
249 | #ifdef SLEEP_TEST_TIMEOUT | ||
250 | #define TMPBUFLEN2 16 | ||
251 | char buf[TMPBUFLEN2], *p; | ||
252 | #endif | ||
253 | |||
254 | if (!write) | ||
255 | *len = 0; | ||
256 | else { | ||
257 | #ifdef SLEEP_TEST_TIMEOUT | ||
258 | if (*len > TMPBUFLEN2 - 1) | ||
259 | return -EFAULT; | ||
260 | if (copy_from_user(buf, buffer, *len)) | ||
261 | return -EFAULT; | ||
262 | buf[*len] = 0; | ||
263 | p = buf; | ||
264 | sleep_ticks = simple_strtoul(p, &p, 0); | ||
265 | #endif | ||
266 | |||
267 | au_sleep(); | ||
268 | } | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int pm_do_freq(ctl_table *ctl, int write, struct file *file, | ||
273 | void __user *buffer, size_t *len, loff_t *ppos) | ||
274 | { | ||
275 | int retval = 0, i; | ||
276 | unsigned long val, pll; | ||
277 | #define TMPBUFLEN 64 | ||
278 | #define MAX_CPU_FREQ 396 | ||
279 | char buf[TMPBUFLEN], *p; | ||
280 | unsigned long flags, intc0_mask, intc1_mask; | ||
281 | unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh; | ||
282 | unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; | ||
283 | unsigned long baud_rate; | ||
284 | |||
285 | spin_lock_irqsave(&pm_lock, flags); | ||
286 | if (!write) | ||
287 | *len = 0; | ||
288 | else { | ||
289 | /* Parse the new frequency */ | ||
290 | if (*len > TMPBUFLEN - 1) { | ||
291 | spin_unlock_irqrestore(&pm_lock, flags); | ||
292 | return -EFAULT; | ||
293 | } | ||
294 | if (copy_from_user(buf, buffer, *len)) { | ||
295 | spin_unlock_irqrestore(&pm_lock, flags); | ||
296 | return -EFAULT; | ||
297 | } | ||
298 | buf[*len] = 0; | ||
299 | p = buf; | ||
300 | val = simple_strtoul(p, &p, 0); | ||
301 | if (val > MAX_CPU_FREQ) { | ||
302 | spin_unlock_irqrestore(&pm_lock, flags); | ||
303 | return -EFAULT; | ||
304 | } | ||
305 | |||
306 | pll = val / 12; | ||
307 | if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ | ||
308 | /* Revisit this for higher speed CPUs */ | ||
309 | spin_unlock_irqrestore(&pm_lock, flags); | ||
310 | return -EFAULT; | ||
311 | } | ||
312 | |||
313 | old_baud_base = get_au1x00_uart_baud_base(); | ||
314 | old_cpu_freq = get_au1x00_speed(); | ||
315 | |||
316 | new_cpu_freq = pll * 12 * 1000000; | ||
317 | new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL) | ||
318 | & 0x03) + 2) * 16)); | ||
319 | set_au1x00_speed(new_cpu_freq); | ||
320 | set_au1x00_uart_baud_base(new_baud_base); | ||
321 | |||
322 | old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff; | ||
323 | new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) | | ||
324 | (au_readl(MEM_SDREFCFG) & ~0x1ffffff); | ||
325 | |||
326 | au_writel(pll, SYS_CPUPLL); | ||
327 | au_sync_delay(1); | ||
328 | au_writel(new_refresh, MEM_SDREFCFG); | ||
329 | au_sync_delay(1); | ||
330 | |||
331 | for (i = 0; i < 4; i++) | ||
332 | if (au_readl(UART_BASE + UART_MOD_CNTRL + | ||
333 | i * 0x00100000) == 3) { | ||
334 | old_clk = au_readl(UART_BASE + UART_CLK + | ||
335 | i * 0x00100000); | ||
336 | baud_rate = old_baud_base / old_clk; | ||
337 | /* | ||
338 | * We won't get an exact baud rate and the error | ||
339 | * could be significant enough that our new | ||
340 | * calculation will result in a clock that will | ||
341 | * give us a baud rate that's too far off from | ||
342 | * what we really want. | ||
343 | */ | ||
344 | if (baud_rate > 100000) | ||
345 | baud_rate = 115200; | ||
346 | else if (baud_rate > 50000) | ||
347 | baud_rate = 57600; | ||
348 | else if (baud_rate > 30000) | ||
349 | baud_rate = 38400; | ||
350 | else if (baud_rate > 17000) | ||
351 | baud_rate = 19200; | ||
352 | else | ||
353 | baud_rate = 9600; | ||
354 | new_clk = new_baud_base / baud_rate; | ||
355 | au_writel(new_clk, UART_BASE + UART_CLK + | ||
356 | i * 0x00100000); | ||
357 | au_sync_delay(10); | ||
358 | } | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * We don't want _any_ interrupts other than match20. Otherwise our | ||
363 | * au1000_calibrate_delay() calculation will be off, potentially a lot. | ||
364 | */ | ||
365 | intc0_mask = save_local_and_disable(0); | ||
366 | intc1_mask = save_local_and_disable(1); | ||
367 | local_enable_irq(AU1000_TOY_MATCH2_INT); | ||
368 | spin_unlock_irqrestore(&pm_lock, flags); | ||
369 | au1000_calibrate_delay(); | ||
370 | restore_local_and_enable(0, intc0_mask); | ||
371 | restore_local_and_enable(1, intc1_mask); | ||
372 | |||
373 | return retval; | ||
374 | } | 215 | } |
375 | 216 | ||
376 | |||
377 | static struct ctl_table pm_table[] = { | ||
378 | { | ||
379 | .ctl_name = CTL_UNNUMBERED, | ||
380 | .procname = "sleep", | ||
381 | .data = NULL, | ||
382 | .maxlen = 0, | ||
383 | .mode = 0600, | ||
384 | .proc_handler = &pm_do_sleep | ||
385 | }, | ||
386 | { | ||
387 | .ctl_name = CTL_UNNUMBERED, | ||
388 | .procname = "freq", | ||
389 | .data = NULL, | ||
390 | .maxlen = 0, | ||
391 | .mode = 0600, | ||
392 | .proc_handler = &pm_do_freq | ||
393 | }, | ||
394 | {} | ||
395 | }; | ||
396 | |||
397 | static struct ctl_table pm_dir_table[] = { | ||
398 | { | ||
399 | .ctl_name = CTL_UNNUMBERED, | ||
400 | .procname = "pm", | ||
401 | .mode = 0555, | ||
402 | .child = pm_table | ||
403 | }, | ||
404 | {} | ||
405 | }; | ||
406 | |||
407 | /* | ||
408 | * Initialize power interface | ||
409 | */ | ||
410 | static int __init pm_init(void) | ||
411 | { | ||
412 | register_sysctl_table(pm_dir_table); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | __initcall(pm_init); | ||
417 | |||
418 | /* | ||
419 | * This is right out of init/main.c | ||
420 | */ | ||
421 | |||
422 | /* | ||
423 | * This is the number of bits of precision for the loops_per_jiffy. | ||
424 | * Each bit takes on average 1.5/HZ seconds. This (like the original) | ||
425 | * is a little better than 1%. | ||
426 | */ | ||
427 | #define LPS_PREC 8 | ||
428 | |||
429 | static void au1000_calibrate_delay(void) | ||
430 | { | ||
431 | unsigned long ticks, loopbit; | ||
432 | int lps_precision = LPS_PREC; | ||
433 | |||
434 | loops_per_jiffy = 1 << 12; | ||
435 | |||
436 | while (loops_per_jiffy <<= 1) { | ||
437 | /* Wait for "start of" clock tick */ | ||
438 | ticks = jiffies; | ||
439 | while (ticks == jiffies) | ||
440 | /* nothing */ ; | ||
441 | /* Go ... */ | ||
442 | ticks = jiffies; | ||
443 | __delay(loops_per_jiffy); | ||
444 | ticks = jiffies - ticks; | ||
445 | if (ticks) | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * Do a binary approximation to get loops_per_jiffy set to be equal | ||
451 | * one clock (up to lps_precision bits) | ||
452 | */ | ||
453 | loops_per_jiffy >>= 1; | ||
454 | loopbit = loops_per_jiffy; | ||
455 | while (lps_precision-- && (loopbit >>= 1)) { | ||
456 | loops_per_jiffy |= loopbit; | ||
457 | ticks = jiffies; | ||
458 | while (ticks == jiffies); | ||
459 | ticks = jiffies; | ||
460 | __delay(loops_per_jiffy); | ||
461 | if (jiffies != ticks) /* longer than 1 tick */ | ||
462 | loops_per_jiffy &= ~loopbit; | ||
463 | } | ||
464 | } | ||
465 | #endif /* CONFIG_PM */ | 217 | #endif /* CONFIG_PM */ |