X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fmips%2Fvr41xx%2Fcommon%2Ficu.c;h=c075261976c58df81ec4f4f1106b1c5bfe1c0739;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=70ff78190e9fb643aad3a981f897a0cf0dae8383;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index 70ff78190..c07526197 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -1,34 +1,23 @@ /* - * FILE NAME - * arch/mips/vr41xx/common/icu.c + * icu.c, Interrupt Control Unit routines for the NEC VR4100 series. * - * BRIEF MODULE DESCRIPTION - * Interrupt Control Unit routines for the NEC VR4100 series. + * Copyright (C) 2001-2002 MontaVista Software Inc. + * Author: Yoichi Yuasa + * Copyright (C) 2003-2005 Yoichi Yuasa * - * Author: Yoichi Yuasa - * yyuasa@mvista.com or source@mvista.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * Copyright 2001,2002 MontaVista Software Inc. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Changes: @@ -36,50 +25,51 @@ * - New creation, NEC VR4122 and VR4131 are supported. * - Added support for NEC VR4111 and VR4121. * - * Yoichi Yuasa + * Yoichi Yuasa * - Coped with INTASSIGN of NEC VR4133. */ #include #include -#include +#include #include +#include #include #include #include #include -#include -#include +#include #include -extern asmlinkage void vr41xx_handle_interrupt(void); - -extern void vr41xx_giuint_init(void); -extern void vr41xx_enable_giuint(int pin); -extern void vr41xx_disable_giuint(int pin); -extern void vr41xx_clear_giuint(int pin); -extern unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs); - -static uint32_t icu1_base; -static uint32_t icu2_base; +static void __iomem *icu1_base; +static void __iomem *icu2_base; static unsigned char sysint1_assign[16] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char sysint2_assign[16] = { - 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -#define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080) -#define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200) +#define ICU1_TYPE1_BASE 0x0b000080UL +#define ICU2_TYPE1_BASE 0x0b000200UL -#define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080) -#define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0) +#define ICU1_TYPE2_BASE 0x0f000080UL +#define ICU2_TYPE2_BASE 0x0f0000a0UL + +#define ICU1_SIZE 0x20 +#define ICU2_SIZE 0x1c #define SYSINT1REG 0x00 +#define PIUINTREG 0x02 #define INTASSIGN0 0x04 #define INTASSIGN1 0x06 #define GIUINTLREG 0x08 +#define DSIUINTREG 0x0a #define MSYSINT1REG 0x0c +#define MPIUINTREG 0x0e +#define MAIUINTREG 0x10 +#define MKIUINTREG 0x12 #define MGIUINTLREG 0x14 +#define MDSIUINTREG 0x16 #define NMIREG 0x18 #define SOFTREG 0x1a #define INTASSIGN2 0x1c @@ -87,266 +77,385 @@ static unsigned char sysint2_assign[16] = { #define SYSINT2REG 0x00 #define GIUINTHREG 0x02 +#define FIRINTREG 0x04 #define MSYSINT2REG 0x06 #define MGIUINTHREG 0x08 +#define MFIRINTREG 0x0a +#define PCIINTREG 0x0c + #define PCIINT0 0x0001 +#define SCUINTREG 0x0e + #define SCUINT0 0x0001 +#define CSIINTREG 0x10 +#define MPCIINTREG 0x12 +#define MSCUINTREG 0x14 +#define MCSIINTREG 0x16 +#define BCUINTREG 0x18 + #define BCUINTR 0x0001 +#define MBCUINTREG 0x1a #define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */ #define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */ -#define read_icu1(offset) readw(icu1_base + (offset)) -#define write_icu1(val, offset) writew((val), icu1_base + (offset)) +#define INT_TO_IRQ(x) ((x) + 2) /* Int0-4 -> IRQ2-6 */ + +#define icu1_read(offset) readw(icu1_base + (offset)) +#define icu1_write(offset, value) writew((value), icu1_base + (offset)) -#define read_icu2(offset) readw(icu2_base + (offset)) -#define write_icu2(val, offset) writew((val), icu2_base + (offset)) +#define icu2_read(offset) readw(icu2_base + (offset)) +#define icu2_write(offset, value) writew((value), icu2_base + (offset)) #define INTASSIGN_MAX 4 #define INTASSIGN_MASK 0x0007 -static inline uint16_t set_icu1(uint8_t offset, uint16_t set) +static inline uint16_t icu1_set(uint8_t offset, uint16_t set) { - uint16_t res; + uint16_t data; - res = read_icu1(offset); - res |= set; - write_icu1(res, offset); + data = icu1_read(offset); + data |= set; + icu1_write(offset, data); - return res; + return data; } -static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear) +static inline uint16_t icu1_clear(uint8_t offset, uint16_t clear) { - uint16_t res; + uint16_t data; - res = read_icu1(offset); - res &= ~clear; - write_icu1(res, offset); + data = icu1_read(offset); + data &= ~clear; + icu1_write(offset, data); - return res; + return data; } -static inline uint16_t set_icu2(uint8_t offset, uint16_t set) +static inline uint16_t icu2_set(uint8_t offset, uint16_t set) { - uint16_t res; + uint16_t data; - res = read_icu2(offset); - res |= set; - write_icu2(res, offset); + data = icu2_read(offset); + data |= set; + icu2_write(offset, data); - return res; + return data; } -static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear) +static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear) { - uint16_t res; + uint16_t data; - res = read_icu2(offset); - res &= ~clear; - write_icu2(res, offset); + data = icu2_read(offset); + data &= ~clear; + icu2_write(offset, data); - return res; + return data; } -/*=======================================================================*/ - -static void enable_sysint1_irq(unsigned int irq) +void vr41xx_enable_piuint(uint16_t mask) { - set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + PIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + icu1_set(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static void disable_sysint1_irq(unsigned int irq) +EXPORT_SYMBOL(vr41xx_enable_piuint); + +void vr41xx_disable_piuint(uint16_t mask) { - clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + PIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + icu1_clear(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static unsigned int startup_sysint1_irq(unsigned int irq) -{ - set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); +EXPORT_SYMBOL(vr41xx_disable_piuint); - return 0; /* never anything pending */ +void vr41xx_enable_aiuint(uint16_t mask) +{ + struct irq_desc *desc = irq_desc + AIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + icu1_set(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } -#define shutdown_sysint1_irq disable_sysint1_irq -#define ack_sysint1_irq disable_sysint1_irq +EXPORT_SYMBOL(vr41xx_enable_aiuint); -static void end_sysint1_irq(unsigned int irq) +void vr41xx_disable_aiuint(uint16_t mask) { - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + AIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + icu1_clear(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static struct hw_interrupt_type sysint1_irq_type = { - .typename = "SYSINT1", - .startup = startup_sysint1_irq, - .shutdown = shutdown_sysint1_irq, - .enable = enable_sysint1_irq, - .disable = disable_sysint1_irq, - .ack = ack_sysint1_irq, - .end = end_sysint1_irq, -}; - -/*=======================================================================*/ +EXPORT_SYMBOL(vr41xx_disable_aiuint); -static void enable_sysint2_irq(unsigned int irq) +void vr41xx_enable_kiuint(uint16_t mask) { - set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + KIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + icu1_set(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static void disable_sysint2_irq(unsigned int irq) +EXPORT_SYMBOL(vr41xx_enable_kiuint); + +void vr41xx_disable_kiuint(uint16_t mask) { - clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + KIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + icu1_clear(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static unsigned int startup_sysint2_irq(unsigned int irq) +EXPORT_SYMBOL(vr41xx_disable_kiuint); + +void vr41xx_enable_dsiuint(uint16_t mask) { - set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + DSIU_IRQ; + unsigned long flags; - return 0; /* never anything pending */ + spin_lock_irqsave(&desc->lock, flags); + icu1_set(MDSIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); } -#define shutdown_sysint2_irq disable_sysint2_irq -#define ack_sysint2_irq disable_sysint2_irq +EXPORT_SYMBOL(vr41xx_enable_dsiuint); -static void end_sysint2_irq(unsigned int irq) +void vr41xx_disable_dsiuint(uint16_t mask) { - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); -} + struct irq_desc *desc = irq_desc + DSIU_IRQ; + unsigned long flags; -static struct hw_interrupt_type sysint2_irq_type = { - .typename = "SYSINT2", - .startup = startup_sysint2_irq, - .shutdown = shutdown_sysint2_irq, - .enable = enable_sysint2_irq, - .disable = disable_sysint2_irq, - .ack = ack_sysint2_irq, - .end = end_sysint2_irq, -}; + spin_lock_irqsave(&desc->lock, flags); + icu1_clear(MDSIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} -/*=======================================================================*/ +EXPORT_SYMBOL(vr41xx_disable_dsiuint); -static void enable_giuint_irq(unsigned int irq) +void vr41xx_enable_firint(uint16_t mask) { - int pin; - - pin = GIU_IRQ_TO_PIN(irq); - if (pin < 16) - set_icu1(MGIUINTLREG, (uint16_t)1 << pin); - else - set_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16)); - vr41xx_enable_giuint(pin); + struct irq_desc *desc = irq_desc + FIR_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + icu2_set(MFIRINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); } -static void disable_giuint_irq(unsigned int irq) +EXPORT_SYMBOL(vr41xx_enable_firint); + +void vr41xx_disable_firint(uint16_t mask) { - int pin; - - pin = GIU_IRQ_TO_PIN(irq); - vr41xx_disable_giuint(pin); - if (pin < 16) - clear_icu1(MGIUINTLREG, (uint16_t)1 << pin); - else - clear_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16)); + struct irq_desc *desc = irq_desc + FIR_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + icu2_clear(MFIRINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); } -static unsigned int startup_giuint_irq(unsigned int irq) +EXPORT_SYMBOL(vr41xx_disable_firint); + +void vr41xx_enable_pciint(void) { - vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + PCI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_write(MPCIINTREG, PCIINT0); + spin_unlock_irqrestore(&desc->lock, flags); + } +} - enable_giuint_irq(irq); +EXPORT_SYMBOL(vr41xx_enable_pciint); - return 0; /* never anything pending */ +void vr41xx_disable_pciint(void) +{ + struct irq_desc *desc = irq_desc + PCI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_write(MPCIINTREG, 0); + spin_unlock_irqrestore(&desc->lock, flags); + } } -#define shutdown_giuint_irq disable_giuint_irq +EXPORT_SYMBOL(vr41xx_disable_pciint); -static void ack_giuint_irq(unsigned int irq) +void vr41xx_enable_scuint(void) { - disable_giuint_irq(irq); - - vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq)); + struct irq_desc *desc = irq_desc + SCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_write(MSCUINTREG, SCUINT0); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static void end_giuint_irq(unsigned int irq) +EXPORT_SYMBOL(vr41xx_enable_scuint); + +void vr41xx_disable_scuint(void) { - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - enable_giuint_irq(irq); + struct irq_desc *desc = irq_desc + SCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_write(MSCUINTREG, 0); + spin_unlock_irqrestore(&desc->lock, flags); + } } -static struct hw_interrupt_type giuint_irq_type = { - .typename = "GIUINT", - .startup = startup_giuint_irq, - .shutdown = shutdown_giuint_irq, - .enable = enable_giuint_irq, - .disable = disable_giuint_irq, - .ack = ack_giuint_irq, - .end = end_giuint_irq, -}; +EXPORT_SYMBOL(vr41xx_disable_scuint); -/*=======================================================================*/ +void vr41xx_enable_csiint(uint16_t mask) +{ + struct irq_desc *desc = irq_desc + CSI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_set(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} -static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL}; +EXPORT_SYMBOL(vr41xx_enable_csiint); -static void __init vr41xx_icu_init(void) +void vr41xx_disable_csiint(uint16_t mask) { - int i; - - switch (current_cpu_data.cputype) { - case CPU_VR4111: - case CPU_VR4121: - icu1_base = SYSINT1REG_TYPE1; - icu2_base = SYSINT2REG_TYPE1; - break; - case CPU_VR4122: - case CPU_VR4131: - case CPU_VR4133: - icu1_base = SYSINT1REG_TYPE2; - icu2_base = SYSINT2REG_TYPE2; - break; - default: - panic("Unexpected CPU of NEC VR4100 series"); - break; + struct irq_desc *desc = irq_desc + CSI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_clear(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); } +} + +EXPORT_SYMBOL(vr41xx_disable_csiint); - write_icu1(0, MSYSINT1REG); - write_icu1(0, MGIUINTLREG); +void vr41xx_enable_bcuint(void) +{ + struct irq_desc *desc = irq_desc + BCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_write(MBCUINTREG, BCUINTR); + spin_unlock_irqrestore(&desc->lock, flags); + } +} - write_icu2(0, MSYSINT2REG); - write_icu2(0, MGIUINTHREG); +EXPORT_SYMBOL(vr41xx_enable_bcuint); - for (i = SYSINT1_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { - if (i >= SYSINT1_IRQ_BASE && i <= SYSINT1_IRQ_LAST) - irq_desc[i].handler = &sysint1_irq_type; - else if (i >= SYSINT2_IRQ_BASE && i <= SYSINT2_IRQ_LAST) - irq_desc[i].handler = &sysint2_irq_type; - else if (i >= GIU_IRQ_BASE && i <= GIU_IRQ_LAST) - irq_desc[i].handler = &giuint_irq_type; +void vr41xx_disable_bcuint(void) +{ + struct irq_desc *desc = irq_desc + BCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + icu2_write(MBCUINTREG, 0); + spin_unlock_irqrestore(&desc->lock, flags); } +} - setup_irq(INT0_CASCADE_IRQ, &icu_cascade); - setup_irq(INT1_CASCADE_IRQ, &icu_cascade); - setup_irq(INT2_CASCADE_IRQ, &icu_cascade); - setup_irq(INT3_CASCADE_IRQ, &icu_cascade); - setup_irq(INT4_CASCADE_IRQ, &icu_cascade); +EXPORT_SYMBOL(vr41xx_disable_bcuint); + +static void disable_sysint1_irq(unsigned int irq) +{ + icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq)); } -void __init init_IRQ(void) +static void enable_sysint1_irq(unsigned int irq) { - memset(irq_desc, 0, sizeof(irq_desc)); + icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq)); +} - init_generic_irq(); - mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); - vr41xx_icu_init(); +static struct irq_chip sysint1_irq_type = { + .typename = "SYSINT1", + .ack = disable_sysint1_irq, + .mask = disable_sysint1_irq, + .mask_ack = disable_sysint1_irq, + .unmask = enable_sysint1_irq, +}; - vr41xx_giuint_init(); +static void disable_sysint2_irq(unsigned int irq) +{ + icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq)); +} - set_except_vector(0, vr41xx_handle_interrupt); +static void enable_sysint2_irq(unsigned int irq) +{ + icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq)); } -/*=======================================================================*/ +static struct irq_chip sysint2_irq_type = { + .typename = "SYSINT2", + .ack = disable_sysint2_irq, + .mask = disable_sysint2_irq, + .mask_ack = disable_sysint2_irq, + .unmask = enable_sysint2_irq, +}; static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) { - irq_desc_t *desc = irq_desc + irq; + struct irq_desc *desc = irq_desc + irq; uint16_t intassign0, intassign1; unsigned int pin; @@ -354,8 +463,8 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) spin_lock_irq(&desc->lock); - intassign0 = read_icu1(INTASSIGN0); - intassign1 = read_icu1(INTASSIGN1); + intassign0 = icu1_read(INTASSIGN0); + intassign1 = icu1_read(INTASSIGN1); switch (pin) { case 0: @@ -395,8 +504,8 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) } sysint1_assign[pin] = assign; - write_icu1(intassign0, INTASSIGN0); - write_icu1(intassign1, INTASSIGN1); + icu1_write(INTASSIGN0, intassign0); + icu1_write(INTASSIGN1, intassign1); spin_unlock_irq(&desc->lock); @@ -405,7 +514,7 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) { - irq_desc_t *desc = irq_desc + irq; + struct irq_desc *desc = irq_desc + irq; uint16_t intassign2, intassign3; unsigned int pin; @@ -413,8 +522,8 @@ static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) spin_lock_irq(&desc->lock); - intassign2 = read_icu1(INTASSIGN2); - intassign3 = read_icu1(INTASSIGN3); + intassign2 = icu1_read(INTASSIGN2); + intassign3 = icu1_read(INTASSIGN3); switch (pin) { case 0: @@ -462,8 +571,8 @@ static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) } sysint2_assign[pin] = assign; - write_icu1(intassign2, INTASSIGN2); - write_icu1(intassign3, INTASSIGN3); + icu1_write(INTASSIGN2, intassign2); + icu1_write(INTASSIGN3, intassign3); spin_unlock_irq(&desc->lock); @@ -488,78 +597,110 @@ int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) return retval; } -/*=======================================================================*/ +EXPORT_SYMBOL(vr41xx_set_intassign); -static inline void giuint_irq_dispatch(uint16_t pendl, uint16_t pendh, - struct pt_regs *regs) +static int icu_get_irq(unsigned int irq) { + uint16_t pend1, pend2; + uint16_t mask1, mask2; int i; - if (pendl) { + pend1 = icu1_read(SYSINT1REG); + mask1 = icu1_read(MSYSINT1REG); + + pend2 = icu2_read(SYSINT2REG); + mask2 = icu2_read(MSYSINT2REG); + + mask1 &= pend1; + mask2 &= pend2; + + if (mask1) { for (i = 0; i < 16; i++) { - if (pendl & ((uint16_t)1 << i)) { - giuint_do_IRQ(i, regs); - return; - } + if (irq == INT_TO_IRQ(sysint1_assign[i]) && (mask1 & (1 << i))) + return SYSINT1_IRQ(i); } - } else { + } + + if (mask2) { for (i = 0; i < 16; i++) { - if (pendh & ((uint16_t)1 << i)) { - giuint_do_IRQ(i + 16, regs); - return; - } + if (irq == INT_TO_IRQ(sysint2_assign[i]) && (mask2 & (1 << i))) + return SYSINT2_IRQ(i); } } + + printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); + + atomic_inc(&irq_err_count); + + return -1; } -asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs) +static int __init vr41xx_icu_init(void) { - uint16_t pend1, pend2, pendl, pendh; - uint16_t mask1, mask2, maskl, maskh; + unsigned long icu1_start, icu2_start; int i; - pend1 = read_icu1(SYSINT1REG); - mask1 = read_icu1(MSYSINT1REG); - - pend2 = read_icu2(SYSINT2REG); - mask2 = read_icu2(MSYSINT2REG); - - pendl = read_icu1(GIUINTLREG); - maskl = read_icu1(MGIUINTLREG); + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + icu1_start = ICU1_TYPE1_BASE; + icu2_start = ICU2_TYPE1_BASE; + break; + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + icu1_start = ICU1_TYPE2_BASE; + icu2_start = ICU2_TYPE2_BASE; + break; + default: + printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n"); + return -ENODEV; + } - pendh = read_icu2(GIUINTHREG); - maskh = read_icu2(MGIUINTHREG); + if (request_mem_region(icu1_start, ICU1_SIZE, "ICU") == NULL) + return -EBUSY; - mask1 &= pend1; - mask2 &= pend2; - maskl &= pendl; - maskh &= pendh; + if (request_mem_region(icu2_start, ICU2_SIZE, "ICU") == NULL) { + release_mem_region(icu1_start, ICU1_SIZE); + return -EBUSY; + } - if (mask1) { - for (i = 0; i < 16; i++) { - if (intnum == sysint1_assign[i] && - (mask1 & ((uint16_t)1 << i))) { - if (i == 8 && (maskl | maskh)) { - giuint_irq_dispatch(maskl, maskh, regs); - return; - } else { - do_IRQ(SYSINT1_IRQ(i), regs); - return; - } - } - } + icu1_base = ioremap(icu1_start, ICU1_SIZE); + if (icu1_base == NULL) { + release_mem_region(icu1_start, ICU1_SIZE); + release_mem_region(icu2_start, ICU2_SIZE); + return -ENOMEM; } - if (mask2) { - for (i = 0; i < 16; i++) { - if (intnum == sysint2_assign[i] && - (mask2 & ((uint16_t)1 << i))) { - do_IRQ(SYSINT2_IRQ(i), regs); - return; - } - } + icu2_base = ioremap(icu2_start, ICU2_SIZE); + if (icu2_base == NULL) { + iounmap(icu1_base); + release_mem_region(icu1_start, ICU1_SIZE); + release_mem_region(icu2_start, ICU2_SIZE); + return -ENOMEM; } - printk(KERN_ERR "spurious interrupt: %04x,%04x,%04x,%04x\n", pend1, pend2, pendl, pendh); - atomic_inc(&irq_err_count); + icu1_write(MSYSINT1REG, 0); + icu1_write(MGIUINTLREG, 0xffff); + + icu2_write(MSYSINT2REG, 0); + icu2_write(MGIUINTHREG, 0xffff); + + for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++) + set_irq_chip_and_handler(i, &sysint1_irq_type, + handle_level_irq); + + for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++) + set_irq_chip_and_handler(i, &sysint2_irq_type, + handle_level_irq); + + cascade_irq(INT0_IRQ, icu_get_irq); + cascade_irq(INT1_IRQ, icu_get_irq); + cascade_irq(INT2_IRQ, icu_get_irq); + cascade_irq(INT3_IRQ, icu_get_irq); + cascade_irq(INT4_IRQ, icu_get_irq); + + return 0; } + +core_initcall(vr41xx_icu_init);