Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2006-2007 PA Semi, Inc
0004  *
0005  * Maintained by: Olof Johansson <olof@lixom.net>
0006  */
0007 
0008 #undef DEBUG
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/string.h>
0012 #include <linux/irq.h>
0013 
0014 #include <asm/machdep.h>
0015 #include <asm/reg.h>
0016 #include <asm/smp.h>
0017 
0018 #include "pasemi.h"
0019 
0020 struct sleep_mode {
0021     char *name;
0022     void (*entry)(void);
0023 };
0024 
0025 static struct sleep_mode modes[] = {
0026     { .name = "spin", .entry = &idle_spin },
0027     { .name = "doze", .entry = &idle_doze },
0028 };
0029 
0030 static int current_mode = 0;
0031 
0032 static int pasemi_system_reset_exception(struct pt_regs *regs)
0033 {
0034     /* If we were woken up from power savings, we need to return
0035      * to the calling function, since nip is not saved across
0036      * all modes.
0037      */
0038 
0039     if (regs->msr & SRR1_WAKEMASK)
0040         regs_set_return_ip(regs, regs->link);
0041 
0042     switch (regs->msr & SRR1_WAKEMASK) {
0043     case SRR1_WAKEDEC:
0044         set_dec(1);
0045         break;
0046     case SRR1_WAKEEE:
0047         /*
0048          * Handle these when interrupts get re-enabled and we take
0049          * them as regular exceptions. We are in an NMI context
0050          * and can't handle these here.
0051          */
0052         break;
0053     default:
0054         /* do system reset */
0055         return 0;
0056     }
0057 
0058     /* Set higher astate since we come out of power savings at 0 */
0059     restore_astate(hard_smp_processor_id());
0060 
0061     /* everything handled */
0062     regs_set_recoverable(regs);
0063     return 1;
0064 }
0065 
0066 static int __init pasemi_idle_init(void)
0067 {
0068 #ifndef CONFIG_PPC_PASEMI_CPUFREQ
0069     pr_warn("No cpufreq driver, powersavings modes disabled\n");
0070     current_mode = 0;
0071 #endif
0072 
0073     ppc_md.system_reset_exception = pasemi_system_reset_exception;
0074     ppc_md.power_save = modes[current_mode].entry;
0075     pr_info("Using PA6T idle loop (%s)\n", modes[current_mode].name);
0076 
0077     return 0;
0078 }
0079 machine_late_initcall(pasemi, pasemi_idle_init);
0080 
0081 static int __init idle_param(char *p)
0082 {
0083     int i;
0084     for (i = 0; i < ARRAY_SIZE(modes); i++) {
0085         if (!strcmp(modes[i].name, p)) {
0086             current_mode = i;
0087             break;
0088         }
0089     }
0090     return 0;
0091 }
0092 
0093 early_param("idle", idle_param);