Au1x PM fixes.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
7ab1261f5f
commit
3ce86ee14b
@ -83,7 +83,7 @@ inline void local_disable_irq(unsigned int irq_nr);
|
|||||||
void (*board_init_irq)(void);
|
void (*board_init_irq)(void);
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
|
extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(irq_lock);
|
static DEFINE_SPINLOCK(irq_lock);
|
||||||
@ -293,29 +293,31 @@ static struct hw_interrupt_type level_irq_type = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *))
|
void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *))
|
||||||
{
|
{
|
||||||
|
struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT];
|
||||||
|
|
||||||
static struct irqaction action;
|
static struct irqaction action;
|
||||||
|
memset(&action, 0, sizeof(struct irqaction));
|
||||||
|
|
||||||
/* This is a big problem.... since we didn't use request_irq
|
/* This is a big problem.... since we didn't use request_irq
|
||||||
when kernel/irq.c calls probe_irq_xxx this interrupt will
|
* when kernel/irq.c calls probe_irq_xxx this interrupt will
|
||||||
be probed for usage. This will end up disabling the device :(
|
* be probed for usage. This will end up disabling the device :(
|
||||||
|
* Give it a bogus "action" pointer -- this will keep it from
|
||||||
Give it a bogus "action" pointer -- this will keep it from
|
* getting auto-probed!
|
||||||
getting auto-probed!
|
*
|
||||||
|
* By setting the status to match that of request_irq() we
|
||||||
By setting the status to match that of request_irq() we
|
* can avoid it. --cgray
|
||||||
can avoid it. --cgray
|
|
||||||
*/
|
*/
|
||||||
action.dev_id = handler;
|
action.dev_id = handler;
|
||||||
action.flags = 0;
|
action.flags = SA_INTERRUPT;
|
||||||
action.mask = 0;
|
cpus_clear(action.mask);
|
||||||
action.name = "Au1xxx TOY";
|
action.name = "Au1xxx TOY";
|
||||||
action.handler = handler;
|
action.handler = handler;
|
||||||
action.next = NULL;
|
action.next = NULL;
|
||||||
|
|
||||||
irq_desc[AU1000_TOY_MATCH2_INT].action = &action;
|
desc->action = &action;
|
||||||
irq_desc[AU1000_TOY_MATCH2_INT].status
|
desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
|
||||||
&= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
|
|
||||||
|
|
||||||
local_enable_irq(AU1000_TOY_MATCH2_INT);
|
local_enable_irq(AU1000_TOY_MATCH2_INT);
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,13 @@
|
|||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
|
||||||
#include <asm/string.h>
|
#include <asm/string.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/mach-au1x00/au1000.h>
|
#include <asm/mach-au1x00/au1000.h>
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
@ -50,7 +52,7 @@
|
|||||||
# define DPRINTK(fmt, args...)
|
# define DPRINTK(fmt, args...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void calibrate_delay(void);
|
static void au1000_calibrate_delay(void);
|
||||||
|
|
||||||
extern void set_au1x00_speed(unsigned int new_freq);
|
extern void set_au1x00_speed(unsigned int new_freq);
|
||||||
extern unsigned int get_au1x00_speed(void);
|
extern unsigned int get_au1x00_speed(void);
|
||||||
@ -260,7 +262,7 @@ int au_sleep(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
|
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
|
||||||
void *buffer, size_t * len)
|
void __user *buffer, size_t * len, loff_t *ppos)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
#ifdef SLEEP_TEST_TIMEOUT
|
#ifdef SLEEP_TEST_TIMEOUT
|
||||||
@ -294,7 +296,7 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
|
static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
|
||||||
void *buffer, size_t * len)
|
void __user *buffer, size_t * len, loff_t *ppos)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
@ -313,7 +315,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
|
|||||||
|
|
||||||
|
|
||||||
static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
|
static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
|
||||||
void *buffer, size_t * len)
|
void __user *buffer, size_t * len, loff_t *ppos)
|
||||||
{
|
{
|
||||||
int retval = 0, i;
|
int retval = 0, i;
|
||||||
unsigned long val, pll;
|
unsigned long val, pll;
|
||||||
@ -408,14 +410,14 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
|
|||||||
|
|
||||||
|
|
||||||
/* We don't want _any_ interrupts other than
|
/* We don't want _any_ interrupts other than
|
||||||
* match20. Otherwise our calibrate_delay()
|
* match20. Otherwise our au1000_calibrate_delay()
|
||||||
* calculation will be off, potentially a lot.
|
* calculation will be off, potentially a lot.
|
||||||
*/
|
*/
|
||||||
intc0_mask = save_local_and_disable(0);
|
intc0_mask = save_local_and_disable(0);
|
||||||
intc1_mask = save_local_and_disable(1);
|
intc1_mask = save_local_and_disable(1);
|
||||||
local_enable_irq(AU1000_TOY_MATCH2_INT);
|
local_enable_irq(AU1000_TOY_MATCH2_INT);
|
||||||
spin_unlock_irqrestore(&pm_lock, flags);
|
spin_unlock_irqrestore(&pm_lock, flags);
|
||||||
calibrate_delay();
|
au1000_calibrate_delay();
|
||||||
restore_local_and_enable(0, intc0_mask);
|
restore_local_and_enable(0, intc0_mask);
|
||||||
restore_local_and_enable(1, intc1_mask);
|
restore_local_and_enable(1, intc1_mask);
|
||||||
return retval;
|
return retval;
|
||||||
@ -455,7 +457,7 @@ __initcall(pm_init);
|
|||||||
better than 1% */
|
better than 1% */
|
||||||
#define LPS_PREC 8
|
#define LPS_PREC 8
|
||||||
|
|
||||||
static void calibrate_delay(void)
|
static void au1000_calibrate_delay(void)
|
||||||
{
|
{
|
||||||
unsigned long ticks, loopbit;
|
unsigned long ticks, loopbit;
|
||||||
int lps_precision = LPS_PREC;
|
int lps_precision = LPS_PREC;
|
||||||
|
@ -63,8 +63,11 @@ extern int allow_au1k_wait; /* default off for CP0 Counter */
|
|||||||
static unsigned int timerhi = 0, timerlo = 0;
|
static unsigned int timerhi = 0, timerlo = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
#define MATCH20_INC 328
|
#if HZ < 100 || HZ > 1000
|
||||||
extern void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *));
|
#error "unsupported HZ value! Must be in [100,1000]"
|
||||||
|
#endif
|
||||||
|
#define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */
|
||||||
|
extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *));
|
||||||
static unsigned long last_pc0, last_match20;
|
static unsigned long last_pc0, last_match20;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -116,17 +119,16 @@ null:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
|
irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long pc0;
|
unsigned long pc0;
|
||||||
int time_elapsed;
|
int time_elapsed;
|
||||||
static int jiffie_drift = 0;
|
static int jiffie_drift = 0;
|
||||||
|
|
||||||
kstat.irqs[0][irq]++;
|
|
||||||
if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
|
if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
|
||||||
/* should never happen! */
|
/* should never happen! */
|
||||||
printk(KERN_WARNING "counter 0 w status eror\n");
|
printk(KERN_WARNING "counter 0 w status error\n");
|
||||||
return;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pc0 = au_readl(SYS_TOYREAD);
|
pc0 = au_readl(SYS_TOYREAD);
|
||||||
@ -163,6 +165,8 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
|
|||||||
update_process_times(user_mode(regs));
|
update_process_times(user_mode(regs));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When we wakeup from sleep, we have to "catch up" on all of the
|
/* When we wakeup from sleep, we have to "catch up" on all of the
|
||||||
@ -439,7 +443,7 @@ void au1xxx_timer_setup(struct irqaction *irq)
|
|||||||
au_sync();
|
au_sync();
|
||||||
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
|
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
|
||||||
|
|
||||||
/* setup match20 to interrupt once every 10ms */
|
/* setup match20 to interrupt once every HZ */
|
||||||
last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
|
last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
|
||||||
au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
|
au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
|
||||||
au_sync();
|
au_sync();
|
||||||
|
Loading…
Reference in New Issue
Block a user