diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index a6640b998c6e06f99fca5982cb039562f15e3ccc..e86b4303994f1ec3c7ce6eceb9db2ec7a5670f50 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -26,39 +26,18 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include #include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include -#include -#include #include -#include #include #ifdef CONFIG_MIPS_PB1000 #include #endif -#undef DEBUG_IRQ -#ifdef DEBUG_IRQ -/* note: prints function name for you */ -#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif - #define EXT_INTC0_REQ0 2 /* IP 2 */ #define EXT_INTC0_REQ1 3 /* IP 3 */ #define EXT_INTC1_REQ0 4 /* IP 4 */ @@ -69,16 +48,98 @@ void (*board_init_irq)(void); static DEFINE_SPINLOCK(irq_lock); +#ifdef CONFIG_PM + +/* + * Save/restore the interrupt controller state. + * Called from the save/restore core registers as part of the + * au_sleep function in power.c.....maybe I should just pm_register() + * them instead? + */ +static unsigned int sleep_intctl_config0[2]; +static unsigned int sleep_intctl_config1[2]; +static unsigned int sleep_intctl_config2[2]; +static unsigned int sleep_intctl_src[2]; +static unsigned int sleep_intctl_assign[2]; +static unsigned int sleep_intctl_wake[2]; +static unsigned int sleep_intctl_mask[2]; + +void save_au1xxx_intctl(void) +{ + sleep_intctl_config0[0] = au_readl(IC0_CFG0RD); + sleep_intctl_config1[0] = au_readl(IC0_CFG1RD); + sleep_intctl_config2[0] = au_readl(IC0_CFG2RD); + sleep_intctl_src[0] = au_readl(IC0_SRCRD); + sleep_intctl_assign[0] = au_readl(IC0_ASSIGNRD); + sleep_intctl_wake[0] = au_readl(IC0_WAKERD); + sleep_intctl_mask[0] = au_readl(IC0_MASKRD); + + sleep_intctl_config0[1] = au_readl(IC1_CFG0RD); + sleep_intctl_config1[1] = au_readl(IC1_CFG1RD); + sleep_intctl_config2[1] = au_readl(IC1_CFG2RD); + sleep_intctl_src[1] = au_readl(IC1_SRCRD); + sleep_intctl_assign[1] = au_readl(IC1_ASSIGNRD); + sleep_intctl_wake[1] = au_readl(IC1_WAKERD); + sleep_intctl_mask[1] = au_readl(IC1_MASKRD); +} + +/* + * For most restore operations, we clear the entire register and + * then set the bits we found during the save. + */ +void restore_au1xxx_intctl(void) +{ + au_writel(0xffffffff, IC0_MASKCLR); au_sync(); + + au_writel(0xffffffff, IC0_CFG0CLR); au_sync(); + au_writel(sleep_intctl_config0[0], IC0_CFG0SET); au_sync(); + au_writel(0xffffffff, IC0_CFG1CLR); au_sync(); + au_writel(sleep_intctl_config1[0], IC0_CFG1SET); au_sync(); + au_writel(0xffffffff, IC0_CFG2CLR); au_sync(); + au_writel(sleep_intctl_config2[0], IC0_CFG2SET); au_sync(); + au_writel(0xffffffff, IC0_SRCCLR); au_sync(); + au_writel(sleep_intctl_src[0], IC0_SRCSET); au_sync(); + au_writel(0xffffffff, IC0_ASSIGNCLR); au_sync(); + au_writel(sleep_intctl_assign[0], IC0_ASSIGNSET); au_sync(); + au_writel(0xffffffff, IC0_WAKECLR); au_sync(); + au_writel(sleep_intctl_wake[0], IC0_WAKESET); au_sync(); + au_writel(0xffffffff, IC0_RISINGCLR); au_sync(); + au_writel(0xffffffff, IC0_FALLINGCLR); au_sync(); + au_writel(0x00000000, IC0_TESTBIT); au_sync(); + + au_writel(0xffffffff, IC1_MASKCLR); au_sync(); + + au_writel(0xffffffff, IC1_CFG0CLR); au_sync(); + au_writel(sleep_intctl_config0[1], IC1_CFG0SET); au_sync(); + au_writel(0xffffffff, IC1_CFG1CLR); au_sync(); + au_writel(sleep_intctl_config1[1], IC1_CFG1SET); au_sync(); + au_writel(0xffffffff, IC1_CFG2CLR); au_sync(); + au_writel(sleep_intctl_config2[1], IC1_CFG2SET); au_sync(); + au_writel(0xffffffff, IC1_SRCCLR); au_sync(); + au_writel(sleep_intctl_src[1], IC1_SRCSET); au_sync(); + au_writel(0xffffffff, IC1_ASSIGNCLR); au_sync(); + au_writel(sleep_intctl_assign[1], IC1_ASSIGNSET); au_sync(); + au_writel(0xffffffff, IC1_WAKECLR); au_sync(); + au_writel(sleep_intctl_wake[1], IC1_WAKESET); au_sync(); + au_writel(0xffffffff, IC1_RISINGCLR); au_sync(); + au_writel(0xffffffff, IC1_FALLINGCLR); au_sync(); + au_writel(0x00000000, IC1_TESTBIT); au_sync(); + + au_writel(sleep_intctl_mask[1], IC1_MASKSET); au_sync(); + + au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync(); +} +#endif /* CONFIG_PM */ + inline void local_enable_irq(unsigned int irq_nr) { if (irq_nr > AU1000_LAST_INTC0_INT) { - au_writel(1<<(irq_nr-32), IC1_MASKSET); - au_writel(1<<(irq_nr-32), IC1_WAKESET); - } - else { - au_writel(1< AU1000_LAST_INTC0_INT) { - au_writel(1<<(irq_nr-32), IC1_MASKCLR); - au_writel(1<<(irq_nr-32), IC1_WAKECLR); - } - else { - au_writel(1< AU1000_LAST_INTC0_INT) { - au_writel(1<<(irq_nr-32), IC1_RISINGCLR); - au_writel(1<<(irq_nr-32), IC1_MASKCLR); - } - else { - au_writel(1< AU1000_LAST_INTC0_INT) { - au_writel(1<<(irq_nr-32), IC1_FALLINGCLR); - au_writel(1<<(irq_nr-32), IC1_MASKCLR); - } - else { - au_writel(1< AU1000_LAST_INTC0_INT) { - au_writel(1<<(irq_nr-32), IC1_FALLINGCLR); - au_writel(1<<(irq_nr-32), IC1_RISINGCLR); - au_writel(1<<(irq_nr-32), IC1_MASKCLR); - } - else { - au_writel(1< AU1000_LAST_INTC0_INT) { switch (type) { - case INTC_INT_RISE_EDGE: /* 0:0:1 */ - au_writel(1<<(irq_nr-32), IC1_CFG2CLR); - au_writel(1<<(irq_nr-32), IC1_CFG1CLR); - au_writel(1<<(irq_nr-32), IC1_CFG0SET); - set_irq_chip(irq_nr, &rise_edge_irq_type); - break; - case INTC_INT_FALL_EDGE: /* 0:1:0 */ - au_writel(1<<(irq_nr-32), IC1_CFG2CLR); - au_writel(1<<(irq_nr-32), IC1_CFG1SET); - au_writel(1<<(irq_nr-32), IC1_CFG0CLR); - set_irq_chip(irq_nr, &fall_edge_irq_type); - break; - case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ - au_writel(1<<(irq_nr-32), IC1_CFG2CLR); - au_writel(1<<(irq_nr-32), IC1_CFG1SET); - au_writel(1<<(irq_nr-32), IC1_CFG0SET); - set_irq_chip(irq_nr, &either_edge_irq_type); - break; - case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ - au_writel(1<<(irq_nr-32), IC1_CFG2SET); - au_writel(1<<(irq_nr-32), IC1_CFG1CLR); - au_writel(1<<(irq_nr-32), IC1_CFG0SET); - set_irq_chip(irq_nr, &level_irq_type); - break; - case INTC_INT_LOW_LEVEL: /* 1:1:0 */ - au_writel(1<<(irq_nr-32), IC1_CFG2SET); - au_writel(1<<(irq_nr-32), IC1_CFG1SET); - au_writel(1<<(irq_nr-32), IC1_CFG0CLR); - set_irq_chip(irq_nr, &level_irq_type); - break; - case INTC_INT_DISABLED: /* 0:0:0 */ - au_writel(1<<(irq_nr-32), IC1_CFG0CLR); - au_writel(1<<(irq_nr-32), IC1_CFG1CLR); - au_writel(1<<(irq_nr-32), IC1_CFG2CLR); - break; - default: /* disable the interrupt */ - printk("unexpected int type %d (irq %d)\n", type, irq_nr); - au_writel(1<<(irq_nr-32), IC1_CFG0CLR); - au_writel(1<<(irq_nr-32), IC1_CFG1CLR); - au_writel(1<<(irq_nr-32), IC1_CFG2CLR); - return; + case INTC_INT_RISE_EDGE: /* 0:0:1 */ + au_writel(1 << (irq_nr - 32), IC1_CFG2CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG1CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG0SET); + set_irq_chip(irq_nr, &rise_edge_irq_type); + break; + case INTC_INT_FALL_EDGE: /* 0:1:0 */ + au_writel(1 << (irq_nr - 32), IC1_CFG2CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG1SET); + au_writel(1 << (irq_nr - 32), IC1_CFG0CLR); + set_irq_chip(irq_nr, &fall_edge_irq_type); + break; + case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ + au_writel(1 << (irq_nr - 32), IC1_CFG2CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG1SET); + au_writel(1 << (irq_nr - 32), IC1_CFG0SET); + set_irq_chip(irq_nr, &either_edge_irq_type); + break; + case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ + au_writel(1 << (irq_nr - 32), IC1_CFG2SET); + au_writel(1 << (irq_nr - 32), IC1_CFG1CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG0SET); + set_irq_chip(irq_nr, &level_irq_type); + break; + case INTC_INT_LOW_LEVEL: /* 1:1:0 */ + au_writel(1 << (irq_nr - 32), IC1_CFG2SET); + au_writel(1 << (irq_nr - 32), IC1_CFG1SET); + au_writel(1 << (irq_nr - 32), IC1_CFG0CLR); + set_irq_chip(irq_nr, &level_irq_type); + break; + case INTC_INT_DISABLED: /* 0:0:0 */ + au_writel(1 << (irq_nr - 32), IC1_CFG0CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG1CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG2CLR); + break; + default: /* disable the interrupt */ + printk(KERN_WARNING "unexpected int type %d (irq %d)\n", + type, irq_nr); + au_writel(1 << (irq_nr - 32), IC1_CFG0CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG1CLR); + au_writel(1 << (irq_nr - 32), IC1_CFG2CLR); + return; } if (int_req) /* assign to interrupt request 1 */ - au_writel(1<<(irq_nr-32), IC1_ASSIGNCLR); + au_writel(1 << (irq_nr - 32), IC1_ASSIGNCLR); else /* assign to interrupt request 0 */ - au_writel(1<<(irq_nr-32), IC1_ASSIGNSET); - au_writel(1<<(irq_nr-32), IC1_SRCSET); - au_writel(1<<(irq_nr-32), IC1_MASKCLR); - au_writel(1<<(irq_nr-32), IC1_WAKECLR); - } - else { + au_writel(1 << (irq_nr - 32), IC1_ASSIGNSET); + au_writel(1 << (irq_nr - 32), IC1_SRCSET); + au_writel(1 << (irq_nr - 32), IC1_MASKCLR); + au_writel(1 << (irq_nr - 32), IC1_WAKECLR); + } else { switch (type) { - case INTC_INT_RISE_EDGE: /* 0:0:1 */ - au_writel(1<im_irq, imp->im_type, imp->im_request); - imp++; - } - - /* Now set up the irq mapping for the board. - */ - imp = au1xxx_irq_map; - for (i=0; iim_irq, imp->im_type, imp->im_request); - imp++; - } - - set_c0_status(ALLINTS); - - /* Board specific IRQ initialization. - */ - if (board_init_irq) - (*board_init_irq)(); -} - - /* * Interrupts are nested. Even if an interrupt handler is registered * as "fast", we might get another interrupt before we return from @@ -468,26 +462,27 @@ void __init arch_init_irq(void) static void intc0_req0_irqdispatch(void) { int irq = 0; - static unsigned long intc0_req0 = 0; + static unsigned long intc0_req0; intc0_req0 |= au_readl(IC0_REQ0INT); if (!intc0_req0) return; + #ifdef AU1000_USB_DEV_REQ_INT /* * Because of the tight timing of SETUP token to reply * transactions, the USB devices-side packet complete * interrupt needs the highest priority. */ - if ((intc0_req0 & (1<im_irq, imp->im_type, imp->im_request); + imp++; + } + + /* Now set up the irq mapping for the board. + */ + imp = au1xxx_irq_map; + for (i = 0; i < au1xxx_nr_irqs; i++) { + setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); + imp++; + } + + set_c0_status(ALLINTS); + + /* Board specific IRQ initialization. + */ + if (board_init_irq) + (*board_init_irq)(); +}