145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21199919bSOlof Johansson /*
31199919bSOlof Johansson * Copyright (C) 2006-2007 PA Semi, Inc
41199919bSOlof Johansson *
51199919bSOlof Johansson * Maintained by: Olof Johansson <olof@lixom.net>
61199919bSOlof Johansson */
71199919bSOlof Johansson
81199919bSOlof Johansson #undef DEBUG
91199919bSOlof Johansson
101199919bSOlof Johansson #include <linux/kernel.h>
111199919bSOlof Johansson #include <linux/string.h>
12bff8dde8SStephen Rothwell #include <linux/irq.h>
131199919bSOlof Johansson
141199919bSOlof Johansson #include <asm/machdep.h>
151199919bSOlof Johansson #include <asm/reg.h>
1618456d01SStephen Rothwell #include <asm/smp.h>
171199919bSOlof Johansson
181199919bSOlof Johansson #include "pasemi.h"
191199919bSOlof Johansson
201199919bSOlof Johansson struct sleep_mode {
211199919bSOlof Johansson char *name;
221199919bSOlof Johansson void (*entry)(void);
231199919bSOlof Johansson };
241199919bSOlof Johansson
251199919bSOlof Johansson static struct sleep_mode modes[] = {
261199919bSOlof Johansson { .name = "spin", .entry = &idle_spin },
271199919bSOlof Johansson { .name = "doze", .entry = &idle_doze },
281199919bSOlof Johansson };
291199919bSOlof Johansson
301199919bSOlof Johansson static int current_mode = 0;
311199919bSOlof Johansson
pasemi_system_reset_exception(struct pt_regs * regs)321199919bSOlof Johansson static int pasemi_system_reset_exception(struct pt_regs *regs)
331199919bSOlof Johansson {
341199919bSOlof Johansson /* If we were woken up from power savings, we need to return
351199919bSOlof Johansson * to the calling function, since nip is not saved across
361199919bSOlof Johansson * all modes.
371199919bSOlof Johansson */
381199919bSOlof Johansson
391199919bSOlof Johansson if (regs->msr & SRR1_WAKEMASK)
4059dc5bfcSNicholas Piggin regs_set_return_ip(regs, regs->link);
411199919bSOlof Johansson
421199919bSOlof Johansson switch (regs->msr & SRR1_WAKEMASK) {
431199919bSOlof Johansson case SRR1_WAKEDEC:
44461e96a3SNicholas Piggin set_dec(1);
45461e96a3SNicholas Piggin break;
46461e96a3SNicholas Piggin case SRR1_WAKEEE:
47461e96a3SNicholas Piggin /*
48461e96a3SNicholas Piggin * Handle these when interrupts get re-enabled and we take
49461e96a3SNicholas Piggin * them as regular exceptions. We are in an NMI context
50461e96a3SNicholas Piggin * and can't handle these here.
511199919bSOlof Johansson */
521199919bSOlof Johansson break;
531199919bSOlof Johansson default:
541199919bSOlof Johansson /* do system reset */
551199919bSOlof Johansson return 0;
562e0c3370SOlof Johansson }
572e0c3370SOlof Johansson
582e0c3370SOlof Johansson /* Set higher astate since we come out of power savings at 0 */
592e0c3370SOlof Johansson restore_astate(hard_smp_processor_id());
601199919bSOlof Johansson
61*806c0e6eSChristophe Leroy /* everything handled */
621199919bSOlof Johansson regs_set_recoverable(regs);
631199919bSOlof Johansson return 1;
641199919bSOlof Johansson }
653850169dSOlof Johansson
pasemi_idle_init(void)661199919bSOlof Johansson static int __init pasemi_idle_init(void)
672e0c3370SOlof Johansson {
68e13606d7SDarren Stevens #ifndef CONFIG_PPC_PASEMI_CPUFREQ
692e0c3370SOlof Johansson pr_warn("No cpufreq driver, powersavings modes disabled\n");
702e0c3370SOlof Johansson current_mode = 0;
712e0c3370SOlof Johansson #endif
721199919bSOlof Johansson
731199919bSOlof Johansson ppc_md.system_reset_exception = pasemi_system_reset_exception;
74e13606d7SDarren Stevens ppc_md.power_save = modes[current_mode].entry;
753850169dSOlof Johansson pr_info("Using PA6T idle loop (%s)\n", modes[current_mode].name);
763850169dSOlof Johansson
771199919bSOlof Johansson return 0;
78bdddec45SGrant Likely }
791199919bSOlof Johansson machine_late_initcall(pasemi, pasemi_idle_init);
801199919bSOlof Johansson
idle_param(char * p)811199919bSOlof Johansson static int __init idle_param(char *p)
821199919bSOlof Johansson {
83a888ad45SStoyan Gaydarov int i;
841199919bSOlof Johansson for (i = 0; i < ARRAY_SIZE(modes); i++) {
851199919bSOlof Johansson if (!strcmp(modes[i].name, p)) {
861199919bSOlof Johansson current_mode = i;
871199919bSOlof Johansson break;
881199919bSOlof Johansson }
891199919bSOlof Johansson }
901199919bSOlof Johansson return 0;
911199919bSOlof Johansson }
921199919bSOlof Johansson
93 early_param("idle", idle_param);
94