diff options
author | Murali Karicheri <m-karicheri2@ti.com> | 2011-11-26 10:28:41 -0500 |
---|---|---|
committer | Cyril Chemparathy <cyril@ti.com> | 2012-09-21 10:44:02 -0400 |
commit | a8d786db1d0a3061e92cceca07b7890eb69fa7ba (patch) | |
tree | 2e5ebc87e93997a255fe5b51c70b8690c1b5af6c | |
parent | 1519a663308ee2d9c9bbac2302e8c25cc3b88554 (diff) | |
download | linux-keystone-a8d786db1d0a3061e92cceca07b7890eb69fa7ba.tar.gz |
tci6614: add driver for omap arm interrupt controller
TCI6614 re-uses the OMAP AINTC for interfacing CP_INTC and other
interrupt lines to ARM. This adds the OMAP AINTC driver for the SOC.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
-rw-r--r-- | arch/arm/mach-davinci/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-davinci/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/include/mach/entry-macro.S | 46 | ||||
-rw-r--r-- | arch/arm/mach-davinci/include/mach/tci6614.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/omap_aintc.c | 131 |
5 files changed, 174 insertions, 8 deletions
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 9e4b613c98717..b4f9e71aae175 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -10,6 +10,9 @@ config CP_INTC config CP_INTD bool +config OMAP_AINTC + bool "OMAP AINTC support" + config ARCH_DAVINCI_DMx select CPU_ARM926T bool diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 8f9f3850e9f06..a293a531b1bbd 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += tnetv107x.o devices-tnetv107x.o obj-$(CONFIG_AINTC) += irq.o obj-$(CONFIG_CP_INTC) += cp_intc.o obj-$(CONFIG_CP_INTD) += cp_intd.o +obj-$(CONFIG_OMAP_AINTC) += omap_aintc.o # Board specific obj-$(CONFIG_MACH_DAVINCI_EVM) += board-dm644x-evm.o diff --git a/arch/arm/mach-davinci/include/mach/entry-macro.S b/arch/arm/mach-davinci/include/mach/entry-macro.S index cf5f573eb5fd7..72484e43f65c1 100644 --- a/arch/arm/mach-davinci/include/mach/entry-macro.S +++ b/arch/arm/mach-davinci/include/mach/entry-macro.S @@ -10,30 +10,60 @@ */ #include <mach/irqs.h> +#define INTCPS_SIR_IRQ_OFFSET 0x0040 +#define ACTIVEIRQ_MASK 0x7f + +#if ((defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC)) || \ + (defined(CONFIG_CP_INTC) && defined(CONFIG_OMAP_AINTC)) || \ + (defined(CONFIG_OMAP_AINTC) && defined(CONFIG_AINTC))) +# define MULTI +#endif + .macro get_irqnr_preamble, base, tmp ldr \base, =davinci_intc_base ldr \base, [\base] .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp -#if defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC) +#if defined(MULTI) ldr \tmp, =davinci_intc_type ldr \tmp, [\tmp] cmp \tmp, #DAVINCI_INTC_TYPE_CP_INTC - beq 1001f + beq 1000f + cmp \tmp, #DAVINCI_INTC_TYPE_OMAP_AINTC + beq 2000f #endif #if defined(CONFIG_AINTC) ldr \tmp, [\base, #0x14] movs \tmp, \tmp, lsr #2 sub \irqnr, \tmp, #1 - b 1002f + b 9999f #endif #if defined(CONFIG_CP_INTC) -1001: ldr \irqnr, [\base, #0x80] /* get irq number */ - mov \tmp, \irqnr, lsr #31 +1000: ldr \irqnr, [\base, #0x80] /* get irq number */ and \irqnr, \irqnr, #0xff /* irq is in bits 0-9 */ - and \tmp, \tmp, #0x1 - cmp \tmp, #0x1 + mov \tmp, \irqnr, lsr #3 + and \tmp, \tmp, #0xfc + add \tmp, \tmp, #0x280 /* get the register offset */ + ldr \irqstat, [\base, \tmp] /* get the intc status */ + cmp \irqstat, #0x0 + b 9999f +#endif +#if defined(CONFIG_OMAP_AINTC) +2000: ldr \irqnr, [\base, #0x98] /* IRQ pending reg 1 */ + cmp \irqnr, #0x0 + bne 2001f + ldr \irqnr, [\base, #0xb8] /* IRQ pending reg 2 */ + cmp \irqnr, #0x0 + bne 2001f + ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */ + cmp \irqnr, #0x0 + bne 2001f + ldr \irqnr, [\base, #0xf8] /* IRQ pending reg 4 */ + cmp \irqnr, #0x0 +2001: + ldrne \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET] + and \irqnr, \irqnr, #ACTIVEIRQ_MASK #endif -1002: +9999: .endm diff --git a/arch/arm/mach-davinci/include/mach/tci6614.h b/arch/arm/mach-davinci/include/mach/tci6614.h index 20a2f7ed4cd2d..0819692fd8da5 100644 --- a/arch/arm/mach-davinci/include/mach/tci6614.h +++ b/arch/arm/mach-davinci/include/mach/tci6614.h @@ -46,6 +46,7 @@ struct tci6614_device_info { struct davinci_spi_platform_data *spi_config; }; +extern void __init omap_aintc_init(void); extern struct platform_device tci6614_wdt_device; extern struct platform_device tci6614_serial_device; diff --git a/arch/arm/mach-davinci/omap_aintc.c b/arch/arm/mach-davinci/omap_aintc.c new file mode 100644 index 0000000000000..b97a842a35bcc --- /dev/null +++ b/arch/arm/mach-davinci/omap_aintc.c @@ -0,0 +1,131 @@ +/* + * linux/arch/arm/mach-omap2/irq.c + * + * Interrupt handler for OMAP2 boards. + * + * Copyright (C) 2005 Nokia Corporation + * Author: Paul Mundt <paul.mundt@nokia.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> + +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/common.h> + +/* selected INTC register offsets */ + +#define INTC_REVISION 0x0000 +#define INTC_SYSCONFIG 0x0010 +#define INTC_SYSSTATUS 0x0014 +#define INTC_SIR 0x0040 +#define INTC_CONTROL 0x0048 +#define INTC_PROTECTION 0x004C +#define INTC_IDLE 0x0050 +#define INTC_THRESHOLD 0x0068 +#define INTC_MIR0 0x0084 +#define INTC_MIR_CLEAR0 0x0088 +#define INTC_MIR_SET0 0x008c +#define INTC_PENDING_IRQ0 0x0098 +#define INTC_PRIORITY_IRQ0 0x0100 +/* Number of IRQ state bits in each MIR register */ +#define IRQ_BITS_PER_REG 32 + +static bool debug_aintc; +#define debug_aintc_irq(irq) (false) + +static void intc_write_reg(u32 val, u16 reg) +{ + if (debug_aintc) + printk(KERN_NOTICE "aintc: write reg = %x, value = %x\n", + reg, val); + __raw_writel(val, davinci_intc_base + reg); +} + +static u32 intc_read_reg(u16 reg) +{ + u32 val = __raw_readl(davinci_intc_base + reg); + if (debug_aintc) + printk(KERN_NOTICE "aintc: read reg = %x, value = %x\n", + reg, val); + return val; +} + +static void omap_ack_irq(struct irq_data *d) +{ + unsigned int irq = d->irq; + + if (debug_aintc || debug_aintc_irq(irq)) + printk(KERN_NOTICE "aintc: ack %d\n", irq); + intc_write_reg(0x1, INTC_CONTROL); +} + +static void omap_mask_irq(struct irq_data *d) +{ + unsigned int irq = d->irq; + int offset = irq & (~(IRQ_BITS_PER_REG - 1)); + + if (debug_aintc || debug_aintc_irq(irq)) + printk(KERN_NOTICE "aintc: mask %d\n", irq); + + irq &= (IRQ_BITS_PER_REG - 1); + + intc_write_reg(1 << irq, INTC_MIR_SET0 + offset); +} + +static void omap_unmask_irq(struct irq_data *d) +{ + unsigned int irq = d->irq; + int offset = irq & (~(IRQ_BITS_PER_REG - 1)); + + if (debug_aintc || debug_aintc_irq(irq)) + printk(KERN_NOTICE "aintc: unmask %d\n", irq); + + irq &= (IRQ_BITS_PER_REG - 1); + + intc_write_reg(1 << irq, INTC_MIR_CLEAR0 + offset); +} + +static struct irq_chip omap_irq_chip = { + .name = "OMAP-AINTC", + .irq_ack = omap_ack_irq, + .irq_mask = omap_mask_irq, + .irq_unmask = omap_unmask_irq, +}; + +void __init omap_aintc_init(void) +{ + unsigned long nr_of_irqs = davinci_soc_info.intc_irq_num; + unsigned long tmp; + int i; + + davinci_intc_type = DAVINCI_INTC_TYPE_OMAP_AINTC; + davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); + + tmp = intc_read_reg(INTC_REVISION) & 0xff; + printk(KERN_INFO "IRQ: Found an omap-aintc at 0x%p " + "(revision %ld.%ld) with %ld interrupts\n", + davinci_intc_base, tmp >> 4, tmp & 0xf, + davinci_soc_info.intc_irq_num); + + tmp = intc_read_reg(INTC_SYSCONFIG); + tmp |= 1 << 1; /* soft reset */ + intc_write_reg(tmp, INTC_SYSCONFIG); + + while (!(intc_read_reg(INTC_SYSSTATUS) & 0x1)) + /* Wait for reset to complete */; + + for (i = 0; i < nr_of_irqs; i++) { + intc_write_reg(davinci_soc_info.intc_irq_prios[i], + INTC_PRIORITY_IRQ0 + 4 * i); + irq_set_chip_and_handler(i, &omap_irq_chip, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } +} |