idle.c 2.3 KB
Newer Older
O
Olof Johansson 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright (C) 2006-2007 PA Semi, Inc
 *
 * Maintained by: Olof Johansson <olof@lixom.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#undef DEBUG

#include <linux/kernel.h>
#include <linux/string.h>
S
Stephen Rothwell 已提交
25
#include <linux/irq.h>
O
Olof Johansson 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

#include <asm/machdep.h>
#include <asm/reg.h>

#include "pasemi.h"

struct sleep_mode {
	char *name;
	void (*entry)(void);
};

static struct sleep_mode modes[] = {
	{ .name = "spin", .entry = &idle_spin },
	{ .name = "doze", .entry = &idle_doze },
};

static int current_mode = 0;

static int pasemi_system_reset_exception(struct pt_regs *regs)
{
	/* If we were woken up from power savings, we need to return
	 * to the calling function, since nip is not saved across
	 * all modes.
	 */

	if (regs->msr & SRR1_WAKEMASK)
		regs->nip = regs->link;

	switch (regs->msr & SRR1_WAKEMASK) {
	case SRR1_WAKEEE:
		do_IRQ(regs);
		break;
	case SRR1_WAKEDEC:
		timer_interrupt(regs);
		break;
	default:
		/* do system reset */
		return 0;
	}
65 66 67 68

	/* Set higher astate since we come out of power savings at 0 */
	restore_astate(hard_smp_processor_id());

O
Olof Johansson 已提交
69 70 71 72 73 74 75
	/* everything handled */
	regs->msr |= MSR_RI;
	return 1;
}

void __init pasemi_idle_init(void)
{
76 77 78 79 80
#ifndef CONFIG_PPC_PASEMI_CPUFREQ
	printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n");
	current_mode = 0;
#endif

O
Olof Johansson 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	ppc_md.system_reset_exception = pasemi_system_reset_exception;
	ppc_md.power_save = modes[current_mode].entry;
	printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
}

static int __init idle_param(char *p)
{
	int i;
	for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) {
		if (!strcmp(modes[i].name, p)) {
			current_mode = i;
			break;
		}
	}
	return 0;
}

early_param("idle", idle_param);