pmu.c 3.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *  pmu.c, Power Management Unit routines for NEC VR4100 series.
 *
Y
Yoichi Yuasa 已提交
4
 *  Copyright (C) 2003-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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
 */
20
#include <linux/errno.h>
L
Linus Torvalds 已提交
21
#include <linux/init.h>
22
#include <linux/ioport.h>
L
Linus Torvalds 已提交
23
#include <linux/kernel.h>
24
#include <linux/pm.h>
Y
Yoichi Yuasa 已提交
25
#include <linux/sched.h>
L
Linus Torvalds 已提交
26 27
#include <linux/types.h>

28
#include <asm/cacheflush.h>
L
Linus Torvalds 已提交
29 30
#include <asm/cpu.h>
#include <asm/io.h>
Y
Yoichi Yuasa 已提交
31
#include <asm/processor.h>
L
Linus Torvalds 已提交
32 33 34
#include <asm/reboot.h>
#include <asm/system.h>

35 36 37 38 39 40 41
#define PMU_TYPE1_BASE	0x0b0000a0UL
#define PMU_TYPE1_SIZE	0x0eUL

#define PMU_TYPE2_BASE	0x0f0000c0UL
#define PMU_TYPE2_SIZE	0x10UL

#define PMUCNT2REG	0x06
L
Linus Torvalds 已提交
42 43
 #define SOFTRST	0x0010

44 45 46 47 48
static void __iomem *pmu_base;

#define pmu_read(offset)		readw(pmu_base + (offset))
#define pmu_write(offset, value)	writew((value), pmu_base + (offset))

Y
Yoichi Yuasa 已提交
49 50 51 52 53 54 55 56 57 58 59 60
static void vr41xx_cpu_wait(void)
{
	local_irq_disable();
	if (!need_resched())
		/*
		 * "standby" sets IE bit of the CP0_STATUS to 1.
		 */
		__asm__("standby;\n");
	else
		local_irq_enable();
}

L
Linus Torvalds 已提交
61 62
static inline void software_reset(void)
{
63
	uint16_t pmucnt2;
L
Linus Torvalds 已提交
64 65 66 67 68

	switch (current_cpu_data.cputype) {
	case CPU_VR4122:
	case CPU_VR4131:
	case CPU_VR4133:
69 70 71
		pmucnt2 = pmu_read(PMUCNT2REG);
		pmucnt2 |= SOFTRST;
		pmu_write(PMUCNT2REG, pmucnt2);
L
Linus Torvalds 已提交
72 73
		break;
	default:
74 75 76 77 78
		set_c0_status(ST0_BEV | ST0_ERL);
		change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
		flush_cache_all();
		write_c0_wired(0);
		__asm__("jr     %0"::"r"(0xbfc00000));
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
		break;
	}
}

static void vr41xx_restart(char *command)
{
	local_irq_disable();
	software_reset();
	while (1) ;
}

static void vr41xx_halt(void)
{
	local_irq_disable();
	printk(KERN_NOTICE "\nYou can turn off the power supply\n");
	while (1) ;
}

static void vr41xx_power_off(void)
{
	local_irq_disable();
	printk(KERN_NOTICE "\nYou can turn off the power supply\n");
	while (1) ;
}

static int __init vr41xx_pmu_init(void)
{
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
	unsigned long start, size;

	switch (current_cpu_data.cputype) {
	case CPU_VR4111:
	case CPU_VR4121:
		start = PMU_TYPE1_BASE;
		size = PMU_TYPE1_SIZE;
		break;
	case CPU_VR4122:
	case CPU_VR4131:
	case CPU_VR4133:
		start = PMU_TYPE2_BASE;
		size = PMU_TYPE2_SIZE;
		break;
	default:
		printk("Unexpected CPU of NEC VR4100 series\n");
		return -ENODEV;
	}

	if (request_mem_region(start, size, "PMU") == NULL)
		return -EBUSY;

	pmu_base = ioremap(start, size);
	if (pmu_base == NULL) {
		release_mem_region(start, size);
		return -EBUSY;
	}

Y
Yoichi Yuasa 已提交
134
	cpu_wait = vr41xx_cpu_wait;
L
Linus Torvalds 已提交
135 136
	_machine_restart = vr41xx_restart;
	_machine_halt = vr41xx_halt;
137
	pm_power_off = vr41xx_power_off;
L
Linus Torvalds 已提交
138 139 140 141

	return 0;
}

142
core_initcall(vr41xx_pmu_init);