Commit d26d2b94 authored by Russell King's avatar Russell King

Merge flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5

into flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-rmk
parents c3136961 574e0aa5
......@@ -534,15 +534,63 @@ config CPU_FREQ
written) to implement the policy. If you don't understand what this
is all about, it's safe to say 'N'.
config CPU_FREQ_24_API
# CPUfreq on SA11x0 is special -- it _needs_ the userspace governor
config CPU_FREQ_SA1100
bool
depends on CPU_FREQ && SA1100_LART
default y
config CPU_FREQ_SA1110
bool
depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3)
default y
if (CPU_FREQ_SA1100 || CPU_FREQ_SA1110)
config CPU_FREQ_GOV_USERSPACE
bool
depends on CPU_FREQ
default y
config CPU_FREQ_24_API
bool
depends on CPU_FREQ_GOV_USERSPACE && SYSCTL
default y
config CPU_FREQ_PROC_INTF
tristate
depends on CPU_FREQ
tristate "/proc/cpufreq interface (deprecated)"
depends on CPU_FREQ && PROC_FS
help
This enables the /proc/cpufreq interface for controlling
CPUFreq. Please note that it is recommended to use the sysfs
interface instead (which is built automatically).
For details, take a look at linux/Documentation/cpufreq.
If in doubt, say N.
endif
# CPUfreq on Integrator can use the generic cpufreq core
config CPU_FREQ_INTEGRATOR
tristate "CPUfreq driver for ARM Integrator CPUs"
depends on ARCH_INTEGRATOR && CPU_FREQ
default y
help
This enables the CPUfreq driver for ARM Integrator CPUs.
For details, take a look at linux/Documentation/cpufreq.
If in doubt, say Y.
if (CPU_FREQ_INTEGRATOR)
source "drivers/cpufreq/Kconfig"
endif
source "drivers/pci/Kconfig"
......
......@@ -743,18 +743,11 @@ struct sa1111_save_data {
static int sa1111_suspend(struct device *dev, u32 state, u32 level)
{
struct sa1111 *sachip = dev_get_drvdata(dev);
struct sa1111_save_data *save;
unsigned long flags;
char *base;
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE ||
level == SUSPEND_DISABLE ||
level == SUSPEND_POWER_DOWN) {
struct sa1111_save_data *save;
if (!dev->saved_state)
if (!dev->saved_state && level == SUSPEND_NOTIFY)
dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
if (!dev->saved_state)
return -ENOMEM;
......@@ -762,6 +755,11 @@ static int sa1111_suspend(struct device *dev, u32 state, u32 level)
save = (struct sa1111_save_data *)dev->saved_state;
spin_lock_irqsave(&sachip->lock, flags);
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE) {
base = sachip->base;
save->skcr = sa1111_readl(base + SA1111_SKCR);
save->skpcr = sa1111_readl(base + SA1111_SKPCR);
......@@ -779,25 +777,20 @@ static int sa1111_suspend(struct device *dev, u32 state, u32 level)
save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1);
save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0);
save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1);
spin_unlock_irqrestore(&sachip->lock, flags);
}
/*
* Disable.
*/
if (level == SUSPEND_DISABLE && state == 4) {
unsigned int val;
spin_lock_irqsave(&sachip->lock, flags);
base = sachip->base;
if (level == SUSPEND_POWER_DOWN && state == 4) {
unsigned int val = sa1111_readl(sachip->base + SA1111_SKCR);
sa1111_writel(0, base + SA1111_SKPWM0);
sa1111_writel(0, base + SA1111_SKPWM1);
val = sa1111_readl(base + SA1111_SKCR);
sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR);
sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
sa1111_writel(0, sachip->base + SA1111_SKPWM0);
sa1111_writel(0, sachip->base + SA1111_SKPWM1);
}
spin_unlock_irqrestore(&sachip->lock, flags);
}
return 0;
}
......@@ -819,17 +812,15 @@ static int sa1111_resume(struct device *dev, u32 level)
unsigned long flags, id;
char *base;
if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE)
return 0;
save = (struct sa1111_save_data *)dev->saved_state;
if (!save)
return 0;
dev->saved_state = NULL;
spin_lock_irqsave(&sachip->lock, flags);
/*
* Ensure that the SA1111 is still here.
* FIXME: shouldn't do this here.
*/
id = sa1111_readl(sachip->base + SA1111_SKID);
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
......@@ -839,9 +830,17 @@ static int sa1111_resume(struct device *dev, u32 level)
return 0;
}
spin_lock_irqsave(&sachip->lock, flags);
/*
* First of all, wake up the chip.
*/
if (level == RESUME_POWER_ON) {
sa1111_wake(sachip);
sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0);
sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1);
}
if (level == RESUME_RESTORE_STATE) {
base = sachip->base;
sa1111_writel(save->skcr, base + SA1111_SKCR);
sa1111_writel(save->skpcr, base + SA1111_SKPCR);
......@@ -859,9 +858,14 @@ static int sa1111_resume(struct device *dev, u32 level)
sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0);
sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1);
}
spin_unlock_irqrestore(&sachip->lock, flags);
if (level == RESUME_ENABLE) {
dev->saved_state = NULL;
kfree(save);
}
return 0;
}
......
......@@ -16,6 +16,7 @@ obj-n :=
obj- :=
obj-$(CONFIG_APM) += apm.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o time-acorn.o
obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o
obj-$(CONFIG_FOOTBRIDGE) += isa.o
......
/*
* bios-less APM driver for ARM Linux
* Jamey Hicks <jamey@crl.dec.com>
* adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
*
* APM 1.2 Reference:
* Intel Corporation, Microsoft Corporation. Advanced Power Management
* (APM) BIOS Interface Specification, Revision 1.2, February 1996.
*
* [This document is available from Microsoft at:
* http://www.microsoft.com/hwdev/busbios/amp_12.htm]
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
#include <linux/apm_bios.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <asm/system.h>
/*
* The apm_bios device is one of the misc char devices.
* This is its minor number.
*/
#define APM_MINOR_DEV 134
/*
* See Documentation/Config.help for the configuration options.
*
* Various options can be changed at boot time as follows:
* (We allow underscores for compatibility with the modules code)
* apm=on/off enable/disable APM
*/
/*
* Maximum number of events stored
*/
#define APM_MAX_EVENTS 20
/*
* The per-file APM data
*/
struct apm_user {
struct list_head list;
int suser: 1;
int writer: 1;
int reader: 1;
int suspend_wait: 1;
int suspend_result;
int suspends_pending;
int standbys_pending;
unsigned int suspends_read;
unsigned int standbys_read;
int event_head;
int event_tail;
apm_event_t events[APM_MAX_EVENTS];
};
/*
* Local variables
*/
static int suspends_pending;
static int standbys_pending;
static int apm_disabled;
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
/*
* This is a list of everyone who has opened /dev/apm_bios
*/
static spinlock_t user_list_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(apm_user_list);
/*
* The kapmd info.
*/
static struct task_struct *kapmd;
static DECLARE_COMPLETION(kapmd_exit);
static const char driver_version[] = "1.13"; /* no spaces */
/*
* This structure gets filled in by the machine specific 'get_power_status'
* implementation. Any fields which are not set default to a safe value.
*/
struct apm_power_info {
unsigned char ac_line_status;
unsigned char battery_status;
unsigned char battery_flag;
unsigned char battery_life;
int time;
int units;
};
/*
* Compatibility cruft until the IPAQ people move over to the new
* interface.
*/
static void __apm_get_power_status(struct apm_power_info *info)
{
#if 0 && defined(CONFIG_SA1100_H3600) && defined(CONFIG_TOUCHSCREEN_H3600)
extern int h3600_apm_get_power_status(u_char *, u_char *, u_char *,
u_char *, u_short *);
if (machine_is_h3600()) {
int dx;
h3600_apm_get_power_status(&info->ac_line_status,
&info->battery_status, &info->battery_flag,
&info->battery_life, &dx);
info->time = dx & 0x7fff;
info->units = dx & 0x8000 ? 0 : 1;
}
#endif
}
/*
* This allows machines to provide their own "apm get power status" function.
*/
void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
EXPORT_SYMBOL(apm_get_power_status);
static int queue_empty(struct apm_user *as)
{
return as->event_head == as->event_tail;
}
static apm_event_t get_queued_event(struct apm_user *as)
{
as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
return as->events[as->event_tail];
}
static void queue_event_one_user(struct apm_user *as, apm_event_t event)
{
as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
if (as->event_head == as->event_tail) {
static int notified;
if (notified++ == 0)
printk(KERN_ERR "apm: an event queue overflowed\n");
as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
}
as->events[as->event_head] = event;
if (!as->suser || !as->writer)
return;
switch (event) {
case APM_SYS_SUSPEND:
case APM_USER_SUSPEND:
as->suspends_pending++;
suspends_pending++;
break;
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
as->standbys_pending++;
standbys_pending++;
break;
}
}
static void queue_event(apm_event_t event, struct apm_user *sender)
{
struct list_head *l;
spin_lock(&user_list_lock);
list_for_each(l, &apm_user_list) {
struct apm_user *as = list_entry(l, struct apm_user, list);
if (as != sender && as->reader)
queue_event_one_user(as, event);
}
spin_unlock(&user_list_lock);
wake_up_interruptible(&apm_waitqueue);
}
/* defined in pm.c */
extern int suspend(void);
static int apm_suspend(void)
{
struct list_head *l;
int err = suspend();
/*
* Anyone on the APM queues will think we're still suspended.
* Send a message so everyone knows we're now awake again.
*/
queue_event(APM_NORMAL_RESUME, NULL);
/*
* Finally, wake up anyone who is sleeping on the suspend.
*/
spin_lock(&user_list_lock);
list_for_each(l, &apm_user_list) {
struct apm_user *as = list_entry(l, struct apm_user, list);
as->suspend_result = err;
as->suspend_wait = 0;
}
spin_unlock(&user_list_lock);
wake_up_interruptible(&apm_suspend_waitqueue);
return err;
}
static ssize_t apm_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
{
struct apm_user *as = fp->private_data;
apm_event_t event;
int i = count, ret = 0, nonblock = fp->f_flags & O_NONBLOCK;
if (count < sizeof(apm_event_t))
return -EINVAL;
if (queue_empty(as) && nonblock)
return -EAGAIN;
wait_event_interruptible(apm_waitqueue, !queue_empty(as));
while ((i >= sizeof(event)) && !queue_empty(as)) {
event = get_queued_event(as);
printk(" apm_read: event=%d\n", event);
ret = -EFAULT;
if (copy_to_user(buf, &event, sizeof(event)))
break;
switch (event) {
case APM_SYS_SUSPEND:
case APM_USER_SUSPEND:
as->suspends_read++;
break;
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
as->standbys_read++;
break;
}
buf += sizeof(event);
i -= sizeof(event);
}
if (i < count)
ret = count - i;
return ret;
}
static unsigned int apm_poll(struct file *fp, poll_table * wait)
{
struct apm_user * as = fp->private_data;
poll_wait(fp, &apm_waitqueue, wait);
return queue_empty(as) ? 0 : POLLIN | POLLRDNORM;
}
/*
* apm_ioctl - handle APM ioctl
*
* APM_IOC_SUSPEND
* This IOCTL is overloaded, and performs two functions. It is used to:
* - initiate a suspend
* - acknowledge a suspend read from /dev/apm_bios.
* Only when everyone who has opened /dev/apm_bios with write permission
* has acknowledge does the actual suspend happen.
*/
static int
apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
{
struct apm_user *as = filp->private_data;
int err = -EINVAL;
if (!as->suser || !as->writer)
return -EPERM;
switch (cmd) {
case APM_IOC_STANDBY:
break;
case APM_IOC_SUSPEND:
/*
* If we read a suspend command from /dev/apm_bios,
* then the corresponding APM_IOC_SUSPEND ioctl is
* interpreted as an acknowledge.
*/
if (as->suspends_read > 0) {
as->suspends_read--;
as->suspends_pending--;
suspends_pending--;
} else {
queue_event(APM_USER_SUSPEND, as);
}
/*
* If there are outstanding suspend requests for other
* people on /dev/apm_bios, we must sleep for them.
* Last one to bed turns the lights out.
*/
if (suspends_pending > 0) {
as->suspend_wait = 1;
err = wait_event_interruptible(apm_suspend_waitqueue,
as->suspend_wait == 0);
if (err == 0)
err = as->suspend_result;
} else {
err = apm_suspend();
}
break;
}
return err;
}
static int apm_release(struct inode * inode, struct file * filp)
{
struct apm_user *as = filp->private_data;
filp->private_data = NULL;
spin_lock(&user_list_lock);
list_del(&as->list);
spin_unlock(&user_list_lock);
/*
* We are now unhooked from the chain. As far as new
* events are concerned, we no longer exist. However, we
* need to balance standbys_pending and suspends_pending,
* which means the possibility of sleeping.
*/
if (as->standbys_pending > 0) {
standbys_pending -= as->standbys_pending;
// if (standbys_pending <= 0)
// standby();
}
if (as->suspends_pending > 0) {
suspends_pending -= as->suspends_pending;
if (suspends_pending <= 0)
apm_suspend();
}
kfree(as);
return 0;
}
static int apm_open(struct inode * inode, struct file * filp)
{
struct apm_user *as;
as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
if (as) {
memset(as, 0, sizeof(*as));
/*
* XXX - this is a tiny bit broken, when we consider BSD
* process accounting. If the device is opened by root, we
* instantly flag that we used superuser privs. Who knows,
* we might close the device immediately without doing a
* privileged operation -- cevans
*/
as->suser = capable(CAP_SYS_ADMIN);
as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
spin_lock(&user_list_lock);
list_add(&as->list, &apm_user_list);
spin_unlock(&user_list_lock);
filp->private_data = as;
}
return as ? 0 : -ENOMEM;
}
static struct file_operations apm_bios_fops = {
owner: THIS_MODULE,
read: apm_read,
poll: apm_poll,
ioctl: apm_ioctl,
open: apm_open,
release: apm_release,
};
static struct miscdevice apm_device = {
minor: APM_MINOR_DEV,
name: "apm_bios",
fops: &apm_bios_fops
};
#ifdef CONFIG_PROC_FS
/*
* Arguments, with symbols from linux/apm_bios.h.
*
* 0) Linux driver version (this will change if format changes)
* 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
* 2) APM flags from APM Installation Check (0x00):
* bit 0: APM_16_BIT_SUPPORT
* bit 1: APM_32_BIT_SUPPORT
* bit 2: APM_IDLE_SLOWS_CLOCK
* bit 3: APM_BIOS_DISABLED
* bit 4: APM_BIOS_DISENGAGED
* 3) AC line status
* 0x00: Off-line
* 0x01: On-line
* 0x02: On backup power (BIOS >= 1.1 only)
* 0xff: Unknown
* 4) Battery status
* 0x00: High
* 0x01: Low
* 0x02: Critical
* 0x03: Charging
* 0x04: Selected battery not present (BIOS >= 1.2 only)
* 0xff: Unknown
* 5) Battery flag
* bit 0: High
* bit 1: Low
* bit 2: Critical
* bit 3: Charging
* bit 7: No system battery
* 0xff: Unknown
* 6) Remaining battery life (percentage of charge):
* 0-100: valid
* -1: Unknown
* 7) Remaining battery life (time units):
* Number of remaining minutes or seconds
* -1: Unknown
* 8) min = minutes; sec = seconds
*/
static int apm_get_info(char *buf, char **start, off_t fpos, int length)
{
struct apm_power_info info;
char *units;
int ret;
info.ac_line_status = 0xff;
info.battery_status = 0xff;
info.battery_flag = 0xff;
info.battery_life = 255;
info.time = -1;
info.units = -1;
if (apm_get_power_status)
apm_get_power_status(&info);
switch (info.units) {
default: units = "?"; break;
case 0: units = "min"; break;
case 1: units = "sec"; break;
}
ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
driver_version, APM_32_BIT_SUPPORT,
info.ac_line_status, info.battery_status,
info.battery_flag, info.battery_life,
info.time, units);
return ret;
}
#endif
#if 0
static int kapmd(void *startup)
{
struct task_struct *tsk = current;
daemonize();
strcpy(tsk->comm, "kapmd");
kapmd = tsk;
spin_lock_irq(&tsk->sigmask_lock);
siginitsetinv(&tsk->blocked, sigmask(SIGQUIT));
recalc_sigpending(tsk);
spin_unlock_irq(&tsk->sigmask_lock);
complete((struct completion *)startup);
do {
set_task_state(tsk, TASK_INTERRUPTIBLE);
schedule();
} while (!signal_pending(tsk));
complete_and_exit(&kapmd_exit, 0);
}
#endif
static int __init apm_init(void)
{
// struct completion startup = COMPLETION_INITIALIZER(startup);
int ret;
if (apm_disabled) {
printk(KERN_NOTICE "apm: disabled on user request.\n");
return -ENODEV;
}
if (PM_IS_ACTIVE()) {
printk(KERN_NOTICE "apm: overridden by ACPI.\n");
return -EINVAL;
}
// ret = kernel_thread(kapmd, &startup, CLONE_FS | CLONE_FILES);
// if (ret)
// return ret;
// wait_for_completion(&startup);
pm_active = 1;
#ifdef CONFIG_PROC_FS
create_proc_info_entry("apm", 0, NULL, apm_get_info);
#endif
ret = misc_register(&apm_device);
if (ret != 0) {
pm_active = 0;
remove_proc_entry("apm", NULL);
send_sig(SIGQUIT, kapmd, 1);
wait_for_completion(&kapmd_exit);
}
return ret;
}
static void __exit apm_exit(void)
{
misc_deregister(&apm_device);
remove_proc_entry("apm", NULL);
pm_active = 0;
// send_sig(SIGQUIT, kapmd, 1);
// wait_for_completion(&kapmd_exit);
}
module_init(apm_init);
module_exit(apm_exit);
MODULE_AUTHOR("Stephen Rothwell");
MODULE_DESCRIPTION("Advanced Power Management");
MODULE_LICENSE("GPL");
EXPORT_NO_SYMBOLS;
#ifndef MODULE
static int __init apm_setup(char *str)
{
while ((str != NULL) && (*str != '\0')) {
if (strncmp(str, "off", 3) == 0)
apm_disabled = 1;
if (strncmp(str, "on", 2) == 0)
apm_disabled = 0;
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
}
return 1;
}
__setup("apm=", apm_setup);
#endif
......@@ -18,7 +18,6 @@
#include <asm/mach/pci.h>
static int debug_pci;
int have_isa_bridge;
void pcibios_report_status(u_int status_mask, int warn)
{
......@@ -363,9 +362,8 @@ pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root)
void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_sys_data *root = bus->sysdata;
struct list_head *walk;
u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
u16 all_status = -1;
struct pci_dev *dev;
u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK;
pbus_assign_bus_resources(bus, root);
......@@ -373,42 +371,43 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
* Walk the devices on this bus, working out what we can
* and can't support.
*/
for (walk = bus->devices.next; walk != &bus->devices; walk = walk->next) {
struct pci_dev *dev = pci_dev_b(walk);
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 status;
pdev_fixup_device_resources(root, dev);
pci_read_config_word(dev, PCI_STATUS, &status);
all_status &= status;
/*
* If any device on this bus does not support fast back
* to back transfers, then the bus as a whole is not able
* to support them. Having fast back to back transfers
* on saves us one PCI cycle per transaction.
*/
if (!(status & PCI_STATUS_FAST_BACK))
features &= ~PCI_COMMAND_FAST_BACK;
if (pdev_bad_for_parity(dev))
features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
switch (dev->class >> 8) {
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
case PCI_CLASS_BRIDGE_ISA:
case PCI_CLASS_BRIDGE_EISA:
/*
* If this device is an ISA bridge, set the have_isa_bridge
* flag. We will then go looking for things like keyboard,
* etc
* If this device is an ISA bridge, set isa_bridge
* to point at this device. We will then go looking
* for things like keyboard, etc.
*/
if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA ||
dev->class >> 8 == PCI_CLASS_BRIDGE_EISA)
have_isa_bridge = !0;
isa_bridge = dev;
break;
#endif
}
/*
* If any device on this bus does not support fast back to back
* transfers, then the bus as a whole is not able to support them.
* Having fast back to back transfers on saves us one PCI cycle
* per transaction.
*/
if (all_status & PCI_STATUS_FAST_BACK)
features |= PCI_COMMAND_FAST_BACK;
/*
* Now walk the devices again, this time setting them up.
*/
for (walk = bus->devices.next; walk != &bus->devices; walk = walk->next) {
struct pci_dev *dev = pci_dev_b(walk);
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 cmd;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
......@@ -416,7 +415,17 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
SMP_CACHE_BYTES >> 2);
L1_CACHE_BYTES >> 2);
}
/*
* Propagate the flags to the PCI bridge.
*/
if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
if (features & PCI_COMMAND_FAST_BACK)
bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
if (features & PCI_COMMAND_PARITY)
bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
}
/*
......@@ -454,10 +463,8 @@ pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *rang
*/
u8 __devinit pci_std_swizzle(struct pci_dev *dev, u8 *pinp)
{
int pin = *pinp;
int pin = *pinp - 1;
if (pin != 0) {
pin -= 1;
while (dev->bus->self) {
pin = (pin + PCI_SLOT(dev->devfn)) & 3;
/*
......@@ -467,7 +474,6 @@ u8 __devinit pci_std_swizzle(struct pci_dev *dev, u8 *pinp)
dev = dev->bus->self;
}
*pinp = pin + 1;
}
return PCI_SLOT(dev->devfn);
}
......
......@@ -37,7 +37,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/notifier.h>
#include <linux/device.h>
#include <linux/init.h>
......@@ -57,7 +56,7 @@
enum req {
req_readbytes,
req_reset_all
req_reset
};
struct ecard_request {
......@@ -131,14 +130,11 @@ slot_to_ecard(unsigned int slot)
#define POD_INT_ADDR(x) ((volatile unsigned char *)\
((BUS_ADDR((x)) - IO_BASE) + IO_START))
static inline void ecard_task_reset(void)
static inline void ecard_task_reset(struct ecard_request *req)
{
ecard_t *ec;
for (ec = cards; ec; ec = ec->next)
struct expansion_card *ec = req->ec;
if (ec->loader)
ecard_loader_reset(POD_INT_ADDR(ec->podaddr),
ec->loader);
ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader);
}
static void
......@@ -218,8 +214,8 @@ static void ecard_do_request(struct ecard_request *req)
ecard_task_readbytes(req);
break;
case req_reset_all:
ecard_task_reset();
case req_reset:
ecard_task_reset(req);
break;
}
}
......@@ -355,60 +351,6 @@ ecard_call(struct ecard_request *req)
/* ======================= Mid-level card control ===================== */
/*
* This function is responsible for resetting the expansion cards to a
* sensible state immediately prior to rebooting the system. This function
* has process state (keventd), so we can sleep.
*
* Possible "val" values here:
* SYS_RESTART - restarting system
* SYS_HALT - halting system
* SYS_POWER_OFF - powering down system
*
* We ignore all calls, unless it is a SYS_RESTART call - power down/halts
* will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
*/
static int ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
{
struct ecard_request req;
if (val != SYS_RESTART)
return 0;
/*
* Disable the expansion card interrupt
*/
disable_irq(IRQ_EXPANSIONCARD);
/*
* If we have any expansion card loader code which will handle
* the reset for us, call it now.
*/
req.req = req_reset_all;
ecard_call(&req);
/*
* Disable the expansion card interrupt again, just to be sure.
*/
disable_irq(IRQ_EXPANSIONCARD);
/*
* Finally, reset the expansion card interrupt mask to
* all enable (RISC OS doesn't set this)
*/
#ifdef HAS_EXPMASK
have_expmask = ~0;
__raw_writeb(have_expmask, EXPMASK_ENABLE);
#endif
return 0;
}
static struct notifier_block ecard_reboot_notifier = {
.notifier_call = ecard_reboot,
};
static void
ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
{
......@@ -1083,11 +1025,6 @@ static int __init ecard_init(void)
{
int slot, irqhw;
/*
* Register our reboot notifier
*/
register_reboot_notifier(&ecard_reboot_notifier);
#ifdef CONFIG_CPU_32
init_waitqueue_head(&ecard_wait);
#endif
......@@ -1158,11 +1095,32 @@ static int ecard_drv_remove(struct device *dev)
return 0;
}
/*
* Before rebooting, we must make sure that the expansion card is in a
* sensible state, so it can be re-detected. This means that the first
* page of the ROM must be visible. We call the expansion cards reset
* handler, if any.
*/
static void ecard_drv_shutdown(struct device *dev)
{
struct expansion_card *ec = ECARD_DEV(dev);
struct ecard_driver *drv = ECARD_DRV(dev->driver);
struct ecard_request req;
if (drv->shutdown)
drv->shutdown(ec);
ecard_release(ec);
req.req = req_reset;
req.ec = ec;
ecard_call(&req);
}
int ecard_register_driver(struct ecard_driver *drv)
{
drv->drv.bus = &ecard_bus_type;
drv->drv.probe = ecard_drv_probe;
drv->drv.remove = ecard_drv_remove;
drv->drv.shutdown = ecard_drv_shutdown;
return driver_register(&drv->drv);
}
......
......@@ -1028,8 +1028,10 @@ vector_IRQ: @
@
@ now branch to the relevant MODE handling routine
@
mov r13, #PSR_I_BIT | MODE_SVC
msr spsr_c, r13 @ switch to SVC_32 mode
mrs r13, cpsr
bic r13, r13, #MODE_MASK
orr r13, r13, #MODE_SVC
msr spsr, r13 @ switch to SVC_32 mode
and lr, lr, #15
ldr lr, [pc, lr, lsl #2]
......
......@@ -75,9 +75,8 @@ no_work_pending:
* This is how we return from a fork.
*/
ENTRY(ret_from_fork)
#ifdef CONFIG_PREEMPT
ldr r0, [r0, #TI_TASK]
bl schedule_tail
#endif
get_thread_info tsk
ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing
mov why, #1
......
/*
* linux/arch/arm/kernel/suspend.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*
* This is the common support code for suspending an ARM machine.
* pm_do_suspend() is responsible for actually putting the CPU to
* sleep.
*/
#include <linux/config.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/cpufreq.h>
#include <asm/leds.h>
#include <asm/system.h>
int suspend(void)
{
int ret;
/*
* Suspend "legacy" devices.
*/
ret = pm_send_all(PM_SUSPEND, (void *)3);
if (ret != 0)
goto out;
/*
* Tell LDM devices we're going to suspend.
*/
ret = device_suspend(4, SUSPEND_NOTIFY);
if (ret != 0)
goto resume_legacy;
/*
* Disable, devices, and save state.
*/
device_suspend(4, SUSPEND_DISABLE);
device_suspend(4, SUSPEND_SAVE_STATE);
/*
* Tell devices that they're going to be powered off.
*/
device_suspend(4, SUSPEND_POWER_DOWN);
local_irq_disable();
leds_event(led_stop);
ret = pm_do_suspend();
leds_event(led_start);
local_irq_enable();
/*
* Tell devices that they now have power.
*/
device_resume(RESUME_POWER_ON);
/*
* Restore the CPU frequency settings.
*/
#ifdef CONFIG_CPU_FREQ
cpufreq_restore();
#endif
/*
* Resume LDM devices.
*/
device_resume(RESUME_RESTORE_STATE);
device_resume(RESUME_ENABLE);
resume_legacy:
/*
* Resume "legacy" devices.
*/
pm_send_all(PM_RESUME, (void *)0);
out:
return ret;
}
#ifdef CONFIG_SYSCTL
#include <linux/init.h>
#include <linux/sysctl.h>
/*
* This came from arch/arm/mach-sa1100/pm.c:
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
* with modifications by Nicolas Pitre and Russell King.
*
* ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
* linux/sysctl.h.
*
* This means our interface here won't survive long - it needs a new
* interface. Quick hack to get this working - use sysctl id 9999.
*/
#warning ACPI broke the kernel, this interface needs to be fixed up.
#define CTL_ACPI 9999
#define ACPI_S1_SLP_TYP 19
static struct ctl_table pm_table[] =
{
{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&suspend},
{0}
};
static struct ctl_table pm_dir_table[] =
{
{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
{0}
};
/*
* Initialize power interface
*/
static int __init pm_init(void)
{
register_sysctl_table(pm_dir_table, 1);
return 0;
}
fs_initcall(pm_init);
#endif
......@@ -200,6 +200,7 @@ void do_settimeofday(struct timeval *tv)
static struct irqaction timer_irq = {
.name = "timer",
.flags = SA_INTERRUPT,
};
/*
......
......@@ -4,10 +4,11 @@
# Object file lists.
obj-y := arch.o cpu.o irq.o mm.o time.o
obj-y := arch.o irq.o mm.o time.o
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_PCI) += pci_v3.o pci.o
obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o
......@@ -23,6 +23,8 @@
#include <asm/hardware.h>
#include <asm/io.h>
static struct cpufreq_driver integrator_driver;
#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
......@@ -43,7 +45,6 @@ static unsigned int vco_to_freq(struct vco vco, int factor)
return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor;
}
#ifdef CONFIG_CPU_FREQ
/*
* Divisor indexes in ascending divisor order
*/
......@@ -69,21 +70,17 @@ static struct vco freq_to_vco(unsigned int freq_khz, int factor)
return vco;
}
/*
* Validate the speed in khz. If it is outside our
* range, then return the lowest.
* Validate the speed policy.
*/
static int integrator_verify_speed(struct cpufreq_policy *policy)
static int integrator_verify_policy(struct cpufreq_policy *policy)
{
struct vco vco;
if (policy->max > policy->cpuinfo.max_freq)
policy->max = policy->cpuinfo.max_freq;
if (policy->max < 12000)
policy->max = 12000;
if (policy->max > 160000)
policy->max = 160000;
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
vco = freq_to_vco(policy->max, 1);
......@@ -92,12 +89,28 @@ static int integrator_verify_speed(struct cpufreq_policy *policy)
if (vco.vdw > 152)
vco.vdw = 152;
policy->min = policy->max = vco_to_freq(vco, 1);
policy->max = vco_to_freq(vco, 1);
vco = freq_to_vco(policy->min, 1);
if (vco.vdw < 4)
vco.vdw = 4;
if (vco.vdw > 152)
vco.vdw = 152;
policy->min = vco_to_freq(vco, 1);
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
return 0;
}
static int integrator_set_policy(struct cpufreq_policy *policy)
static int integrator_set_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned long cpus_allowed;
int cpu = policy->cpu;
......@@ -121,9 +134,18 @@ static int integrator_set_policy(struct cpufreq_policy *policy)
cm_osc = __raw_readl(CM_OSC);
vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255;
freqs.old = vco_to_freq(vco, 1);
freqs.new = target_freq;
/* freq_to_vco rounds down -- so we need the next larger freq in
* case of CPUFREQ_RELATION_L.
*/
if (relation == CPUFREQ_RELATION_L)
target_freq += 1999;
if (target_freq > policy->max)
target_freq = policy->max;
vco = freq_to_vco(target_freq, 1);
freqs.new = vco_to_freq(vco, 1);
freqs.cpu = policy->cpu;
if (freqs.old == freqs.new) {
......@@ -132,7 +154,6 @@ static int integrator_set_policy(struct cpufreq_policy *policy)
}
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
vco = freq_to_vco(policy->max, 1);
cm_osc = __raw_readl(CM_OSC);
cm_osc &= 0xfffff800;
......@@ -152,48 +173,19 @@ static int integrator_set_policy(struct cpufreq_policy *policy)
return 0;
}
static struct cpufreq_policy integrator_policy = {
.cpu = 0,
.policy = CPUFREQ_POLICY_POWERSAVE,
.cpuinfo = {
.max_freq = 160000,
.min_freq = 12000,
.transition_latency = CPUFREQ_ETERNAL,
},
};
static struct cpufreq_driver integrator_driver = {
.verify = integrator_verify_speed,
.setpolicy = integrator_set_policy,
.policy = &integrator_policy,
.name = "integrator",
};
#endif
static int __init integrator_cpu_init(void)
static int integrator_cpufreq_init(struct cpufreq *policy)
{
struct cpufreq_policy *policies;
unsigned long cpus_allowed;
int cpu;
policies = kmalloc(sizeof(struct cpufreq_policy) * NR_CPUS,
GFP_KERNEL);
if (!policies) {
printk(KERN_ERR "CPU: unable to allocate policies structure\n");
return -ENOMEM;
}
cpus_allowed = current->cpus_allowed;
for (cpu = 0; cpu < NR_CPUS; cpu++) {
unsigned long cus_allowed;
unsigned int cpu = policy->cpu;
u_int cm_osc, cm_stat, mem_freq_khz;
struct vco vco;
if (!cpu_online(cpu))
continue;
cpus_allowed = current->cpus_allowed;
set_cpus_allowed(current, 1 << cpu);
BUG_ON(cpu != smp_processor_id());
/* detect memory etc. */
cm_stat = __raw_readl(CM_STAT);
cm_osc = __raw_readl(CM_OSC);
vco.od = (cm_osc >> 20) & 7;
......@@ -207,25 +199,38 @@ static int __init integrator_cpu_init(void)
vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255;
policies[cpu].cpu = cpu;
policies[cpu].policy = CPUFREQ_POLICY_POWERSAVE,
policies[cpu].cpuinfo.max_freq = 160000;
policies[cpu].cpuinfo.min_freq = 12000;
policies[cpu].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policies[cpu].min =
policies[cpu].max = vco_to_freq(vco, 1);
}
/* set default policy and cpuinfo */
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.max_freq = 160000;
policy->cpuinfo.min_freq = 12000;
policy->cpuinfo.transition_latency = 1000; /* 1 ms, assumed */
policy->cur = policy->min = policy->max = vco_to_freq(vco, 1); /* current freq */
set_cpus_allowed(current, cpus_allowed);
#ifdef CONFIG_CPU_FREQ
integrator_driver.policy = policies;
cpufreq_register(&integrator_driver);
#else
kfree(policies);
#endif
return 0;
}
arch_initcall(integrator_cpu_init);
static struct cpufreq_driver integrator_driver = {
.verify = integrator_verify_policy,
.target = integrator_set_target,
.init = integrator_cpufreq_init,
.name = "integrator",
};
static int __init integrator_cpu_init(void)
{
return cpufreq_register_driver(&integrator_driver);
}
static void __exit integrator_cpu_exit(void)
{
cpufreq_unregister_driver(&integrator_driver);
}
MODULE_AUTHOR ("Russell M. King");
MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
MODULE_LICENSE ("GPL");
module_init(integrator_cpu_init);
module_exit(integrator_cpu_exit);
......@@ -9,15 +9,8 @@ obj-n :=
obj- :=
led-y := leds.o
# This needs to be cleaned up. We probably need to have SA1100
# and SA1110 config symbols.
ifeq ($(CONFIG_CPU_FREQ),y)
obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o
obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o
obj-$(CONFIG_SA1100_HACKKIT) += cpu-sa1110.o
obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o
obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o
endif
obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o
obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o
# Specific board support
obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o
......
......@@ -101,7 +101,7 @@ typedef struct {
} sa1100_dram_regs_t;
static struct cpufreq_driver sa1100_driver;
static sa1100_dram_regs_t sa1100_dram_settings[] =
{
......@@ -176,60 +176,73 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
}
}
static int sa1100_setspeed(struct cpufreq_policy *policy)
static int sa1100_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int cur = sa11x0_getspeed();
unsigned int new_ppcr;
struct cpufreq_freqs freqs;
switch(relation){
case CPUFREQ_RELATION_L:
new_ppcr = sa11x0_freq_to_ppcr(target_freq);
if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max)
new_ppcr--;
break;
case CPUFREQ_RELATION_H:
new_ppcr = sa11x0_freq_to_ppcr(target_freq);
if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) &&
(sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min))
mew_ppcr--;
break;
}
freqs.old = cur;
freqs.new = policy->max;
freqs.new = sa11x0_ppcr_to_freq(new_ppcr);
freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (policy->max > cur)
sa1100_update_dram_timings(cur, policy->max);
if (freqs.new > cur)
sa1100_update_dram_timings(cur, freqs.new);
PPCR = sa11x0_freq_to_ppcr(policy->max);
PPCR = new_ppcr;
if (policy->max < cur)
sa1100_update_dram_timings(cur, policy->max);
if (freqs.new < cur)
sa1100_update_dram_timings(cur, freqs.new);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0;
}
static struct cpufreq_policy sa1100_policy = {
.cpu = 0,
.policy = CPUFREQ_POLICY_POWERSAVE,
.cpuinfo = {
.max_freq = 287000,
.min_freq = 59000,
.transition_latency = CPUFREQ_ETERNAL,
},
};
static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
{
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed();
policy->policy = CPUFREQ_POLICY_POWERSAVE;
policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
return 0;
}
static struct cpufreq_driver sa1100_driver = {
.verify = sa11x0_verify_speed,
.setpolicy = sa1100_setspeed,
.policy = &sa1100_policy,
.target = sa1100_target,
.init = sa1100_cpu_init,
.name = "sa1100",
};
static int __init sa1100_dram_init(void)
{
int ret = -ENODEV;
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) {
sa1100_driver.cpu_cur_freq[0] =
sa1100_policy.min =
sa1100_policy.max = sa11x0_getspeed();
ret = cpufreq_register(&sa1100_driver);
}
return ret;
cpufreq_gov_userspace_init();
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
return cpufreq_register_driver(&sa1100_driver);
else
return -ENODEV;
}
arch_initcall(sa1100_dram_init);
......@@ -32,6 +32,8 @@
#undef DEBUG
static struct cpufreq_driver sa1110_driver;
struct sdram_params {
u_char rows; /* bits */
u_char cas_latency; /* cycles */
......@@ -208,11 +210,11 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
}
/*
* Ok, set the CPU frequency. Since we've done the validation
* above, we can match for an exact frequency. If we don't find
* an exact match, we will to set the lowest frequency to be safe.
* Ok, set the CPU frequency.
*/
static int sa1110_setspeed(struct cpufreq_policy *policy)
static int sa1110_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
struct sdram_params *sdram = &sdram_params;
struct cpufreq_freqs freqs;
......@@ -220,8 +222,25 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
unsigned long flags;
unsigned int ppcr, unused;
ppcr = sa11x0_freq_to_ppcr(policy->max);
sdram_calculate_timing(&sd, policy->max, sdram);
switch(relation){
case CPUFREQ_RELATION_L:
ppcr = sa11x0_freq_to_ppcr(target_freq);
if (sa11x0_ppcr_to_freq(ppcr) > policy->max)
ppcr--;
break;
case CPUFREQ_RELATION_H:
ppcr = sa11x0_freq_to_ppcr(target_freq);
if (ppcr && (sa11x0_ppcr_to_freq(ppcr) > target_freq) &&
(sa11x0_ppcr_to_freq(ppcr-1) >= policy->min))
ppcr--;
break;
}
freqs.old = sa11x0_getspeed();
freqs.new = sa11x0_ppcr_to_freq(ppcr);
freqs.cpu = 0;
sdram_calculate_timing(&sd, freqs.new, sdram);
#if 0
/*
......@@ -240,10 +259,6 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
sd.mdcas[2] = 0xaaaaaaaa;
#endif
freqs.old = sa11x0_getspeed();
freqs.new = policy->max;
freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/*
......@@ -288,27 +303,29 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
/*
* Now, return the SDRAM refresh back to normal.
*/
sdram_update_refresh(policy->max, sdram);
sdram_update_refresh(freqs.new, sdram);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0;
}
static struct cpufreq_policy sa1110_policy = {
.cpu = 0,
.policy = CPUFREQ_POLICY_POWERSAVE,
.cpuinfo = {
.max_freq = 287000,
.min_freq = 59000,
.transition_latency = CPUFREQ_ETERNAL,
},
};
static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
{
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed();
policy->policy = CPUFREQ_POLICY_POWERSAVE;
policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
return 0;
}
static struct cpufreq_driver sa1110_driver = {
.verify = sa11x0_verify_speed,
.setpolicy = sa1110_setspeed,
.policy = &sa1110_policy,
.target = sa1110_target,
.init = sa1110_cpu_init,
.name = "sa1110",
};
......@@ -331,15 +348,11 @@ static int __init sa1110_clk_init(void)
sdram->tck, sdram->trcd, sdram->trp,
sdram->twr, sdram->refresh, sdram->cas_latency);
memcpy(&sdram_params, sdram, sizeof(sdram_params));
sa1110_driver.cpu_cur_freq[0] =
sa1110_policy.min =
sa1110_policy.max = sa11x0_getspeed();
cpufreq_gov_userspace_init();
sa1110_setspeed(&sa1110_policy);
memcpy(&sdram_params, sdram, sizeof(sdram_params));
return cpufreq_register(&sa1110_driver);
return cpufreq_register_driver(&sa1110_driver);
}
return 0;
......
......@@ -48,33 +48,48 @@ static const unsigned short cclk_frequency_100khz[NR_FREQS] = {
2802 /* 280.2 MHz */
};
#ifdef CONFIG_CPU_FREQ
#if defined(CONFIG_CPU_FREQ_SA1100) || defined(CONFIG_CPU_FREQ_SA1110)
/* rounds up(!) */
unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
{
int i;
khz /= 100;
for (i = NR_FREQS - 1; i > 0; i--)
if (cclk_frequency_100khz[i] <= khz)
for (i = 0; i < NR_FREQS; i++)
if (cclk_frequency_100khz[i] >= khz)
break;
return i;
}
/*
* Validate the policy. We aren't able to do any fancy in-kernel
* scaling, so we force min=max, and set the policy to "performance".
* If we can't generate the precise frequency requested, round it up.
unsigned int sa11x0_ppcr_to_freq(unsigned int idx)
{
unsigned int freq = 0;
if (idx < NR_FREQS)
freq = cclk_frequency_100khz[idx] * 100;
return freq;
}
/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
* this platform, anyway.
*/
int sa11x0_verify_speed(struct cpufreq_policy *policy)
{
if (policy->max > policy->cpuinfo.max_freq)
policy->max = policy->cpuinfo.max_freq;
unsigned int tmp;
if (policy->cpu)
return -EINVAL;
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
/* make sure that at least one frequency is within the policy */
tmp = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->min)] * 100;
if (tmp > policy->max)
policy->max = tmp;
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
policy->max = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->max)] * 100;
policy->min = policy->max;
policy->policy = CPUFREQ_POLICY_POWERSAVE;
return 0;
}
......
......@@ -23,3 +23,4 @@ struct cpufreq_policy;
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern int sa11x0_verify_speed(struct cpufreq_policy *policy);
extern unsigned int sa11x0_getspeed(void);
extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx);
......@@ -211,6 +211,99 @@ static struct resource irq_resource = {
.end = 0x9005ffff,
};
struct sa1100irq_state {
unsigned int saved;
unsigned int icmr;
unsigned int iclr;
unsigned int iccr;
};
static int sa1100irq_suspend(struct device *dev, u32 state, u32 level)
{
struct sa1100irq_state *st;
if (!dev->saved_state && level == SUSPEND_NOTIFY)
dev->saved_state = kmalloc(sizeof(struct sa1100irq_state),
GFP_KERNEL);
if (!dev->saved_state)
return -ENOMEM;
if (level == SUSPEND_POWER_DOWN) {
st = (struct sa1100irq_state *)dev->saved_state;
st->saved = 1;
st->icmr = ICMR;
st->iclr = ICLR;
st->iccr = ICCR;
/*
* Disable all GPIO-based interrupts.
*/
ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7|
IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2|
IC_GPIO1|IC_GPIO0);
/*
* Set the appropriate edges for wakeup.
*/
GRER = PWER & GPIO_IRQ_rising_edge;
GFER = PWER & GPIO_IRQ_falling_edge;
/*
* Clear any pending GPIO interrupts.
*/
GEDR = GEDR;
}
return 0;
}
static int sa1100irq_resume(struct device *dev, u32 level)
{
struct sa1100irq_state *st;
if (level == RESUME_POWER_ON) {
st = (struct sa1100irq_state *)dev->saved_state;
dev->saved_state = NULL;
if (st->saved) {
ICCR = st->iccr;
ICLR = st->iclr;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
ICMR = st->icmr;
}
kfree(st);
}
return 0;
}
static struct device_driver sa1100irq_driver = {
.name = "sa11x0-irq",
.bus = &system_bus_type,
.suspend = sa1100irq_suspend,
.resume = sa1100irq_resume,
};
static struct sys_device sa1100irq_device = {
.name = "irq",
.id = 0,
.dev = {
.name = "Intel SA11x0 [Interrupt Controller]",
.driver = &sa1100irq_driver,
},
};
static int __init sa1100irq_init_devicefs(void)
{
driver_register(&sa1100irq_driver);
return sys_device_register(&sa1100irq_device);
}
device_initcall(sa1100irq_init_devicefs);
void __init sa1100_init_irq(void)
{
unsigned int irq;
......
......@@ -22,25 +22,12 @@
* 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array.
* Storage is local on the stack now.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/cpufreq.h>
#include <linux/time.h>
#include <asm/hardware.h>
#include <asm/memory.h>
#include <asm/system.h>
#include <asm/leds.h>
/*
* Debug macros
*/
#undef DEBUG
extern void sa1100_cpu_suspend(void);
extern void sa1100_cpu_resume(void);
......@@ -58,10 +45,9 @@ enum { SLEEP_SAVE_SP = 0,
SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
SLEEP_SAVE_ICMR,
SLEEP_SAVE_Ser1SDCR0,
SLEEP_SAVE_SIZE
......@@ -72,10 +58,6 @@ int pm_do_suspend(void)
{
unsigned long sleep_save[SLEEP_SAVE_SIZE];
local_irq_disable();
leds_event(led_stop);
/* preserve current time */
RCNR = xtime.tv_sec;
......@@ -88,8 +70,6 @@ int pm_do_suspend(void)
SAVE(OIER);
SAVE(GPDR);
SAVE(GRER);
SAVE(GFER);
SAVE(GAFR);
SAVE(PPDR);
......@@ -99,13 +79,6 @@ int pm_do_suspend(void)
SAVE(Ser1SDCR0);
SAVE(ICMR);
/* ... maybe a global variable initialized by arch code to set this? */
GRER = PWER;
GFER = 0;
GEDR = GEDR;
/* Clear previous reset status */
RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
......@@ -115,22 +88,23 @@ int pm_do_suspend(void)
/* go zzz */
sa1100_cpu_suspend();
/* ensure not to come back here if it wasn't intended */
/*
* Ensure not to come back here if it wasn't intended
*/
PSPR = 0;
#ifdef DEBUG
printk(KERN_DEBUG "*** made it back from resume\n");
#endif
/*
* Ensure interrupt sources are disabled; we will re-init
* the interrupt subsystem via the device manager.
*/
ICLR = 0;
ICCR = 1;
ICMR = 0;
/* restore registers */
RESTORE(GPDR);
RESTORE(GRER);
RESTORE(GFER);
RESTORE(GAFR);
/* clear any edge detect bit */
GEDR = GEDR;
RESTORE(PPDR);
RESTORE(PPSR);
RESTORE(PPAR);
......@@ -138,6 +112,9 @@ int pm_do_suspend(void)
RESTORE(Ser1SDCR0);
/*
* Clear the peripheral sleep-hold bit.
*/
PSSR = PSSR_PH;
RESTORE(OSMR0);
......@@ -147,24 +124,9 @@ int pm_do_suspend(void)
RESTORE(OSCR);
RESTORE(OIER);
ICLR = 0;
ICCR = 1;
RESTORE(ICMR);
/* restore current time */
xtime.tv_sec = RCNR;
leds_event(led_start);
local_irq_enable();
/*
* Restore the CPU frequency settings.
*/
#ifdef CONFIG_CPU_FREQ
cpufreq_restore();
#endif
return 0;
}
......@@ -172,78 +134,3 @@ unsigned long sleep_phys_sp(void *sp)
{
return virt_to_phys(sp);
}
#ifdef CONFIG_SYSCTL
/*
* ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
* linux/sysctl.h.
*
* This means our interface here won't survive long - it needs a new
* interface. Quick hack to get this working - use sysctl id 9999.
*/
#warning ACPI broke the kernel, this interface needs to be fixed up.
#define CTL_ACPI 9999
#define ACPI_S1_SLP_TYP 19
/*
* Send us to sleep.
*/
static int sysctl_pm_do_suspend(void)
{
int retval;
/*
* Suspend "legacy" devices.
*/
retval = pm_send_all(PM_SUSPEND, (void *)3);
if (retval == 0) {
/*
* Suspend LDM devices.
*/
device_suspend(4, SUSPEND_NOTIFY);
device_suspend(4, SUSPEND_SAVE_STATE);
device_suspend(4, SUSPEND_DISABLE);
retval = pm_do_suspend();
/*
* Resume LDM devices.
*/
device_resume(RESUME_RESTORE_STATE);
device_resume(RESUME_ENABLE);
/*
* Resume "legacy" devices.
*/
pm_send_all(PM_RESUME, (void *)0);
}
return retval;
}
static struct ctl_table pm_table[] =
{
{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
{0}
};
static struct ctl_table pm_dir_table[] =
{
{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
{0}
};
/*
* Initialize power interface
*/
static int __init pm_init(void)
{
register_sysctl_table(pm_dir_table, 1);
return 0;
}
fs_initcall(pm_init);
#endif
EXPORT_SYMBOL(pm_do_suspend);
......@@ -213,11 +213,17 @@ static void __init system3_init_irq(void)
static int sdram_notifier(struct notifier_block *nb, unsigned long event,
void *data)
{
struct cpufreq_policy *policy = data;
switch (event) {
case CPUFREQ_MINMAX:
cpufreq_updateminmax(data, 147500, 206000);
case CPUFREQ_ADJUST:
case CPUFREQ_INCOMPATIBLE:
cpufreq_verify_within_limits(policy, 147500, 206000);
break;
case CPUFREQ_NOTIFY:
if ((policy->min < 147500) ||
(policy->max > 206000))
panic("cpufreq failed to limit the speed\n");
break;
}
return 0;
}
......@@ -405,7 +411,7 @@ static int __init system3_init(void)
goto DONE;
}
#if defined( CONFIG_CPU_FREQ )
#ifdef CONFIG_CPU_FREQ
ret = cpufreq_register_notifier(&system3_clkchg_block);
if ( ret != 0 ) {
printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" );
......
......@@ -6,7 +6,7 @@
# To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk
#
# Last update: Mon Jan 13 22:55:16 2003
# Last update: Wed Mar 5 22:11:59 2003
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
......@@ -228,7 +228,7 @@ csb226 ARCH_CSB226 CSB226 216
arnold SA1100_ARNOLD ARNOLD 217
psiboard SA1100_PSIBOARD PSIBOARD 218
jz8028 ARCH_JZ8028 JZ8028 219
ipaq3 ARCH_IPAQ3 IPAQ3 220
h5400 ARCH_IPAQ3 IPAQ3 220
forte SA1100_FORTE FORTE 221
acam SA1100_ACAM ACAM 222
abox SA1100_ABOX ABOX 223
......@@ -259,7 +259,7 @@ stork_nest ARCH_STORK_NEST STORK_NEST 247
stork_egg ARCH_STORK_EGG STORK_EGG 248
wismo SA1100_WISMO WISMO 249
ezlinx ARCH_EZLINX EZLINX 250
at91rm9200 ARCH_AT91 AT91 251
at91 ARCH_AT91 AT91 251
orion ARCH_ORION ORION 252
neptune ARCH_NEPTUNE NEPTUNE 253
hackkit SA1100_HACKKIT HACKKIT 254
......@@ -281,3 +281,27 @@ stlc1502 ARCH_STLC1502 STLC1502 269
siren ARCH_SIREN SIREN 270
greenlake ARCH_GREENLAKE GREENLAKE 271
argus ARCH_ARGUS ARGUS 272
combadge SA1100_COMBADGE COMBADGE 273
rokepxa ARCH_ROKEPXA ROKEPXA 274
cintegrator ARCH_CINTEGRATOR CINTEGRATOR 275
guidea07 ARCH_GUIDEA07 GUIDEA07 276
tat257 ARCH_TAT257 TAT257 277
igp2425 ARCH_IGP2425 IGP2425 278
bluegrama ARCH_BLUEGRAMMA BLUEGRAMMA 279
ipod ARCH_IPOD IPOD 280
adsbitsyx ARCH_ADSBITSYX ADSBITSYX 281
trizeps2 ARCH_TRIZEPS2 TRIZEPS2 282
viper ARCH_VIPER VIPER 283
adsbitsyplus SA1100_ADSBITSYPLUS ADSBITSYPLUS 284
adsagc SA1100_ADSAGC ADSAGC 285
stp7312 ARCH_STP7312 STP7312 286
nx_phnx ARCH_PXA255 PXA255 287
wep_ep250 ARCH_WEP_EP250 WEP_EP250 288
inhandelf3 ARCH_INHANDELF3 INHANDELF3 289
adi_coyote ARCH_ADI_COYOTE ADI_COYOTE 290
iyonix ARCH_IYONIX IYONIX 291
damicam_sa1110 ARCH_DAMICAM_SA1110 DAMICAM_SA1110 292
meg03 ARCH_MEG03 MEG03 293
pxa_whitechapel ARCH_PXA_WHITECHAPEL PXA_WHITECHAPEL 294
nwsc ARCH_NWSC NWSC 295
nwlarm ARCH_NWLARM NWLARM 296
......@@ -973,23 +973,6 @@ ether1_getstats (struct net_device *dev)
return &priv->stats;
}
static int
ether1_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/*
* We'll set the MAC address on the chip when we open it.
*/
return 0;
}
/*
* Set or clear the multicast filter for this adaptor.
* num_addrs == -1 Promiscuous mode, receive all packets.
......@@ -1062,7 +1045,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
dev->hard_start_xmit = ether1_sendpacket;
dev->get_stats = ether1_getstats;
dev->set_multicast_list = ether1_setmulticastlist;
dev->set_mac_address = ether1_set_mac_address;
dev->tx_timeout = ether1_timeout;
dev->watchdog_timeo = 5 * HZ / 100;
......
......@@ -461,23 +461,6 @@ static struct net_device_stats *ether3_getstats(struct net_device *dev)
return &priv->stats;
}
static int
ether3_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/*
* We'll set the MAC address on the chip when we open it.
*/
return 0;
}
/*
* Set or clear promiscuous/multicast mode filter for this adaptor.
*
......@@ -903,7 +886,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
dev->hard_start_xmit = ether3_sendpacket;
dev->get_stats = ether3_getstats;
dev->set_multicast_list = ether3_setmulticastlist;
dev->set_mac_address = ether3_set_mac_address;
dev->tx_timeout = ether3_timeout;
dev->watchdog_timeo = 5 * HZ / 100;
......
......@@ -482,23 +482,6 @@ etherh_close(struct net_device *dev)
return 0;
}
static int
etherh_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/*
* We'll set the MAC address on the chip when we open it.
*/
return 0;
}
/*
* Initialisation
*/
......@@ -585,7 +568,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
dev->open = etherh_open;
dev->stop = etherh_close;
dev->set_mac_address = etherh_set_mac_address;
dev->set_config = etherh_set_config;
dev->irq = ec->irq;
dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
......
......@@ -47,7 +47,6 @@
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/cpufreq.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
......
......@@ -1590,11 +1590,21 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
struct cpufreq_policy *policy = data;
if (val == CPUFREQ_INCOMPATIBLE) {
switch (val) {
case CPUFREQ_ADJUST:
case CPUFREQ_INCOMPATIBLE:
printk(KERN_DEBUG "min dma period: %d ps, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
policy->max);
/* todo: fill in min/max values */
break;
case CPUFREQ_NOTIFY:
do {} while(0);
/* todo: panic if min/max values aren't fulfilled
* [can't really happen unless there's a bug in the
* CPU policy verififcation process *
*/
break;
}
return 0;
}
......
......@@ -23,7 +23,6 @@ anakin_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
void __init time_init(void)
{
timer_irq.handler = anakin_timer_interrupt;
timer_irq.flags = SA_INTERRUPT;
setup_irq(IRQ_TICK, &timer_irq);
}
......
......@@ -75,15 +75,12 @@ static unsigned long sa1100_gettimeoffset (void)
static void sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int next_match;
unsigned long flags;
do {
do_leds();
local_irq_save(flags);
do_timer(regs);
OSSR = OSSR_M0; /* Clear match on timer 0 */
next_match = (OSMR0 += LATCH);
local_irq_restore(flags);
do_set_rtc();
} while ((signed long)(next_match - OSCR) <= 0);
......
......@@ -34,6 +34,5 @@ void __init time_init(void)
xtime.tv_sec = 0;
timer_irq.handler = timer_interrupt;
timer_irq.flags = SA_INTERRUPT; /* FIXME: really? */
setup_irq(IRQ_TIMER, &timer_irq);
}
......@@ -267,6 +267,7 @@ extern struct bus_type ecard_bus_type;
struct ecard_driver {
int (*probe)(struct expansion_card *, const struct ecard_id *id);
void (*remove)(struct expansion_card *);
void (*shutdown)(struct expansion_card *);
const struct ecard_id *id_table;
unsigned int id;
struct device_driver drv;
......
......@@ -26,16 +26,10 @@
#define ide_default_io_base(i) ((ide_ioreg_t)0)
#define ide_default_irq(b) (0)
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
#define ide_check_region(from,extent) check_region((from), (extent))
#define ide_request_region(from,extent,name) request_region((from), (extent), (name))
#define ide_release_region(from,extent) release_region((from), (extent))
/*
* The following are not needed for the non-m68k ports
*/
#define ide_ack_intr(hwif) (1)
#define __ide_mm_insw(port,addr,len) readsw(port,addr,len)
#define __ide_mm_insl(port,addr,len) readsl(port,addr,len)
#define __ide_mm_outsw(port,addr,len) writesw(port,addr,len)
#define __ide_mm_outsl(port,addr,len) writesl(port,addr,len)
#endif /* __KERNEL__ */
......
......@@ -131,7 +131,10 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
/*
* Return the index of the PCI controller for device PDEV.
*/
#define pci_controller_num(PDEV) (0)
static inline int pci_controller_num(struct pci_dev *dev)
{
return 0;
}
#if defined(CONFIG_SA1111) && !defined(CONFIG_PCI)
......
......@@ -110,6 +110,7 @@ extern struct page *empty_zero_page;
#define pgd_bad(pgd) (0)
#define pgd_present(pgd) (1)
#define pgd_clear(pgdp) do { } while (0)
#define set_pgd(pgd,pgdp) do { } while (0)
#define page_pte_prot(page,prot) mk_pte(page, prot)
#define page_pte(page) mk_pte(page, __pgprot(0))
......
......@@ -34,6 +34,8 @@ typedef int __kernel_ptrdiff_t;
typedef long __kernel_time_t;
typedef long __kernel_suseconds_t;
typedef long __kernel_clock_t;
typedef int __kernel_timer_t;
typedef int __kernel_clockid_t;
typedef int __kernel_daddr_t;
typedef char * __kernel_caddr_t;
typedef unsigned short __kernel_uid16_t;
......
/*
* linux/include/asm-arm/proc-armv/tlbflush.h
*
* Copyright (C) 1999-2002 Russell King
* Copyright (C) 1999-2003 Russell King
*
* 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
......@@ -38,21 +38,31 @@
#define v3_tlb_flags (TLB_V3_FULL | TLB_V3_PAGE)
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
# define v3_possible_flags v3_tlb_flags
# define v3_always_flags v3_tlb_flags
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v3
# endif
#else
# define v3_possible_flags 0
# define v3_always_flags (-1UL)
#endif
#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE)
#if defined(CONFIG_CPU_ARM720T)
# define v4_possible_flags v4_tlb_flags
# define v4_always_flags v4_tlb_flags
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4
# endif
#else
# define v4_possible_flags 0
# define v4_always_flags (-1UL)
#endif
#define v4wbi_tlb_flags (TLB_WB | \
......@@ -62,11 +72,16 @@
#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \
defined(CONFIG_CPU_XSCALE)
# define v4wbi_possible_flags v4wbi_tlb_flags
# define v4wbi_always_flags v4wbi_tlb_flags
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4wbi
# endif
#else
# define v4wbi_possible_flags 0
# define v4wbi_always_flags (-1UL)
#endif
#define v4wb_tlb_flags (TLB_WB | \
......@@ -74,11 +89,16 @@
TLB_V4_D_PAGE)
#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
# define v4wb_possible_flags v4wb_tlb_flags
# define v4wb_always_flags v4wb_tlb_flags
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4wb
# endif
#else
# define v4wb_possible_flags 0
# define v4wb_always_flags (-1UL)
#endif
#ifndef _TLB
......@@ -98,23 +118,23 @@ struct cpu_tlb_fns {
*/
#ifdef MULTI_TLB
extern struct cpu_tlb_fns cpu_tlb;
#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range
#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
#define __cpu_tlb_flags cpu_tlb.tlb_flags
#else
#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range)
#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range)
#define __cpu_tlb_flags __glue(_TLB,_tlb_flags)
extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
#endif
extern struct cpu_tlb_fns cpu_tlb;
#define __cpu_tlb_flags cpu_tlb.tlb_flags
/*
* TLB Management
* ==============
......@@ -158,11 +178,34 @@ extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
* - kaddr - Kernel virtual memory address
*/
#define tlb_flag(f) (__cpu_tlb_flags & (f))
/*
* We optimise the code below by:
* - building a set of TLB flags that might be set in __cpu_tlb_flags
* - building a set of TLB flags that will always be set in __cpu_tlb_flags
* - if we're going to need __cpu_tlb_flags, access it once and only once
*
* This allows us to build optimal assembly for the single-CPU type case,
* and as close to optimal given the compiler constrants for multi-CPU
* case. We could do better for the multi-CPU case if the compiler
* implemented the "%?" method, but this has been discontinued due to too
* many people getting it wrong.
*/
#define possible_tlb_flags (v3_possible_flags | \
v4_possible_flags | \
v4wbi_possible_flags | \
v4wb_possible_flags)
#define always_tlb_flags (v3_always_flags & \
v4_always_flags & \
v4wbi_always_flags & \
v4wb_always_flags)
#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
static inline void flush_tlb_all(void)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_WB))
asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
......@@ -180,6 +223,7 @@ static inline void flush_tlb_all(void)
static inline void flush_tlb_mm(struct mm_struct *mm)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_WB))
asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
......@@ -200,6 +244,7 @@ static inline void
flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
uaddr &= PAGE_MASK;
......@@ -223,6 +268,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
static inline void flush_tlb_kernel_page(unsigned long kaddr)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
kaddr &= PAGE_MASK;
......@@ -241,6 +287,10 @@ static inline void flush_tlb_kernel_page(unsigned long kaddr)
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
#undef tlb_flag
#undef always_tlb_flags
#undef possible_tlb_flags
/*
* Convert calls to our calling convention.
*/
......
......@@ -122,15 +122,4 @@
#include CPU_INCLUDE_NAME
#endif /* __KERNEL__ */
#if 0
* The following is to fool mkdep into generating the correct
* dependencies. Without this, it can't figure out that this
* file does indeed depend on the cpu-*.h files.
#include <asm/cpu-single.h>
#include <asm/cpu-multi26.h>
#include <asm/cpu-multi32.h>
*
#endif
#endif /* __ASM_PROCFNS_H */
......@@ -14,16 +14,6 @@ extern unsigned int system_serial_low;
extern unsigned int system_serial_high;
extern unsigned int mem_fclk_21285;
/*
* This tells us if we have an ISA bridge
* present in a PCI system.
*/
#ifdef CONFIG_PCI
extern int have_isa_bridge;
#else
#define have_isa_bridge (0)
#endif
struct pt_regs;
void die(const char *msg, struct pt_regs *regs, int err)
......@@ -75,7 +65,7 @@ extern int cpu_architecture(void);
* The `mb' is to tell GCC not to cache `current' across this call.
*/
struct thread_info;
extern struct task_struct *__switch_to(struct thread_info *, struct thread_info *);
extern struct thread_info *__switch_to(struct thread_info *, struct thread_info *);
#define switch_to(prev,next,last) \
do { \
......
......@@ -354,6 +354,13 @@ static int cpufreq_add_dev (struct device * dev)
&cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy));
/* 2.4-API init for this CPU */
#ifdef CONFIG_CPU_FREQ_24_API
cpu_min_freq[cpu] = cpufreq_driver->policy[cpu].cpuinfo.min_freq;
cpu_max_freq[cpu] = cpufreq_driver->policy[cpu].cpuinfo.max_freq;
cpu_cur_freq[cpu] = cpufreq_driver->cpu_cur_freq[cpu];
#endif
if (cpufreq_driver->target)
cpufreq_governor(cpu, CPUFREQ_GOV_START);
......
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