aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMurali Karicheri <m-karicheri2@ti.com>2011-11-26 10:28:41 -0500
committerCyril Chemparathy <cyril@ti.com>2012-09-21 10:44:02 -0400
commita8d786db1d0a3061e92cceca07b7890eb69fa7ba (patch)
tree2e5ebc87e93997a255fe5b51c70b8690c1b5af6c
parent1519a663308ee2d9c9bbac2302e8c25cc3b88554 (diff)
downloadlinux-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/Kconfig3
-rw-r--r--arch/arm/mach-davinci/Makefile1
-rw-r--r--arch/arm/mach-davinci/include/mach/entry-macro.S46
-rw-r--r--arch/arm/mach-davinci/include/mach/tci6614.h1
-rw-r--r--arch/arm/mach-davinci/omap_aintc.c131
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);
+ }
+}