aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/alchemy/common
diff options
context:
space:
mode:
authorManuel Lauss <mano@roarinelk.homelinux.net>2008-12-21 03:26:27 -0500
committerRalf Baechle <ralf@linux-mips.org>2009-01-11 04:57:27 -0500
commit61f9c58da57a80b0df1ced18a28cbbaebd4d417a (patch)
treecbeaa2353d98899e88c6d44dc8d1a16eabbb6a47 /arch/mips/alchemy/common
parentac15dad061d351281b0bafbae1ecdd84e601435a (diff)
MIPS: Alchemy: new userspace suspend interface for development boards.
Replace the current sysctl-based suspend interface with a new sysfs- based one which also uses the Linux-2.6 suspend model. To configure wakeup sources, a subtree for the demoboards is created under /sys/power/db1x: sys/ `-- power `-- db1x |-- gpio0 |-- gpio1 |-- gpio2 |-- gpio3 |-- gpio4 |-- gpio5 |-- gpio6 |-- gpio7 |-- timer |-- timer_timeout |-- wakemsk `-- wakesrc The nodes 'gpio[0-7]' and 'timer' configure the GPIO0..7 and M2 bits of the SYS_WAKEMSK (wakeup source enable) register. Writing '1' enables a wakesource, 0 disables it. The 'timer_timeout' node holds the timeout in seconds after which the TOYMATCH2 event should wake the system. The 'wakesrc' node holds the SYS_WAKESRC register after wakeup (in hex), the 'wakemsk' node can be used to get/set the wakeup mask directly. For example, to have the timer wake the system after 10 seconds of sleep, the following must be done in userspace: echo 10 > /sys/power/db1x/timer_timeout echo 1 > /sys/power/db1x/timer echo mem > /sys/power/sleep This patch also removes the homebrew CPU frequency switching code. I don't understand how it could have ever worked reliably; it does not communicate the clock changes to peripheral devices other than uarts. Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net> Signed-off-by: Ralf Baechle <ralf@linux-mips.org> create mode 100644 arch/mips/alchemy/devboards/pm.c
Diffstat (limited to 'arch/mips/alchemy/common')
-rw-r--r--arch/mips/alchemy/common/irq.c44
-rw-r--r--arch/mips/alchemy/common/power.c309
2 files changed, 0 insertions, 353 deletions
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index c54384779fb9..c88c821b4c36 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -37,8 +37,6 @@
37#include <asm/mach-pb1x00/pb1000.h> 37#include <asm/mach-pb1x00/pb1000.h>
38#endif 38#endif
39 39
40static DEFINE_SPINLOCK(irq_lock);
41
42static int au1x_ic_settype(unsigned int irq, unsigned int flow_type); 40static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);
43 41
44/* per-processor fixed function irqs */ 42/* per-processor fixed function irqs */
@@ -611,45 +609,3 @@ void __init arch_init_irq(void)
611 609
612 set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); 610 set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
613} 611}
614
615unsigned long save_local_and_disable(int controller)
616{
617 int i;
618 unsigned long flags, mask;
619
620 spin_lock_irqsave(&irq_lock, flags);
621 if (controller) {
622 mask = au_readl(IC1_MASKSET);
623 for (i = 0; i < 32; i++)
624 au1x_ic1_mask(i + AU1000_INTC1_INT_BASE);
625 } else {
626 mask = au_readl(IC0_MASKSET);
627 for (i = 0; i < 32; i++)
628 au1x_ic0_mask(i + AU1000_INTC0_INT_BASE);
629 }
630 spin_unlock_irqrestore(&irq_lock, flags);
631
632 return mask;
633}
634
635void restore_local_and_enable(int controller, unsigned long mask)
636{
637 int i;
638 unsigned long flags, new_mask;
639
640 spin_lock_irqsave(&irq_lock, flags);
641 for (i = 0; i < 32; i++)
642 if (mask & (1 << i)) {
643 if (controller)
644 au1x_ic1_unmask(i + AU1000_INTC1_INT_BASE);
645 else
646 au1x_ic0_unmask(i + AU1000_INTC0_INT_BASE);
647 }
648
649 if (controller)
650 new_mask = au_readl(IC1_MASKSET);
651 else
652 new_mask = au_readl(IC0_MASKSET);
653
654 spin_unlock_irqrestore(&irq_lock, flags);
655}
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index f58e151b38d4..6ab7b42aa1be 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -42,18 +42,6 @@
42 42
43#ifdef CONFIG_PM 43#ifdef CONFIG_PM
44 44
45#define DEBUG 1
46#ifdef DEBUG
47#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
48#else
49#define DPRINTK(fmt, args...)
50#endif
51
52extern unsigned long save_local_and_disable(int controller);
53extern void restore_local_and_enable(int controller, unsigned long mask);
54
55static DEFINE_SPINLOCK(pm_lock);
56
57/* 45/*
58 * 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
59 * either volatile or reset to some state across a processor sleep. 47 * either volatile or reset to some state across a processor sleep.
@@ -74,21 +62,6 @@ static unsigned int sleep_sys_clocks[5];
74static unsigned int sleep_sys_pinfunc; 62static unsigned int sleep_sys_pinfunc;
75static unsigned int sleep_static_memctlr[4][3]; 63static unsigned int sleep_static_memctlr[4][3];
76 64
77/*
78 * Define this to cause the value you write to /proc/sys/pm/sleep to
79 * set the TOY timer for the amount of time you want to sleep.
80 * This is done mainly for testing, but may be useful in other cases.
81 * The value is number of 32KHz ticks to sleep.
82 */
83#define SLEEP_TEST_TIMEOUT 1
84#ifdef SLEEP_TEST_TIMEOUT
85static int sleep_ticks;
86static void wakeup_counter0_set(int ticks)
87{
88 au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
89 au_sync();
90}
91#endif
92 65
93static void save_core_regs(void) 66static void save_core_regs(void)
94{ 67{
@@ -234,13 +207,6 @@ static void restore_core_regs(void)
234#endif 207#endif
235} 208}
236 209
237unsigned long suspend_mode;
238
239void wakeup_from_suspend(void)
240{
241 suspend_mode = 0;
242}
243
244void au_sleep(void) 210void au_sleep(void)
245{ 211{
246 save_core_regs(); 212 save_core_regs();
@@ -248,279 +214,4 @@ void au_sleep(void)
248 restore_core_regs(); 214 restore_core_regs();
249} 215}
250 216
251static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
252 void __user *buffer, size_t *len, loff_t *ppos)
253{
254 unsigned long wakeup, flags;
255 int ret;
256#ifdef SLEEP_TEST_TIMEOUT
257#define TMPBUFLEN2 16
258 char buf[TMPBUFLEN2], *p;
259#endif
260
261 spin_lock_irqsave(&pm_lock, flags);
262
263 if (!write) {
264 *len = 0;
265 ret = 0;
266 goto out_unlock;
267 };
268
269#ifdef SLEEP_TEST_TIMEOUT
270 if (*len > TMPBUFLEN2 - 1) {
271 ret = -EFAULT;
272 goto out_unlock;
273 }
274 if (copy_from_user(buf, buffer, *len)) {
275 return -EFAULT;
276 goto out_unlock;
277 }
278 buf[*len] = 0;
279 p = buf;
280 sleep_ticks = simple_strtoul(p, &p, 0);
281 wakeup_counter0_set(sleep_ticks);
282#endif
283
284 /**
285 ** The code below is all system dependent and we should probably
286 ** have a function call out of here to set this up. You need
287 ** to configure the GPIO or timer interrupts that will bring
288 ** you out of sleep.
289 ** For testing, the TOY counter wakeup is useful.
290 **/
291#if 0
292 au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
293
294 /* GPIO 6 can cause a wake up event */
295 wakeup = au_readl(SYS_WAKEMSK);
296 wakeup &= ~(1 << 8); /* turn off match20 wakeup */
297 wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */
298#else
299 /* For testing, allow match20 to wake us up. */
300 wakeup = 1 << 8; /* turn on match20 wakeup */
301 wakeup = 0;
302#endif
303 au_writel(1, SYS_WAKESRC); /* clear cause */
304 au_sync();
305 au_writel(wakeup, SYS_WAKEMSK);
306 au_sync();
307
308 au_sleep();
309 ret = 0;
310
311out_unlock:
312 spin_unlock_irqrestore(&pm_lock, flags);
313 return ret;
314}
315
316#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
317
318/*
319 * This is right out of init/main.c
320 */
321
322/*
323 * This is the number of bits of precision for the loops_per_jiffy.
324 * Each bit takes on average 1.5/HZ seconds. This (like the original)
325 * is a little better than 1%.
326 */
327#define LPS_PREC 8
328
329static void au1000_calibrate_delay(void)
330{
331 unsigned long ticks, loopbit;
332 int lps_precision = LPS_PREC;
333
334 loops_per_jiffy = 1 << 12;
335
336 while (loops_per_jiffy <<= 1) {
337 /* Wait for "start of" clock tick */
338 ticks = jiffies;
339 while (ticks == jiffies)
340 /* nothing */ ;
341 /* Go ... */
342 ticks = jiffies;
343 __delay(loops_per_jiffy);
344 ticks = jiffies - ticks;
345 if (ticks)
346 break;
347 }
348
349 /*
350 * Do a binary approximation to get loops_per_jiffy set to be equal
351 * one clock (up to lps_precision bits)
352 */
353 loops_per_jiffy >>= 1;
354 loopbit = loops_per_jiffy;
355 while (lps_precision-- && (loopbit >>= 1)) {
356 loops_per_jiffy |= loopbit;
357 ticks = jiffies;
358 while (ticks == jiffies);
359 ticks = jiffies;
360 __delay(loops_per_jiffy);
361 if (jiffies != ticks) /* longer than 1 tick */
362 loops_per_jiffy &= ~loopbit;
363 }
364}
365
366static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
367 void __user *buffer, size_t *len, loff_t *ppos)
368{
369 int retval = 0, i;
370 unsigned long val, pll;
371#define TMPBUFLEN 64
372#define MAX_CPU_FREQ 396
373 char buf[TMPBUFLEN], *p;
374 unsigned long flags, intc0_mask, intc1_mask;
375 unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh;
376 unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
377 unsigned long baud_rate;
378
379 spin_lock_irqsave(&pm_lock, flags);
380 if (!write)
381 *len = 0;
382 else {
383 /* Parse the new frequency */
384 if (*len > TMPBUFLEN - 1) {
385 spin_unlock_irqrestore(&pm_lock, flags);
386 return -EFAULT;
387 }
388 if (copy_from_user(buf, buffer, *len)) {
389 spin_unlock_irqrestore(&pm_lock, flags);
390 return -EFAULT;
391 }
392 buf[*len] = 0;
393 p = buf;
394 val = simple_strtoul(p, &p, 0);
395 if (val > MAX_CPU_FREQ) {
396 spin_unlock_irqrestore(&pm_lock, flags);
397 return -EFAULT;
398 }
399
400 pll = val / 12;
401 if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
402 /* Revisit this for higher speed CPUs */
403 spin_unlock_irqrestore(&pm_lock, flags);
404 return -EFAULT;
405 }
406
407 old_baud_base = get_au1x00_uart_baud_base();
408 old_cpu_freq = get_au1x00_speed();
409
410 new_cpu_freq = pll * 12 * 1000000;
411 new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)
412 & 0x03) + 2) * 16));
413 set_au1x00_speed(new_cpu_freq);
414 set_au1x00_uart_baud_base(new_baud_base);
415
416 old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
417 new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) |
418 (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
419
420 au_writel(pll, SYS_CPUPLL);
421 au_sync_delay(1);
422 au_writel(new_refresh, MEM_SDREFCFG);
423 au_sync_delay(1);
424
425 for (i = 0; i < 4; i++)
426 if (au_readl(UART_BASE + UART_MOD_CNTRL +
427 i * 0x00100000) == 3) {
428 old_clk = au_readl(UART_BASE + UART_CLK +
429 i * 0x00100000);
430 baud_rate = old_baud_base / old_clk;
431 /*
432 * We won't get an exact baud rate and the error
433 * could be significant enough that our new
434 * calculation will result in a clock that will
435 * give us a baud rate that's too far off from
436 * what we really want.
437 */
438 if (baud_rate > 100000)
439 baud_rate = 115200;
440 else if (baud_rate > 50000)
441 baud_rate = 57600;
442 else if (baud_rate > 30000)
443 baud_rate = 38400;
444 else if (baud_rate > 17000)
445 baud_rate = 19200;
446 else
447 baud_rate = 9600;
448 new_clk = new_baud_base / baud_rate;
449 au_writel(new_clk, UART_BASE + UART_CLK +
450 i * 0x00100000);
451 au_sync_delay(10);
452 }
453 }
454
455 /*
456 * We don't want _any_ interrupts other than match20. Otherwise our
457 * au1000_calibrate_delay() calculation will be off, potentially a lot.
458 */
459 intc0_mask = save_local_and_disable(0);
460 intc1_mask = save_local_and_disable(1);
461 val = 1 << (AU1000_TOY_MATCH2_INT - AU1000_INTC0_INT_BASE);
462 au_writel(val, IC0_MASKSET); /* unmask */
463 au_writel(val, IC0_WAKESET); /* enable wake-from-sleep */
464 au_sync();
465 spin_unlock_irqrestore(&pm_lock, flags);
466 au1000_calibrate_delay();
467 restore_local_and_enable(0, intc0_mask);
468 restore_local_and_enable(1, intc1_mask);
469
470 return retval;
471}
472#endif
473
474static struct ctl_table pm_table[] = {
475 {
476 .ctl_name = CTL_UNNUMBERED,
477 .procname = "sleep",
478 .data = NULL,
479 .maxlen = 0,
480 .mode = 0600,
481 .proc_handler = &pm_do_sleep
482 },
483#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
484 {
485 .ctl_name = CTL_UNNUMBERED,
486 .procname = "freq",
487 .data = NULL,
488 .maxlen = 0,
489 .mode = 0600,
490 .proc_handler = &pm_do_freq
491 },
492#endif
493 {}
494};
495
496static struct ctl_table pm_dir_table[] = {
497 {
498 .ctl_name = CTL_UNNUMBERED,
499 .procname = "pm",
500 .mode = 0555,
501 .child = pm_table
502 },
503 {}
504};
505
506/*
507 * Initialize power interface
508 */
509static int __init pm_init(void)
510{
511 /* init TOY to tick at 1Hz. No need to wait for access bits
512 * since there's plenty of time between here and the first
513 * suspend cycle.
514 */
515 if (au_readl(SYS_TOYTRIM) != 32767) {
516 au_writel(32767, SYS_TOYTRIM);
517 au_sync();
518 }
519
520 register_sysctl_table(pm_dir_table);
521 return 0;
522}
523
524__initcall(pm_init);
525
526#endif /* CONFIG_PM */ 217#endif /* CONFIG_PM */