patch-2.4.25 linux-2.4.25/arch/mips/vr41xx/common/icu.c
Next file: linux-2.4.25/arch/mips/vr41xx/common/int-handler.S
Previous file: linux-2.4.25/arch/mips/vr41xx/common/giu.c
Back to the patch index
Back to the overall index
- Lines: 598
- Date:
2004-02-18 05:36:30.000000000 -0800
- Orig file:
linux-2.4.24/arch/mips/vr41xx/common/icu.c
- Orig date:
2003-08-25 04:44:40.000000000 -0700
diff -urN linux-2.4.24/arch/mips/vr41xx/common/icu.c linux-2.4.25/arch/mips/vr41xx/common/icu.c
@@ -1,9 +1,9 @@
/*
* FILE NAME
- * arch/mips/vr41xx/vr4122/common/icu.c
+ * arch/mips/vr41xx/common/icu.c
*
* BRIEF MODULE DESCRIPTION
- * Interrupt Control Unit routines for the NEC VR4122 and VR4131.
+ * Interrupt Control Unit routines for the NEC VR4100 series.
*
* Author: Yoichi Yuasa
* yyuasa@mvista.com or source@mvista.com
@@ -33,13 +33,11 @@
/*
* Changes:
* MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ * - New creation, NEC VR4122 and VR4131 are supported.
* - Added support for NEC VR4111 and VR4121.
*
- * Paul Mundt <lethal@chaoticdreams.org>
- * - kgdb support.
- *
- * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
- * - New creation, NEC VR4122 and VR4131 are supported.
+ * Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ * - Coped with INTASSIGN of NEC VR4133.
*/
#include <linux/errno.h>
#include <linux/init.h>
@@ -47,51 +45,65 @@
#include <linux/irq.h>
#include <linux/types.h>
-#include <asm/addrspace.h>
#include <asm/cpu.h>
-#include <asm/gdb-stub.h>
#include <asm/io.h>
-#include <asm/mipsregs.h>
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
#include <asm/vr41xx/vr41xx.h>
extern asmlinkage void vr41xx_handle_interrupt(void);
-extern void __init init_generic_irq(void);
-extern void mips_cpu_irq_init(u32 irq_base);
-
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 u32 vr41xx_icu1_base = 0;
-static u32 vr41xx_icu2_base = 0;
+static uint32_t icu1_base;
+static uint32_t icu2_base;
-#define VR4111_SYSINT1REG KSEG1ADDR(0x0b000080)
-#define VR4111_SYSINT2REG KSEG1ADDR(0x0b000200)
+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 };
-#define VR4122_SYSINT1REG KSEG1ADDR(0x0f000080)
-#define VR4122_SYSINT2REG KSEG1ADDR(0x0f0000a0)
+#define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080)
+#define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200)
+
+#define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080)
+#define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0)
#define SYSINT1REG 0x00
+#define INTASSIGN0 0x04
+#define INTASSIGN1 0x06
#define GIUINTLREG 0x08
#define MSYSINT1REG 0x0c
#define MGIUINTLREG 0x14
#define NMIREG 0x18
#define SOFTREG 0x1a
+#define INTASSIGN2 0x1c
+#define INTASSIGN3 0x1e
#define SYSINT2REG 0x00
#define GIUINTHREG 0x02
#define MSYSINT2REG 0x06
#define MGIUINTHREG 0x08
-#define read_icu1(offset) readw(vr41xx_icu1_base + (offset))
-#define write_icu1(val, offset) writew((val), vr41xx_icu1_base + (offset))
+#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 read_icu2(offset) readw(vr41xx_icu2_base + (offset))
-#define write_icu2(val, offset) writew((val), vr41xx_icu2_base + (offset))
+#define read_icu2(offset) readw(icu2_base + (offset))
+#define write_icu2(val, offset) writew((val), icu2_base + (offset))
-static inline u16 set_icu1(u16 offset, u16 set)
+#define INTASSIGN_MAX 4
+#define INTASSIGN_MASK 0x0007
+
+static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
{
- u16 res;
+ uint16_t res;
res = read_icu1(offset);
res |= set;
@@ -100,9 +112,9 @@
return res;
}
-static inline u16 clear_icu1(u16 offset, u16 clear)
+static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
{
- u16 res;
+ uint16_t res;
res = read_icu1(offset);
res &= ~clear;
@@ -111,9 +123,9 @@
return res;
}
-static inline u16 set_icu2(u16 offset, u16 set)
+static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
{
- u16 res;
+ uint16_t res;
res = read_icu2(offset);
res |= set;
@@ -122,9 +134,9 @@
return res;
}
-static inline u16 clear_icu2(u16 offset, u16 clear)
+static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
{
- u16 res;
+ uint16_t res;
res = read_icu2(offset);
res &= ~clear;
@@ -137,17 +149,17 @@
static void enable_sysint1_irq(unsigned int irq)
{
- set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+ set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
}
static void disable_sysint1_irq(unsigned int irq)
{
- clear_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+ clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
}
static unsigned int startup_sysint1_irq(unsigned int irq)
{
- set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+ set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
return 0; /* never anything pending */
}
@@ -158,35 +170,34 @@
static void end_sysint1_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+ set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
}
static struct hw_interrupt_type sysint1_irq_type = {
- "SYSINT1",
- startup_sysint1_irq,
- shutdown_sysint1_irq,
- enable_sysint1_irq,
- disable_sysint1_irq,
- ack_sysint1_irq,
- end_sysint1_irq,
- NULL
+ .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,
};
/*=======================================================================*/
static void enable_sysint2_irq(unsigned int irq)
{
- set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+ set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
}
static void disable_sysint2_irq(unsigned int irq)
{
- clear_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+ clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
}
static unsigned int startup_sysint2_irq(unsigned int irq)
{
- set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+ set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
return 0; /* never anything pending */
}
@@ -197,18 +208,17 @@
static void end_sysint2_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+ set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
}
static struct hw_interrupt_type sysint2_irq_type = {
- "SYSINT2",
- startup_sysint2_irq,
- shutdown_sysint2_irq,
- enable_sysint2_irq,
- disable_sysint2_irq,
- ack_sysint2_irq,
- end_sysint2_irq,
- NULL
+ .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,
};
/*=======================================================================*/
@@ -217,12 +227,11 @@
{
int pin;
- pin = irq - GIU_IRQ_BASE;
+ pin = GIU_IRQ_TO_PIN(irq);
if (pin < 16)
- set_icu1(MGIUINTLREG, (u16)1 << pin);
+ set_icu1(MGIUINTLREG, (uint16_t)1 << pin);
else
- set_icu2(MGIUINTHREG, (u16)1 << (pin - 16));
-
+ set_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
vr41xx_enable_giuint(pin);
}
@@ -230,18 +239,17 @@
{
int pin;
- pin = irq - GIU_IRQ_BASE;
+ pin = GIU_IRQ_TO_PIN(irq);
vr41xx_disable_giuint(pin);
-
if (pin < 16)
- clear_icu1(MGIUINTLREG, (u16)1 << pin);
+ clear_icu1(MGIUINTLREG, (uint16_t)1 << pin);
else
- clear_icu2(MGIUINTHREG, (u16)1 << (pin - 16));
+ clear_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
}
static unsigned int startup_giuint_irq(unsigned int irq)
{
- vr41xx_clear_giuint(irq - GIU_IRQ_BASE);
+ vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
enable_giuint_irq(irq);
@@ -254,7 +262,7 @@
{
disable_giuint_irq(irq);
- vr41xx_clear_giuint(irq - GIU_IRQ_BASE);
+ vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
}
static void end_giuint_irq(unsigned int irq)
@@ -264,14 +272,13 @@
}
static struct hw_interrupt_type giuint_irq_type = {
- "GIUINT",
- startup_giuint_irq,
- shutdown_giuint_irq,
- enable_giuint_irq,
- disable_giuint_irq,
- ack_giuint_irq,
- end_giuint_irq,
- NULL
+ .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,
};
/*=======================================================================*/
@@ -285,13 +292,14 @@
switch (current_cpu_data.cputype) {
case CPU_VR4111:
case CPU_VR4121:
- vr41xx_icu1_base = VR4111_SYSINT1REG;
- vr41xx_icu2_base = VR4111_SYSINT2REG;
+ icu1_base = SYSINT1REG_TYPE1;
+ icu2_base = SYSINT2REG_TYPE1;
break;
case CPU_VR4122:
case CPU_VR4131:
- vr41xx_icu1_base = VR4122_SYSINT1REG;
- vr41xx_icu2_base = VR4122_SYSINT2REG;
+ case CPU_VR4133:
+ icu1_base = SYSINT1REG_TYPE2;
+ icu2_base = SYSINT2REG_TYPE2;
break;
default:
panic("Unexpected CPU of NEC VR4100 series");
@@ -313,7 +321,11 @@
irq_desc[i].handler = &giuint_irq_type;
}
- setup_irq(ICU_CASCADE_IRQ, &icu_cascade);
+ 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);
}
void __init init_IRQ(void)
@@ -327,31 +339,171 @@
vr41xx_giuint_init();
set_except_vector(0, vr41xx_handle_interrupt);
+}
+
+/*=======================================================================*/
+
+static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ uint16_t intassign0, intassign1;
+ unsigned int pin;
+
+ pin = SYSINT1_IRQ_TO_PIN(irq);
+
+ spin_lock_irq(&desc->lock);
-#ifdef CONFIG_KGDB
- printk("Setting debug traps - please connect the remote debugger.\n");
- set_debug_traps();
- breakpoint();
-#endif
+ intassign0 = read_icu1(INTASSIGN0);
+ intassign1 = read_icu1(INTASSIGN1);
+
+ switch (pin) {
+ case 0:
+ intassign0 &= ~INTASSIGN_MASK;
+ intassign0 |= (uint16_t)assign;
+ break;
+ case 1:
+ intassign0 &= ~(INTASSIGN_MASK << 3);
+ intassign0 |= (uint16_t)assign << 3;
+ break;
+ case 2:
+ intassign0 &= ~(INTASSIGN_MASK << 6);
+ intassign0 |= (uint16_t)assign << 6;
+ break;
+ case 3:
+ intassign0 &= ~(INTASSIGN_MASK << 9);
+ intassign0 |= (uint16_t)assign << 9;
+ break;
+ case 8:
+ intassign0 &= ~(INTASSIGN_MASK << 12);
+ intassign0 |= (uint16_t)assign << 12;
+ break;
+ case 9:
+ intassign1 &= ~INTASSIGN_MASK;
+ intassign1 |= (uint16_t)assign;
+ break;
+ case 11:
+ intassign1 &= ~(INTASSIGN_MASK << 6);
+ intassign1 |= (uint16_t)assign << 6;
+ break;
+ case 12:
+ intassign1 &= ~(INTASSIGN_MASK << 9);
+ intassign1 |= (uint16_t)assign << 9;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sysint1_assign[pin] = assign;
+ write_icu1(intassign0, INTASSIGN0);
+ write_icu1(intassign1, INTASSIGN1);
+
+ spin_unlock_irq(&desc->lock);
+
+ return 0;
+}
+
+static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ uint16_t intassign2, intassign3;
+ unsigned int pin;
+
+ pin = SYSINT2_IRQ_TO_PIN(irq);
+
+ spin_lock_irq(&desc->lock);
+
+ intassign2 = read_icu1(INTASSIGN2);
+ intassign3 = read_icu1(INTASSIGN3);
+
+ switch (pin) {
+ case 0:
+ intassign2 &= ~INTASSIGN_MASK;
+ intassign2 |= (uint16_t)assign;
+ break;
+ case 1:
+ intassign2 &= ~(INTASSIGN_MASK << 3);
+ intassign2 |= (uint16_t)assign << 3;
+ break;
+ case 3:
+ intassign2 &= ~(INTASSIGN_MASK << 6);
+ intassign2 |= (uint16_t)assign << 6;
+ break;
+ case 4:
+ intassign2 &= ~(INTASSIGN_MASK << 9);
+ intassign2 |= (uint16_t)assign << 9;
+ break;
+ case 5:
+ intassign2 &= ~(INTASSIGN_MASK << 12);
+ intassign2 |= (uint16_t)assign << 12;
+ break;
+ case 6:
+ intassign3 &= ~INTASSIGN_MASK;
+ intassign3 |= (uint16_t)assign;
+ break;
+ case 7:
+ intassign3 &= ~(INTASSIGN_MASK << 3);
+ intassign3 |= (uint16_t)assign << 3;
+ break;
+ case 8:
+ intassign3 &= ~(INTASSIGN_MASK << 6);
+ intassign3 |= (uint16_t)assign << 6;
+ break;
+ case 9:
+ intassign3 &= ~(INTASSIGN_MASK << 9);
+ intassign3 |= (uint16_t)assign << 9;
+ break;
+ case 10:
+ intassign3 &= ~(INTASSIGN_MASK << 12);
+ intassign3 |= (uint16_t)assign << 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sysint2_assign[pin] = assign;
+ write_icu1(intassign2, INTASSIGN2);
+ write_icu1(intassign3, INTASSIGN3);
+
+ spin_unlock_irq(&desc->lock);
+
+ return 0;
+}
+
+int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
+{
+ int retval = -EINVAL;
+
+ if (current_cpu_data.cputype != CPU_VR4133)
+ return -EINVAL;
+
+ if (intassign > INTASSIGN_MAX)
+ return -EINVAL;
+
+ if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST)
+ retval = set_sysint1_assign(irq, intassign);
+ else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST)
+ retval = set_sysint2_assign(irq, intassign);
+
+ return retval;
}
/*=======================================================================*/
-static inline void giuint_irqdispatch(u16 pendl, u16 pendh, struct pt_regs *regs)
+static inline void giuint_irq_dispatch(uint16_t pendl, uint16_t pendh,
+ struct pt_regs *regs)
{
int i;
if (pendl) {
for (i = 0; i < 16; i++) {
- if (pendl & (0x0001 << i)) {
+ if (pendl & ((uint16_t)1 << i)) {
giuint_do_IRQ(i, regs);
return;
}
}
- }
- else if (pendh) {
+ } else {
for (i = 0; i < 16; i++) {
- if (pendh & (0x0001 << i)) {
+ if (pendh & ((uint16_t)1 << i)) {
giuint_do_IRQ(i + 16, regs);
return;
}
@@ -359,10 +511,10 @@
}
}
-asmlinkage void icu_irqdispatch(struct pt_regs *regs)
+asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
{
- u16 pend1, pend2, pendl, pendh;
- u16 mask1, mask2, maskl, maskh;
+ uint16_t pend1, pend2, pendl, pendh;
+ uint16_t mask1, mask2, maskl, maskh;
int i;
pend1 = read_icu1(SYSINT1REG);
@@ -377,31 +529,36 @@
pendh = read_icu2(GIUINTHREG);
maskh = read_icu2(MGIUINTHREG);
- pend1 &= mask1;
- pend2 &= mask2;
- pendl &= maskl;
- pendh &= maskh;
-
- if (pend1) {
- if ((pend1 & 0x01ff) == 0x0100) {
- giuint_irqdispatch(pendl, pendh, regs);
- }
- else {
- for (i = 0; i < 16; i++) {
- if (pend1 & (0x0001 << i)) {
- do_IRQ(SYSINT1_IRQ_BASE + i, regs);
- break;
+ mask1 &= pend1;
+ mask2 &= pend2;
+ maskl &= pendl;
+ maskh &= pendh;
+
+ 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;
}
}
}
- return;
}
- else if (pend2) {
+
+ if (mask2) {
for (i = 0; i < 16; i++) {
- if (pend2 & (0x0001 << i)) {
- do_IRQ(SYSINT2_IRQ_BASE + i, regs);
- break;
+ if (intnum == sysint2_assign[i] &&
+ (mask2 & ((uint16_t)1 << i))) {
+ do_IRQ(SYSINT2_IRQ(i), regs);
+ return;
}
}
}
+
+ printk(KERN_ERR "spurious interrupt: %04x,%04x,%04x,%04x\n", pend1, pend2, pendl, pendh);
+ atomic_inc(&irq_err_count);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)