11199919bSOlof Johansson /* 21199919bSOlof Johansson * Copyright (C) 2006-2007 PA Semi, Inc 31199919bSOlof Johansson * 41199919bSOlof Johansson * Maintained by: Olof Johansson <olof@lixom.net> 51199919bSOlof Johansson * 61199919bSOlof Johansson * This program is free software; you can redistribute it and/or modify 71199919bSOlof Johansson * it under the terms of the GNU General Public License version 2 as 81199919bSOlof Johansson * published by the Free Software Foundation. 91199919bSOlof Johansson * 101199919bSOlof Johansson * This program is distributed in the hope that it will be useful, 111199919bSOlof Johansson * but WITHOUT ANY WARRANTY; without even the implied warranty of 121199919bSOlof Johansson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 131199919bSOlof Johansson * GNU General Public License for more details. 141199919bSOlof Johansson * 151199919bSOlof Johansson * You should have received a copy of the GNU General Public License 161199919bSOlof Johansson * along with this program; if not, write to the Free Software 171199919bSOlof Johansson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 181199919bSOlof Johansson * 191199919bSOlof Johansson */ 201199919bSOlof Johansson 211199919bSOlof Johansson #undef DEBUG 221199919bSOlof Johansson 231199919bSOlof Johansson #include <linux/kernel.h> 241199919bSOlof Johansson #include <linux/string.h> 251199919bSOlof Johansson 261199919bSOlof Johansson #include <asm/machdep.h> 271199919bSOlof Johansson #include <asm/reg.h> 281199919bSOlof Johansson 291199919bSOlof Johansson #include "pasemi.h" 301199919bSOlof Johansson 311199919bSOlof Johansson struct sleep_mode { 321199919bSOlof Johansson char *name; 331199919bSOlof Johansson void (*entry)(void); 341199919bSOlof Johansson }; 351199919bSOlof Johansson 361199919bSOlof Johansson static struct sleep_mode modes[] = { 371199919bSOlof Johansson { .name = "spin", .entry = &idle_spin }, 381199919bSOlof Johansson { .name = "doze", .entry = &idle_doze }, 391199919bSOlof Johansson }; 401199919bSOlof Johansson 411199919bSOlof Johansson static int current_mode = 0; 421199919bSOlof Johansson 431199919bSOlof Johansson static int pasemi_system_reset_exception(struct pt_regs *regs) 441199919bSOlof Johansson { 451199919bSOlof Johansson /* If we were woken up from power savings, we need to return 461199919bSOlof Johansson * to the calling function, since nip is not saved across 471199919bSOlof Johansson * all modes. 481199919bSOlof Johansson */ 491199919bSOlof Johansson 501199919bSOlof Johansson if (regs->msr & SRR1_WAKEMASK) 511199919bSOlof Johansson regs->nip = regs->link; 521199919bSOlof Johansson 531199919bSOlof Johansson switch (regs->msr & SRR1_WAKEMASK) { 541199919bSOlof Johansson case SRR1_WAKEEE: 551199919bSOlof Johansson do_IRQ(regs); 561199919bSOlof Johansson break; 571199919bSOlof Johansson case SRR1_WAKEDEC: 581199919bSOlof Johansson timer_interrupt(regs); 591199919bSOlof Johansson break; 601199919bSOlof Johansson default: 611199919bSOlof Johansson /* do system reset */ 621199919bSOlof Johansson return 0; 631199919bSOlof Johansson } 642e0c3370SOlof Johansson 652e0c3370SOlof Johansson /* Set higher astate since we come out of power savings at 0 */ 662e0c3370SOlof Johansson restore_astate(hard_smp_processor_id()); 672e0c3370SOlof Johansson 681199919bSOlof Johansson /* everything handled */ 691199919bSOlof Johansson regs->msr |= MSR_RI; 701199919bSOlof Johansson return 1; 711199919bSOlof Johansson } 721199919bSOlof Johansson 731199919bSOlof Johansson void __init pasemi_idle_init(void) 741199919bSOlof Johansson { 752e0c3370SOlof Johansson #ifndef CONFIG_PPC_PASEMI_CPUFREQ 762e0c3370SOlof Johansson printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); 772e0c3370SOlof Johansson current_mode = 0; 782e0c3370SOlof Johansson #endif 792e0c3370SOlof Johansson 801199919bSOlof Johansson ppc_md.system_reset_exception = pasemi_system_reset_exception; 811199919bSOlof Johansson ppc_md.power_save = modes[current_mode].entry; 821199919bSOlof Johansson printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); 831199919bSOlof Johansson } 841199919bSOlof Johansson 851199919bSOlof Johansson static int __init idle_param(char *p) 861199919bSOlof Johansson { 871199919bSOlof Johansson int i; 881199919bSOlof Johansson for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) { 891199919bSOlof Johansson if (!strcmp(modes[i].name, p)) { 901199919bSOlof Johansson current_mode = i; 911199919bSOlof Johansson break; 921199919bSOlof Johansson } 931199919bSOlof Johansson } 941199919bSOlof Johansson return 0; 951199919bSOlof Johansson } 961199919bSOlof Johansson 971199919bSOlof Johansson early_param("idle", idle_param); 98