summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-ixp4xx/common.c109
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/entry-macro.S41
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/irqs.h95
4 files changed, 126 insertions, 120 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 054ead960f98..eb27554aa04f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -433,6 +433,7 @@ config ARCH_IXP4XX
select CPU_XSCALE
select DMABOUNCE if PCI
select GENERIC_CLOCKEVENTS
+ select GENERIC_IRQ_MULTI_HANDLER
select GPIOLIB
select HAVE_PCI
select NEED_MACH_IO_H
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 846e033c56fa..58a1b851425e 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -31,12 +31,14 @@
#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/sched_clock.h>
+#include <linux/bitops.h>
#include <mach/udc.h>
#include <mach/hardware.h>
#include <mach/io.h>
#include <linux/uaccess.h>
#include <asm/pgtable.h>
#include <asm/page.h>
+#include <asm/exception.h>
#include <asm/irq.h>
#include <asm/system_misc.h>
#include <asm/mach/map.h>
@@ -54,6 +56,7 @@
(IXP4XX_OST_RELOAD_MASK + 1) * HZ) * \
(IXP4XX_OST_RELOAD_MASK + 1)
+static struct irq_domain *ixp4xx_irqdomain;
static void __init ixp4xx_clocksource_init(void);
static void __init ixp4xx_clockevent_init(void);
static struct clock_event_device clockevent_ixp4xx;
@@ -166,16 +169,17 @@ static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
{
- int line = irq2gpio[d->irq];
+ int line = irq2gpio[d->hwirq];
u32 int_style;
enum ixp4xx_irq_type irq_type;
volatile u32 *int_reg;
/*
* Only for GPIO IRQs
+ * all other IRQs are simply active low
*/
if (line < 0)
- return -EINVAL;
+ return 0;
switch (type){
case IRQ_TYPE_EDGE_BOTH:
@@ -203,9 +207,9 @@ static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
}
if (irq_type == IXP4XX_IRQ_EDGE)
- ixp4xx_irq_edge |= (1 << d->irq);
+ ixp4xx_irq_edge |= (1 << d->hwirq);
else
- ixp4xx_irq_edge &= ~(1 << d->irq);
+ ixp4xx_irq_edge &= ~(1 << d->hwirq);
if (line >= 8) { /* pins 8-15 */
line -= 8;
@@ -224,22 +228,22 @@ static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
*int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
/* Configure the line as an input */
- gpio_line_config(irq2gpio[d->irq], IXP4XX_GPIO_IN);
+ gpio_line_config(irq2gpio[d->hwirq], IXP4XX_GPIO_IN);
return 0;
}
static void ixp4xx_irq_mask(struct irq_data *d)
{
- if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->irq >= 32)
- *IXP4XX_ICMR2 &= ~(1 << (d->irq - 32));
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->hwirq >= 32)
+ *IXP4XX_ICMR2 &= ~(1 << (d->hwirq - 32));
else
- *IXP4XX_ICMR &= ~(1 << d->irq);
+ *IXP4XX_ICMR &= ~(1 << d->hwirq);
}
static void ixp4xx_irq_ack(struct irq_data *d)
{
- int line = (d->irq < 32) ? irq2gpio[d->irq] : -1;
+ int line = (d->hwirq < 32) ? irq2gpio[d->hwirq] : -1;
if (line >= 0)
*IXP4XX_GPIO_GPISR = (1 << line);
@@ -251,13 +255,13 @@ static void ixp4xx_irq_ack(struct irq_data *d)
*/
static void ixp4xx_irq_unmask(struct irq_data *d)
{
- if (!(ixp4xx_irq_edge & (1 << d->irq)))
+ if (!(ixp4xx_irq_edge & (1 << d->hwirq)))
ixp4xx_irq_ack(d);
- if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->irq >= 32)
- *IXP4XX_ICMR2 |= (1 << (d->irq - 32));
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->hwirq >= 32)
+ *IXP4XX_ICMR2 |= (1 << (d->hwirq - 32));
else
- *IXP4XX_ICMR |= (1 << d->irq);
+ *IXP4XX_ICMR |= (1 << d->hwirq);
}
static struct irq_chip ixp4xx_irq_chip = {
@@ -268,9 +272,50 @@ static struct irq_chip ixp4xx_irq_chip = {
.irq_set_type = ixp4xx_set_irq_type,
};
+asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
+{
+ unsigned long status;
+ int i;
+
+ status = *IXP4XX_ICIP;
+
+ for_each_set_bit(i, &status, 32)
+ handle_domain_irq(ixp4xx_irqdomain, i, regs);
+
+ /*
+ * IXP465/IXP435 has an upper IRQ status register
+ */
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x())) {
+ status = *IXP4XX_ICIP2;
+ for_each_set_bit(i, &status, 32)
+ handle_domain_irq(ixp4xx_irqdomain, i + 32, regs);
+ }
+}
+
+static int ixp4xx_irqdomain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_data(irq, &ixp4xx_irq_chip);
+ irq_set_chip_and_handler(irq, &ixp4xx_irq_chip, handle_level_irq);
+ irq_set_probe(irq);
+
+ return 0;
+}
+
+static void ixp4xx_irqdomain_unmap(struct irq_domain *d, unsigned int irq)
+{
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
+ .map = ixp4xx_irqdomain_map,
+ .unmap = ixp4xx_irqdomain_unmap,
+};
+
void __init ixp4xx_init_irq(void)
{
- int i = 0;
+ int nr_irqs;
/*
* ixp4xx does not implement the XScale PWRMODE register
@@ -290,14 +335,21 @@ void __init ixp4xx_init_irq(void)
/* Disable upper 32 interrupts */
*IXP4XX_ICMR2 = 0x00;
+
+ nr_irqs = 64;
+ } else {
+ nr_irqs = 32;
}
- /* Default to all level triggered */
- for(i = 0; i < NR_IRQS; i++) {
- irq_set_chip_and_handler(i, &ixp4xx_irq_chip,
- handle_level_irq);
- irq_clear_status_flags(i, IRQ_NOREQUEST);
+ ixp4xx_irqdomain = irq_domain_add_simple(NULL, nr_irqs, IRQ_IXP4XX_BASE,
+ &ixp4xx_irqdomain_ops,
+ NULL);
+ if (!ixp4xx_irqdomain) {
+ pr_crit("can not add primary irqdomain\n");
+ return;
}
+
+ set_handle_irq(ixp4xx_handle_irq);
}
@@ -319,13 +371,6 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct irqaction ixp4xx_timer_irq = {
- .name = "timer1",
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- .handler = ixp4xx_timer_interrupt,
- .dev_id = &clockevent_ixp4xx,
-};
-
void __init ixp4xx_timer_init(void)
{
/* Reset/disable counter */
@@ -337,9 +382,6 @@ void __init ixp4xx_timer_init(void)
/* Reset time-stamp counter */
*IXP4XX_OSTS = 0;
- /* Connect the interrupt handler and enable the interrupt */
- setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
-
ixp4xx_clocksource_init();
ixp4xx_clockevent_init();
}
@@ -574,7 +616,16 @@ static struct clock_event_device clockevent_ixp4xx = {
static void __init ixp4xx_clockevent_init(void)
{
+ int ret;
+
clockevent_ixp4xx.cpumask = cpumask_of(0);
+ clockevent_ixp4xx.irq = IRQ_IXP4XX_TIMER1;
+ ret = request_irq(IRQ_IXP4XX_TIMER1, ixp4xx_timer_interrupt,
+ IRQF_TIMER, "IXP4XX-TIMER1", &clockevent_ixp4xx);
+ if (ret) {
+ pr_crit("no timer IRQ\n");
+ return;
+ }
clockevents_config_and_register(&clockevent_ixp4xx, IXP4XX_TIMER_FREQ,
0xf, 0xfffffffe);
}
diff --git a/arch/arm/mach-ixp4xx/include/mach/entry-macro.S b/arch/arm/mach-ixp4xx/include/mach/entry-macro.S
deleted file mode 100644
index 79adf83e2c3d..000000000000
--- a/arch/arm/mach-ixp4xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for IXP4xx-based platforms
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <mach/hardware.h>
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP_OFFSET)
- ldr \irqstat, [\irqstat] @ get interrupts
- cmp \irqstat, #0
- beq 1001f @ upper IRQ?
- clz \irqnr, \irqstat
- mov \base, #31
- sub \irqnr, \base, \irqnr
- b 1002f @ lower IRQ being
- @ handled
-
-1001:
- /*
- * IXP465/IXP435 has an upper IRQ status register
- */
-#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
- ldr \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP2_OFFSET)
- ldr \irqstat, [\irqstat] @ get upper interrupts
- mov \irqnr, #63
- clz \irqstat, \irqstat
- cmp \irqstat, #32
- subne \irqnr, \irqnr, \irqstat
-#endif
-1002:
- .endm
-
-
diff --git a/arch/arm/mach-ixp4xx/include/mach/irqs.h b/arch/arm/mach-ixp4xx/include/mach/irqs.h
index 7e6d4cce7c27..dadcd4ddb0a9 100644
--- a/arch/arm/mach-ixp4xx/include/mach/irqs.h
+++ b/arch/arm/mach-ixp4xx/include/mach/irqs.h
@@ -15,60 +15,55 @@
#ifndef _ARCH_IXP4XX_IRQS_H_
#define _ARCH_IXP4XX_IRQS_H_
-#define IRQ_IXP4XX_NPEA 0
-#define IRQ_IXP4XX_NPEB 1
-#define IRQ_IXP4XX_NPEC 2
-#define IRQ_IXP4XX_QM1 3
-#define IRQ_IXP4XX_QM2 4
-#define IRQ_IXP4XX_TIMER1 5
-#define IRQ_IXP4XX_GPIO0 6
-#define IRQ_IXP4XX_GPIO1 7
-#define IRQ_IXP4XX_PCI_INT 8
-#define IRQ_IXP4XX_PCI_DMA1 9
-#define IRQ_IXP4XX_PCI_DMA2 10
-#define IRQ_IXP4XX_TIMER2 11
-#define IRQ_IXP4XX_USB 12
-#define IRQ_IXP4XX_UART2 13
-#define IRQ_IXP4XX_TIMESTAMP 14
-#define IRQ_IXP4XX_UART1 15
-#define IRQ_IXP4XX_WDOG 16
-#define IRQ_IXP4XX_AHB_PMU 17
-#define IRQ_IXP4XX_XSCALE_PMU 18
-#define IRQ_IXP4XX_GPIO2 19
-#define IRQ_IXP4XX_GPIO3 20
-#define IRQ_IXP4XX_GPIO4 21
-#define IRQ_IXP4XX_GPIO5 22
-#define IRQ_IXP4XX_GPIO6 23
-#define IRQ_IXP4XX_GPIO7 24
-#define IRQ_IXP4XX_GPIO8 25
-#define IRQ_IXP4XX_GPIO9 26
-#define IRQ_IXP4XX_GPIO10 27
-#define IRQ_IXP4XX_GPIO11 28
-#define IRQ_IXP4XX_GPIO12 29
-#define IRQ_IXP4XX_SW_INT1 30
-#define IRQ_IXP4XX_SW_INT2 31
-#define IRQ_IXP4XX_USB_HOST 32
-#define IRQ_IXP4XX_I2C 33
-#define IRQ_IXP4XX_SSP 34
-#define IRQ_IXP4XX_TSYNC 35
-#define IRQ_IXP4XX_EAU_DONE 36
-#define IRQ_IXP4XX_SHA_DONE 37
-#define IRQ_IXP4XX_SWCP_PE 58
-#define IRQ_IXP4XX_QM_PE 60
-#define IRQ_IXP4XX_MCU_ECC 61
-#define IRQ_IXP4XX_EXP_PE 62
+#define IRQ_IXP4XX_BASE 16
+
+#define IRQ_IXP4XX_NPEA (IRQ_IXP4XX_BASE + 0)
+#define IRQ_IXP4XX_NPEB (IRQ_IXP4XX_BASE + 1)
+#define IRQ_IXP4XX_NPEC (IRQ_IXP4XX_BASE + 2)
+#define IRQ_IXP4XX_QM1 (IRQ_IXP4XX_BASE + 3)
+#define IRQ_IXP4XX_QM2 (IRQ_IXP4XX_BASE + 4)
+#define IRQ_IXP4XX_TIMER1 (IRQ_IXP4XX_BASE + 5)
+#define IRQ_IXP4XX_GPIO0 (IRQ_IXP4XX_BASE + 6)
+#define IRQ_IXP4XX_GPIO1 (IRQ_IXP4XX_BASE + 7)
+#define IRQ_IXP4XX_PCI_INT (IRQ_IXP4XX_BASE + 8)
+#define IRQ_IXP4XX_PCI_DMA1 (IRQ_IXP4XX_BASE + 9)
+#define IRQ_IXP4XX_PCI_DMA2 (IRQ_IXP4XX_BASE + 10)
+#define IRQ_IXP4XX_TIMER2 (IRQ_IXP4XX_BASE + 11)
+#define IRQ_IXP4XX_USB (IRQ_IXP4XX_BASE + 12)
+#define IRQ_IXP4XX_UART2 (IRQ_IXP4XX_BASE + 13)
+#define IRQ_IXP4XX_TIMESTAMP (IRQ_IXP4XX_BASE + 14)
+#define IRQ_IXP4XX_UART1 (IRQ_IXP4XX_BASE + 15)
+#define IRQ_IXP4XX_WDOG (IRQ_IXP4XX_BASE + 16)
+#define IRQ_IXP4XX_AHB_PMU (IRQ_IXP4XX_BASE + 17)
+#define IRQ_IXP4XX_XSCALE_PMU (IRQ_IXP4XX_BASE + 18)
+#define IRQ_IXP4XX_GPIO2 (IRQ_IXP4XX_BASE + 19)
+#define IRQ_IXP4XX_GPIO3 (IRQ_IXP4XX_BASE + 20)
+#define IRQ_IXP4XX_GPIO4 (IRQ_IXP4XX_BASE + 21)
+#define IRQ_IXP4XX_GPIO5 (IRQ_IXP4XX_BASE + 22)
+#define IRQ_IXP4XX_GPIO6 (IRQ_IXP4XX_BASE + 23)
+#define IRQ_IXP4XX_GPIO7 (IRQ_IXP4XX_BASE + 24)
+#define IRQ_IXP4XX_GPIO8 (IRQ_IXP4XX_BASE + 25)
+#define IRQ_IXP4XX_GPIO9 (IRQ_IXP4XX_BASE + 26)
+#define IRQ_IXP4XX_GPIO10 (IRQ_IXP4XX_BASE + 27)
+#define IRQ_IXP4XX_GPIO11 (IRQ_IXP4XX_BASE + 28)
+#define IRQ_IXP4XX_GPIO12 (IRQ_IXP4XX_BASE + 29)
+#define IRQ_IXP4XX_SW_INT1 (IRQ_IXP4XX_BASE + 30)
+#define IRQ_IXP4XX_SW_INT2 (IRQ_IXP4XX_BASE + 31)
+#define IRQ_IXP4XX_USB_HOST (IRQ_IXP4XX_BASE + 32)
+#define IRQ_IXP4XX_I2C (IRQ_IXP4XX_BASE + 33)
+#define IRQ_IXP4XX_SSP (IRQ_IXP4XX_BASE + 34)
+#define IRQ_IXP4XX_TSYNC (IRQ_IXP4XX_BASE + 35)
+#define IRQ_IXP4XX_EAU_DONE (IRQ_IXP4XX_BASE + 36)
+#define IRQ_IXP4XX_SHA_DONE (IRQ_IXP4XX_BASE + 37)
+#define IRQ_IXP4XX_SWCP_PE (IRQ_IXP4XX_BASE + 58)
+#define IRQ_IXP4XX_QM_PE (IRQ_IXP4XX_BASE + 60)
+#define IRQ_IXP4XX_MCU_ECC (IRQ_IXP4XX_BASE + 61)
+#define IRQ_IXP4XX_EXP_PE (IRQ_IXP4XX_BASE + 62)
#define _IXP4XX_GPIO_IRQ(n) (IRQ_IXP4XX_GPIO ## n)
#define IXP4XX_GPIO_IRQ(n) _IXP4XX_GPIO_IRQ(n)
-/*
- * Only first 32 sources are valid if running on IXP42x systems
- */
-#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
-#define NR_IRQS 64
-#else
-#define NR_IRQS 32
-#endif
+#define NR_IRQS 512
#define XSCALE_PMU_IRQ (IRQ_IXP4XX_XSCALE_PMU)