aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/au1000/common/power.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/au1000/common/power.c')
-rw-r--r--arch/mips/au1000/common/power.c493
1 files changed, 493 insertions, 0 deletions
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
new file mode 100644
index 000000000000..c40daccbb5b1
--- /dev/null
+++ b/arch/mips/au1000/common/power.c
@@ -0,0 +1,493 @@
1/*
2 * BRIEF MODULE DESCRIPTION
3 * Au1000 Power Management routines.
4 *
5 * Copyright 2001 MontaVista Software Inc.
6 * Author: MontaVista Software, Inc.
7 * ppopov@mvista.com or source@mvista.com
8 *
9 * Some of the routines are right out of init/main.c, whose
10 * copyrights apply here.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
20 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * You should have received a copy of the GNU General Public License along
29 * with this program; if not, write to the Free Software Foundation, Inc.,
30 * 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32#include <linux/config.h>
33#include <linux/init.h>
34#include <linux/pm.h>
35#include <linux/slab.h>
36#include <linux/sysctl.h>
37
38#include <asm/string.h>
39#include <asm/uaccess.h>
40#include <asm/io.h>
41#include <asm/system.h>
42#include <asm/mach-au1x00/au1000.h>
43
44#ifdef CONFIG_PM
45
46#define DEBUG 1
47#ifdef DEBUG
48# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
49#else
50# define DPRINTK(fmt, args...)
51#endif
52
53static void calibrate_delay(void);
54
55extern void set_au1x00_speed(unsigned int new_freq);
56extern unsigned int get_au1x00_speed(void);
57extern unsigned long get_au1x00_uart_baud_base(void);
58extern void set_au1x00_uart_baud_base(unsigned long new_baud_base);
59extern unsigned long save_local_and_disable(int controller);
60extern void restore_local_and_enable(int controller, unsigned long mask);
61extern void local_enable_irq(unsigned int irq_nr);
62
63/* Quick acpi hack. This will have to change! */
64#define CTL_ACPI 9999
65#define ACPI_S1_SLP_TYP 19
66#define ACPI_SLEEP 21
67
68
69static DEFINE_SPINLOCK(pm_lock);
70
71/* We need to save/restore a bunch of core registers that are
72 * either volatile or reset to some state across a processor sleep.
73 * If reading a register doesn't provide a proper result for a
74 * later restore, we have to provide a function for loading that
75 * register and save a copy.
76 *
77 * We only have to save/restore registers that aren't otherwise
78 * done as part of a driver pm_* function.
79 */
80static uint sleep_aux_pll_cntrl;
81static uint sleep_cpu_pll_cntrl;
82static uint sleep_pin_function;
83static uint sleep_uart0_inten;
84static uint sleep_uart0_fifoctl;
85static uint sleep_uart0_linectl;
86static uint sleep_uart0_clkdiv;
87static uint sleep_uart0_enable;
88static uint sleep_usbhost_enable;
89static uint sleep_usbdev_enable;
90static uint sleep_static_memctlr[4][3];
91
92/* Define this to cause the value you write to /proc/sys/pm/sleep to
93 * set the TOY timer for the amount of time you want to sleep.
94 * This is done mainly for testing, but may be useful in other cases.
95 * The value is number of 32KHz ticks to sleep.
96 */
97#define SLEEP_TEST_TIMEOUT 1
98#ifdef SLEEP_TEST_TIMEOUT
99static int sleep_ticks;
100void wakeup_counter0_set(int ticks);
101#endif
102
103static void
104save_core_regs(void)
105{
106 extern void save_au1xxx_intctl(void);
107 extern void pm_eth0_shutdown(void);
108
109 /* Do the serial ports.....these really should be a pm_*
110 * registered function by the driver......but of course the
111 * standard serial driver doesn't understand our Au1xxx
112 * unique registers.
113 */
114 sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER);
115 sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR);
116 sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR);
117 sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK);
118 sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL);
119
120 /* Shutdown USB host/device.
121 */
122 sleep_usbhost_enable = au_readl(USB_HOST_CONFIG);
123
124 /* There appears to be some undocumented reset register....
125 */
126 au_writel(0, 0xb0100004); au_sync();
127 au_writel(0, USB_HOST_CONFIG); au_sync();
128
129 sleep_usbdev_enable = au_readl(USBD_ENABLE);
130 au_writel(0, USBD_ENABLE); au_sync();
131
132 /* Save interrupt controller state.
133 */
134 save_au1xxx_intctl();
135
136 /* Clocks and PLLs.
137 */
138 sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL);
139
140 /* We don't really need to do this one, but unless we
141 * write it again it won't have a valid value if we
142 * happen to read it.
143 */
144 sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL);
145
146 sleep_pin_function = au_readl(SYS_PINFUNC);
147
148 /* Save the static memory controller configuration.
149 */
150 sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0);
151 sleep_static_memctlr[0][1] = au_readl(MEM_STTIME0);
152 sleep_static_memctlr[0][2] = au_readl(MEM_STADDR0);
153 sleep_static_memctlr[1][0] = au_readl(MEM_STCFG1);
154 sleep_static_memctlr[1][1] = au_readl(MEM_STTIME1);
155 sleep_static_memctlr[1][2] = au_readl(MEM_STADDR1);
156 sleep_static_memctlr[2][0] = au_readl(MEM_STCFG2);
157 sleep_static_memctlr[2][1] = au_readl(MEM_STTIME2);
158 sleep_static_memctlr[2][2] = au_readl(MEM_STADDR2);
159 sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3);
160 sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3);
161 sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3);
162}
163
164static void
165restore_core_regs(void)
166{
167 extern void restore_au1xxx_intctl(void);
168 extern void wakeup_counter0_adjust(void);
169
170 au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync();
171 au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync();
172 au_writel(sleep_pin_function, SYS_PINFUNC); au_sync();
173
174 /* Restore the static memory controller configuration.
175 */
176 au_writel(sleep_static_memctlr[0][0], MEM_STCFG0);
177 au_writel(sleep_static_memctlr[0][1], MEM_STTIME0);
178 au_writel(sleep_static_memctlr[0][2], MEM_STADDR0);
179 au_writel(sleep_static_memctlr[1][0], MEM_STCFG1);
180 au_writel(sleep_static_memctlr[1][1], MEM_STTIME1);
181 au_writel(sleep_static_memctlr[1][2], MEM_STADDR1);
182 au_writel(sleep_static_memctlr[2][0], MEM_STCFG2);
183 au_writel(sleep_static_memctlr[2][1], MEM_STTIME2);
184 au_writel(sleep_static_memctlr[2][2], MEM_STADDR2);
185 au_writel(sleep_static_memctlr[3][0], MEM_STCFG3);
186 au_writel(sleep_static_memctlr[3][1], MEM_STTIME3);
187 au_writel(sleep_static_memctlr[3][2], MEM_STADDR3);
188
189 /* Enable the UART if it was enabled before sleep.
190 * I guess I should define module control bits........
191 */
192 if (sleep_uart0_enable & 0x02) {
193 au_writel(0, UART0_ADDR + UART_MOD_CNTRL); au_sync();
194 au_writel(1, UART0_ADDR + UART_MOD_CNTRL); au_sync();
195 au_writel(3, UART0_ADDR + UART_MOD_CNTRL); au_sync();
196 au_writel(sleep_uart0_inten, UART0_ADDR + UART_IER); au_sync();
197 au_writel(sleep_uart0_fifoctl, UART0_ADDR + UART_FCR); au_sync();
198 au_writel(sleep_uart0_linectl, UART0_ADDR + UART_LCR); au_sync();
199 au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync();
200 }
201
202 restore_au1xxx_intctl();
203 wakeup_counter0_adjust();
204}
205
206unsigned long suspend_mode;
207
208void wakeup_from_suspend(void)
209{
210 suspend_mode = 0;
211}
212
213int au_sleep(void)
214{
215 unsigned long wakeup, flags;
216 extern void save_and_sleep(void);
217
218 spin_lock_irqsave(&pm_lock,flags);
219
220 save_core_regs();
221
222 flush_cache_all();
223
224 /** The code below is all system dependent and we should probably
225 ** have a function call out of here to set this up. You need
226 ** to configure the GPIO or timer interrupts that will bring
227 ** you out of sleep.
228 ** For testing, the TOY counter wakeup is useful.
229 **/
230
231#if 0
232 au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
233
234 /* gpio 6 can cause a wake up event */
235 wakeup = au_readl(SYS_WAKEMSK);
236 wakeup &= ~(1 << 8); /* turn off match20 wakeup */
237 wakeup |= 1 << 6; /* turn on gpio 6 wakeup */
238#else
239 /* For testing, allow match20 to wake us up.
240 */
241#ifdef SLEEP_TEST_TIMEOUT
242 wakeup_counter0_set(sleep_ticks);
243#endif
244 wakeup = 1 << 8; /* turn on match20 wakeup */
245 wakeup = 0;
246#endif
247 au_writel(1, SYS_WAKESRC); /* clear cause */
248 au_sync();
249 au_writel(wakeup, SYS_WAKEMSK);
250 au_sync();
251
252 save_and_sleep();
253
254 /* after a wakeup, the cpu vectors back to 0x1fc00000 so
255 * it's up to the boot code to get us back here.
256 */
257 restore_core_regs();
258 spin_unlock_irqrestore(&pm_lock, flags);
259 return 0;
260}
261
262static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
263 void *buffer, size_t * len)
264{
265 int retval = 0;
266#ifdef SLEEP_TEST_TIMEOUT
267#define TMPBUFLEN2 16
268 char buf[TMPBUFLEN2], *p;
269#endif
270
271 if (!write) {
272 *len = 0;
273 } else {
274#ifdef SLEEP_TEST_TIMEOUT
275 if (*len > TMPBUFLEN2 - 1) {
276 return -EFAULT;
277 }
278 if (copy_from_user(buf, buffer, *len)) {
279 return -EFAULT;
280 }
281 buf[*len] = 0;
282 p = buf;
283 sleep_ticks = simple_strtoul(p, &p, 0);
284#endif
285 retval = pm_send_all(PM_SUSPEND, (void *) 2);
286
287 if (retval)
288 return retval;
289
290 au_sleep();
291 retval = pm_send_all(PM_RESUME, (void *) 0);
292 }
293 return retval;
294}
295
296static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
297 void *buffer, size_t * len)
298{
299 int retval = 0;
300 void au1k_wait(void);
301
302 if (!write) {
303 *len = 0;
304 } else {
305 retval = pm_send_all(PM_SUSPEND, (void *) 2);
306 if (retval)
307 return retval;
308 suspend_mode = 1;
309 au1k_wait();
310 retval = pm_send_all(PM_RESUME, (void *) 0);
311 }
312 return retval;
313}
314
315
316static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
317 void *buffer, size_t * len)
318{
319 int retval = 0, i;
320 unsigned long val, pll;
321#define TMPBUFLEN 64
322#define MAX_CPU_FREQ 396
323 char buf[TMPBUFLEN], *p;
324 unsigned long flags, intc0_mask, intc1_mask;
325 unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk,
326 old_refresh;
327 unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
328
329 spin_lock_irqsave(&pm_lock, flags);
330 if (!write) {
331 *len = 0;
332 } else {
333 /* Parse the new frequency */
334 if (*len > TMPBUFLEN - 1) {
335 spin_unlock_irqrestore(&pm_lock, flags);
336 return -EFAULT;
337 }
338 if (copy_from_user(buf, buffer, *len)) {
339 spin_unlock_irqrestore(&pm_lock, flags);
340 return -EFAULT;
341 }
342 buf[*len] = 0;
343 p = buf;
344 val = simple_strtoul(p, &p, 0);
345 if (val > MAX_CPU_FREQ) {
346 spin_unlock_irqrestore(&pm_lock, flags);
347 return -EFAULT;
348 }
349
350 pll = val / 12;
351 if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
352 /* revisit this for higher speed cpus */
353 spin_unlock_irqrestore(&pm_lock, flags);
354 return -EFAULT;
355 }
356
357 old_baud_base = get_au1x00_uart_baud_base();
358 old_cpu_freq = get_au1x00_speed();
359
360 new_cpu_freq = pll * 12 * 1000000;
361 new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
362 set_au1x00_speed(new_cpu_freq);
363 set_au1x00_uart_baud_base(new_baud_base);
364
365 old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
366 new_refresh =
367 ((old_refresh * new_cpu_freq) /
368 old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
369
370 au_writel(pll, SYS_CPUPLL);
371 au_sync_delay(1);
372 au_writel(new_refresh, MEM_SDREFCFG);
373 au_sync_delay(1);
374
375 for (i = 0; i < 4; i++) {
376 if (au_readl
377 (UART_BASE + UART_MOD_CNTRL +
378 i * 0x00100000) == 3) {
379 old_clk =
380 au_readl(UART_BASE + UART_CLK +
381 i * 0x00100000);
382 // baud_rate = baud_base/clk
383 baud_rate = old_baud_base / old_clk;
384 /* we won't get an exact baud rate and the error
385 * could be significant enough that our new
386 * calculation will result in a clock that will
387 * give us a baud rate that's too far off from
388 * what we really want.
389 */
390 if (baud_rate > 100000)
391 baud_rate = 115200;
392 else if (baud_rate > 50000)
393 baud_rate = 57600;
394 else if (baud_rate > 30000)
395 baud_rate = 38400;
396 else if (baud_rate > 17000)
397 baud_rate = 19200;
398 else
399 (baud_rate = 9600);
400 // new_clk = new_baud_base/baud_rate
401 new_clk = new_baud_base / baud_rate;
402 au_writel(new_clk,
403 UART_BASE + UART_CLK +
404 i * 0x00100000);
405 au_sync_delay(10);
406 }
407 }
408 }
409
410
411 /* We don't want _any_ interrupts other than
412 * match20. Otherwise our calibrate_delay()
413 * calculation will be off, potentially a lot.
414 */
415 intc0_mask = save_local_and_disable(0);
416 intc1_mask = save_local_and_disable(1);
417 local_enable_irq(AU1000_TOY_MATCH2_INT);
418 spin_unlock_irqrestore(&pm_lock, flags);
419 calibrate_delay();
420 restore_local_and_enable(0, intc0_mask);
421 restore_local_and_enable(1, intc1_mask);
422 return retval;
423}
424
425
426static struct ctl_table pm_table[] = {
427 {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend},
428 {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep},
429 {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq},
430 {0}
431};
432
433static struct ctl_table pm_dir_table[] = {
434 {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
435 {0}
436};
437
438/*
439 * Initialize power interface
440 */
441static int __init pm_init(void)
442{
443 register_sysctl_table(pm_dir_table, 1);
444 return 0;
445}
446
447__initcall(pm_init);
448
449
450/*
451 * This is right out of init/main.c
452 */
453
454/* This is the number of bits of precision for the loops_per_jiffy. Each
455 bit takes on average 1.5/HZ seconds. This (like the original) is a little
456 better than 1% */
457#define LPS_PREC 8
458
459static void calibrate_delay(void)
460{
461 unsigned long ticks, loopbit;
462 int lps_precision = LPS_PREC;
463
464 loops_per_jiffy = (1 << 12);
465
466 while (loops_per_jiffy <<= 1) {
467 /* wait for "start of" clock tick */
468 ticks = jiffies;
469 while (ticks == jiffies)
470 /* nothing */ ;
471 /* Go .. */
472 ticks = jiffies;
473 __delay(loops_per_jiffy);
474 ticks = jiffies - ticks;
475 if (ticks)
476 break;
477 }
478
479/* Do a binary approximation to get loops_per_jiffy set to equal one clock
480 (up to lps_precision bits) */
481 loops_per_jiffy >>= 1;
482 loopbit = loops_per_jiffy;
483 while (lps_precision-- && (loopbit >>= 1)) {
484 loops_per_jiffy |= loopbit;
485 ticks = jiffies;
486 while (ticks == jiffies);
487 ticks = jiffies;
488 __delay(loops_per_jiffy);
489 if (jiffies != ticks) /* longer than 1 tick */
490 loops_per_jiffy &= ~loopbit;
491 }
492}
493#endif /* CONFIG_PM */