Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2006-2007 PA Semi, Inc |
| 3 | * |
| 4 | * Maintained by: Olof Johansson <olof@lixom.net> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | * |
| 19 | */ |
| 20 | |
| 21 | #undef DEBUG |
| 22 | |
| 23 | #include <linux/kernel.h> |
| 24 | #include <linux/string.h> |
Stephen Rothwell | bff8dde | 2007-05-11 15:40:36 +1000 | [diff] [blame] | 25 | #include <linux/irq.h> |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 26 | |
| 27 | #include <asm/machdep.h> |
| 28 | #include <asm/reg.h> |
Stephen Rothwell | 18456d01 | 2007-05-28 10:20:45 +1000 | [diff] [blame] | 29 | #include <asm/smp.h> |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 30 | |
| 31 | #include "pasemi.h" |
| 32 | |
| 33 | struct sleep_mode { |
| 34 | char *name; |
| 35 | void (*entry)(void); |
| 36 | }; |
| 37 | |
| 38 | static struct sleep_mode modes[] = { |
| 39 | { .name = "spin", .entry = &idle_spin }, |
| 40 | { .name = "doze", .entry = &idle_doze }, |
| 41 | }; |
| 42 | |
| 43 | static int current_mode = 0; |
| 44 | |
| 45 | static int pasemi_system_reset_exception(struct pt_regs *regs) |
| 46 | { |
| 47 | /* If we were woken up from power savings, we need to return |
| 48 | * to the calling function, since nip is not saved across |
| 49 | * all modes. |
| 50 | */ |
| 51 | |
| 52 | if (regs->msr & SRR1_WAKEMASK) |
| 53 | regs->nip = regs->link; |
| 54 | |
| 55 | switch (regs->msr & SRR1_WAKEMASK) { |
| 56 | case SRR1_WAKEEE: |
| 57 | do_IRQ(regs); |
| 58 | break; |
| 59 | case SRR1_WAKEDEC: |
| 60 | timer_interrupt(regs); |
| 61 | break; |
| 62 | default: |
| 63 | /* do system reset */ |
| 64 | return 0; |
| 65 | } |
Olof Johansson | 2e0c337 | 2007-04-27 15:46:01 +1000 | [diff] [blame] | 66 | |
| 67 | /* Set higher astate since we come out of power savings at 0 */ |
| 68 | restore_astate(hard_smp_processor_id()); |
| 69 | |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 70 | /* everything handled */ |
| 71 | regs->msr |= MSR_RI; |
| 72 | return 1; |
| 73 | } |
| 74 | |
Olof Johansson | 3850169 | 2007-09-05 12:09:45 +1000 | [diff] [blame] | 75 | static int __init pasemi_idle_init(void) |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 76 | { |
Olof Johansson | 2e0c337 | 2007-04-27 15:46:01 +1000 | [diff] [blame] | 77 | #ifndef CONFIG_PPC_PASEMI_CPUFREQ |
| 78 | printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); |
| 79 | current_mode = 0; |
| 80 | #endif |
| 81 | |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 82 | ppc_md.system_reset_exception = pasemi_system_reset_exception; |
| 83 | ppc_md.power_save = modes[current_mode].entry; |
| 84 | printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); |
Olof Johansson | 3850169 | 2007-09-05 12:09:45 +1000 | [diff] [blame] | 85 | |
| 86 | return 0; |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 87 | } |
Grant Likely | bdddec4 | 2008-01-02 12:32:28 -0700 | [diff] [blame] | 88 | machine_late_initcall(pasemi, pasemi_idle_init); |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 89 | |
| 90 | static int __init idle_param(char *p) |
| 91 | { |
| 92 | int i; |
Stoyan Gaydarov | a888ad4 | 2009-07-21 17:02:31 +0000 | [diff] [blame] | 93 | for (i = 0; i < ARRAY_SIZE(modes); i++) { |
Olof Johansson | 1199919 | 2007-02-04 16:36:51 -0600 | [diff] [blame] | 94 | if (!strcmp(modes[i].name, p)) { |
| 95 | current_mode = i; |
| 96 | break; |
| 97 | } |
| 98 | } |
| 99 | return 0; |
| 100 | } |
| 101 | |
| 102 | early_param("idle", idle_param); |