Commit 3ada9612 authored by Eric Brower's avatar Eric Brower Committed by David S. Miller

Add Sparc Voyager power management support.

parent 2e1e23d5
...@@ -34,6 +34,11 @@ CONFIG_SPARC32 ...@@ -34,6 +34,11 @@ CONFIG_SPARC32
maintains both the SPARC32 and SPARC64 ports; its web page is maintains both the SPARC32 and SPARC64 ports; its web page is
available at <http://www.ultralinux.org/>. available at <http://www.ultralinux.org/>.
SPARC power management support
CONFIG_SUN_PM
Enable power management and CPU standby features on supported
SPARC platforms.
CONFIG_BLK_DEV_FD CONFIG_BLK_DEV_FD
If you want to use the floppy disk drive(s) of your PC under Linux, If you want to use the floppy disk drive(s) of your PC under Linux,
say Y. Information about this driver, especially important for IBM say Y. Information about this driver, especially important for IBM
......
...@@ -38,6 +38,7 @@ define_bool CONFIG_SUN_AUXIO y ...@@ -38,6 +38,7 @@ define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y define_bool CONFIG_SUN_IO y
define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
define_bool CONFIG_SUN_PM y
bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
if [ "$CONFIG_SUN4" != "y" ]; then if [ "$CONFIG_SUN4" != "y" ]; then
......
...@@ -48,6 +48,7 @@ CONFIG_SUN_AUXIO=y ...@@ -48,6 +48,7 @@ CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y CONFIG_SUN_IO=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
CONFIG_SUN_PM=y
# CONFIG_SUN4 is not set # CONFIG_SUN4 is not set
# CONFIG_PCI is not set # CONFIG_PCI is not set
CONFIG_SUN_OPENPROMFS=m CONFIG_SUN_OPENPROMFS=m
......
...@@ -32,6 +32,7 @@ obj-$(CONFIG_SUN4) += sun4setup.o ...@@ -32,6 +32,7 @@ obj-$(CONFIG_SUN4) += sun4setup.o
obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
obj-$(CONFIG_SUN_AUXIO) += auxio.o obj-$(CONFIG_SUN_AUXIO) += auxio.o
obj-$(CONFIG_PCI) += ebus.o obj-$(CONFIG_PCI) += ebus.o
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
ifdef CONFIG_SUNOS_EMUL ifdef CONFIG_SUNOS_EMUL
obj-y += sys_sunos.o sunos_ioctl.o obj-y += sys_sunos.o sunos_ioctl.o
......
/* $Id$
*
* apc - Driver implementation for power management functions
* of Aurora Personality Chip (APC) on SPARCstation-4/5 and
* derivatives.
*
* Copyright (c) 2002 Eric Brower (ebrower@usa.net)
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
#include <asm/io.h>
#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
#include <asm/apc.h>
/* Debugging
*
* #define APC_DEBUG_LED
* #define APC_NO_IDLE
*/
#define APC_MINOR MISC_DYNAMIC_MINOR
#define APC_OBPNAME "power-management"
#define APC_DEVNAME "apc"
volatile static u8 *regs;
static int apc_regsize;
#define apc_readb(offs) (sbus_readb(regs+offs))
#define apc_writeb(val, offs) (sbus_writeb(val, regs+offs))
/*
* CPU idle callback function
* See .../arch/sparc/kernel/process.c
*/
void apc_swift_idle(void)
{
#ifdef APC_DEBUG_LED
set_auxio(0x00, AUXIO_LED);
#endif
apc_writeb(apc_readb(APC_IDLE_REG) | APC_IDLE_ON, APC_IDLE_REG);
#ifdef APC_DEBUG_LED
set_auxio(AUXIO_LED, 0x00);
#endif
}
static inline void apc_free(void)
{
sbus_iounmap((unsigned long)regs, apc_regsize);
}
static int apc_open(struct inode *inode, struct file *f)
{
return 0;
}
static int apc_release(struct inode *inode, struct file *f)
{
return 0;
}
static int apc_ioctl(struct inode *inode, struct file *f,
unsigned int cmd, unsigned long arg)
{
__u8 inarg;
switch (cmd) {
case APCIOCGFANCTL:
if(put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, (__u8*) arg)) {
return -EFAULT;
}
break;
case APCIOCGCPWR:
if(put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, (__u8*) arg)) {
return -EFAULT;
}
break;
case APCIOCGBPORT:
if(put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, (__u8*) arg)) {
return -EFAULT;
}
break;
case APCIOCSFANCTL:
if(get_user(inarg, (__u8*) arg)) {
return -EFAULT;
}
apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
break;
case APCIOCSCPWR:
if(get_user(inarg, (__u8*) arg)) {
return -EFAULT;
}
apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
break;
case APCIOCSBPORT:
if(get_user(inarg, (__u8*) arg)) {
return -EFAULT;
}
apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
break;
default:
return -EINVAL;
};
return 0;
}
static struct file_operations apc_fops = {
ioctl: apc_ioctl,
open: apc_open,
release: apc_release,
};
static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
static int __init apc_probe(void)
{
struct sbus_bus *sbus = NULL;
struct sbus_dev *sdev = NULL;
int iTmp = 0;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
goto sbus_done;
}
}
}
sbus_done:
if (!sdev) {
return -ENODEV;
}
apc_regsize = sdev->reg_addrs[0].reg_size;
regs = (u8*) sbus_ioremap(&sdev->resource[0], 0,
apc_regsize, APC_OBPNAME);
if(NULL == regs) {
printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
return -ENODEV;
}
iTmp = misc_register(&apc_miscdev);
if (iTmp != 0) {
printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
apc_free();
return -ENODEV;
}
#ifndef APC_NO_IDLE
/* Assign power management IDLE handler */
pm_idle = apc_swift_idle;
#endif
printk(KERN_INFO "%s: power management initialized\n", APC_DEVNAME);
return 0;
}
/* This driver is not critical to the boot process
* and is easiest to ioremap when SBus is already
* initialized, so we install ourselves thusly:
*/
__initcall(apc_probe);
/* $Id$
*
* pmc - Driver implementation for power management functions
* of Power Management Controller (PMC) on SPARCstation-Voyager.
*
* Copyright (c) 2002 Eric Brower (ebrower@usa.net)
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
#include <asm/io.h>
#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
/* Debug
*
* #define PMC_DEBUG_LED
* #define PMC_NO_IDLE
*/
#define PMC_MINOR MISC_DYNAMIC_MINOR
#define PMC_OBPNAME "SUNW,pmc"
#define PMC_DEVNAME "pmc"
#define PMC_IDLE_REG 0x00
#define PMC_IDLE_ON 0x01
volatile static u8 *regs;
static int pmc_regsize;
#define pmc_readb(offs) (sbus_readb(regs+offs))
#define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs))
/*
* CPU idle callback function
* See .../arch/sparc/kernel/process.c
*/
void pmc_swift_idle(void)
{
#ifdef PMC_DEBUG_LED
set_auxio(0x00, AUXIO_LED);
#endif
pmc_writeb(pmc_readb(PMC_IDLE_REG) | PMC_IDLE_ON, PMC_IDLE_REG);
#ifdef PMC_DEBUG_LED
set_auxio(AUXIO_LED, 0x00);
#endif
}
static inline void pmc_free(void)
{
sbus_iounmap((unsigned long)regs, pmc_regsize);
}
static int __init pmc_probe(void)
{
struct sbus_bus *sbus = NULL;
struct sbus_dev *sdev = NULL;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
goto sbus_done;
}
}
}
sbus_done:
if (!sdev) {
return -ENODEV;
}
pmc_regsize = sdev->reg_addrs[0].reg_size;
regs = (u8*) sbus_ioremap(&sdev->resource[0], 0,
pmc_regsize, PMC_OBPNAME);
if(NULL == regs) {
printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
return -ENODEV;
}
#ifndef PMC_NO_IDLE
/* Assign power management IDLE handler */
pm_idle = pmc_swift_idle;
#endif
printk(KERN_INFO "%s: power management initialized\n", PMC_DEVNAME);
return 0;
}
/* This driver is not critical to the boot process
* and is easiest to ioremap when SBus is already
* initialized, so we install ourselves thusly:
*/
__initcall(pmc_probe);
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h>
#include <asm/auxio.h> #include <asm/auxio.h>
#include <asm/oplib.h> #include <asm/oplib.h>
...@@ -40,6 +41,19 @@ ...@@ -40,6 +41,19 @@
#include <asm/psr.h> #include <asm/psr.h>
#include <asm/elf.h> #include <asm/elf.h>
/*
* Power management idle function
* Set in pm platform drivers
*/
void (*pm_idle)(void);
/*
* Power-off handler instantiation for pm.h compliance
* This is done via auxio, but could be used as a fallback
* handler when auxio is not present-- unused for now...
*/
void (*pm_power_off)(void);
extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
struct task_struct *last_task_used_math = NULL; struct task_struct *last_task_used_math = NULL;
...@@ -91,8 +105,13 @@ int cpu_idle(void) ...@@ -91,8 +105,13 @@ int cpu_idle(void)
} }
restore_flags(flags); restore_flags(flags);
} }
check_pgt_cache();
while((!current->need_resched) && pm_idle) {
(*pm_idle)();
}
schedule(); schedule();
check_pgt_cache();
} }
ret = 0; ret = 0;
out: out:
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
#include <linux/pci.h> #include <linux/pci.h>
#endif #endif
#include <linux/pm.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/delay.h> #include <asm/delay.h>
...@@ -295,3 +296,6 @@ EXPORT_SYMBOL_DOT(mul); ...@@ -295,3 +296,6 @@ EXPORT_SYMBOL_DOT(mul);
EXPORT_SYMBOL_DOT(umul); EXPORT_SYMBOL_DOT(umul);
EXPORT_SYMBOL_DOT(div); EXPORT_SYMBOL_DOT(div);
EXPORT_SYMBOL_DOT(udiv); EXPORT_SYMBOL_DOT(udiv);
/* Sun Power Management Idle Handler */
EXPORT_SYMBOL(pm_idle);
/* $Id$
*
* apc - Driver definitions for power management functions
* of Aurora Personality Chip (APC) on SPARCstation-4/5 and
* derivatives
*
* Copyright (c) 2001 Eric Brower (ebrower@usa.net)
*
*/
#ifndef _SPARC_APC_H
#define _SPARC_APC_H
#include <linux/ioctl.h>
#define APC_IOC 'A'
#define APCIOCGFANCTL _IOR(APC_IOC, 0x00, int) /* Get fan speed */
#define APCIOCSFANCTL _IOW(APC_IOC, 0x01, int) /* Set fan speed */
#define APCIOCGCPWR _IOR(APC_IOC, 0x02, int) /* Get CPOWER state */
#define APCIOCSCPWR _IOW(APC_IOC, 0x03, int) /* Set CPOWER state */
#define APCIOCGBPORT _IOR(APC_IOC, 0x04, int) /* Get BPORT state */
#define APCIOCSBPORT _IOW(APC_IOC, 0x05, int) /* Set BPORT state */
/*
* Register offsets
*/
#define APC_IDLE_REG 0x00
#define APC_FANCTL_REG 0x20
#define APC_CPOWER_REG 0x24
#define APC_BPORT_REG 0x30
#define APC_REGMASK 0x01
#define APC_BPMASK 0x03
/*
* IDLE - CPU standby values (set to initiate standby)
*/
#define APC_IDLE_ON 0x01
/*
* FANCTL - Fan speed control state values
*/
#define APC_FANCTL_HI 0x00 /* Fan speed high */
#define APC_FANCTL_LO 0x01 /* Fan speed low */
/*
* CPWR - Convenience power outlet state values
*/
#define APC_CPOWER_ON 0x00 /* Conv power on */
#define APC_CPOWER_OFF 0x01 /* Conv power off */
/*
* BPA/BPB - Read-Write "Bit Ports" state values (reset to 0 at power-on)
*
* WARNING: Internal usage of bit ports is platform dependent--
* don't modify BPORT settings unless you know what you are doing.
*
* On SS5 BPA seems to toggle onboard ethernet loopback... -E
*/
#define APC_BPORT_A 0x01 /* Bit Port A */
#define APC_BPORT_B 0x02 /* Bit Port B */
#endif /* !(_SPARC_APC_H) */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment