[U-Boot] [PATCH 2/2] mpc83xx: Implement interrupt support for mpc83xx
Joe Hershberger
joe.hershberger at ni.com
Thu Oct 6 01:14:15 CEST 2011
Signed-off-by: Joe Hershberger <joe.hershberger at ni.com>
Cc: Joe Hershberger <joe.hershberger at gmail.com>
Cc: Kim Phillips <kim.phillips at freescale.com>
---
arch/powerpc/cpu/mpc83xx/interrupts.c | 447 ++++++++++++++++++++++++++++++--
arch/powerpc/include/asm/mpc83xx_irq.h | 72 +++++
2 files changed, 499 insertions(+), 20 deletions(-)
create mode 100644 arch/powerpc/include/asm/mpc83xx_irq.h
diff --git a/arch/powerpc/cpu/mpc83xx/interrupts.c b/arch/powerpc/cpu/mpc83xx/interrupts.c
index 446af27..5661421 100644
--- a/arch/powerpc/cpu/mpc83xx/interrupts.c
+++ b/arch/powerpc/cpu/mpc83xx/interrupts.c
@@ -26,17 +26,385 @@
#include <common.h>
#include <command.h>
#include <mpc83xx.h>
+#include <asm/io.h>
+#include <asm/mpc83xx_irq.h>
#include <asm/processor.h>
DECLARE_GLOBAL_DATA_PTR;
+/*
+ * Some ipic code copied from the linux 2.6 kernel:
+ * /arch/powerpc/sysdev/ipic.*
+ * /arch/powerpc/include/asm/ipic.h
+ */
+static struct ipic_info_t ipic_info[] = {
+ [1] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 16,
+ },
+ [2] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 17,
+ },
+ [3] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 18,
+ },
+ [4] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 19,
+ },
+ [5] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 20,
+ },
+ [6] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 21,
+ },
+ [7] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 22,
+ },
+ [8] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 23,
+ },
+ [IPIC_INT_UART1] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 24,
+ },
+ [IPIC_INT_UART2] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 25,
+ },
+ [IPIC_INT_SEC] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 26,
+ },
+ [IPIC_INT_1588_1] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 27,
+ },
+ [IPIC_INT_1588_2] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 28,
+ },
+ [IPIC_INT_I2C1] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 29,
+ },
+ [IPIC_INT_I2C2] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 30,
+ },
+ [IPIC_INT_SPI] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 31,
+ },
+ [IPIC_INT_IRQ1] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 1,
+ },
+ [IPIC_INT_IRQ2] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 2,
+ },
+ [IPIC_INT_IRQ3] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 3,
+ },
+ [IPIC_INT_IRQ4] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 4,
+ },
+ [21] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 5,
+ },
+ [22] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 6,
+ },
+ [23] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 7,
+ },
+ [IPIC_INT_TSEC1_TX] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 0,
+ },
+ [IPIC_INT_TSEC1_RX] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 1,
+ },
+ [IPIC_INT_TSEC1_ERR] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 2,
+ },
+ [IPIC_INT_TSEC2_TX] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 3,
+ },
+ [IPIC_INT_TSEC2_RX] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 4,
+ },
+ [IPIC_INT_TSEC2_ERR] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 5,
+ },
+ [IPIC_INT_USB_DR] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 6,
+ },
+ [39] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 7,
+ },
+ [40] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 8,
+ },
+ [41] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 9,
+ },
+ [42] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 10,
+ },
+ [43] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 11,
+ },
+ [44] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 12,
+ },
+ [45] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 13,
+ },
+ [46] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 14,
+ },
+ [47] = {
+ .mask = IPIC_SIMSR_H,
+ .bit = 15,
+ },
+ [IPIC_INT_IRQ0] = {
+ .ack = IPIC_SEPNR,
+ .mask = IPIC_SEMSR,
+ .bit = 0,
+ },
+ [IPIC_INT_RTC_SEC] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 0,
+ },
+ [IPIC_INT_PIT] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 1,
+ },
+ [IPIC_INT_PCI] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 2,
+ },
+ [67] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 3,
+ },
+ [IPIC_INT_RTC_ALR] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 4,
+ },
+ [IPIC_INT_MU] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 5,
+ },
+ [IPIC_INT_SBA] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 6,
+ },
+ [IPIC_INT_DMA] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 7,
+ },
+ [IPIC_INT_GTM4] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 8,
+ },
+ [IPIC_INT_GTM8] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 9,
+ },
+ [IPIC_INT_GPIO] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 10,
+ },
+ [75] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 11,
+ },
+ [IPIC_INT_DDR] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 12,
+ },
+ [IPIC_INT_LBC] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 13,
+ },
+ [IPIC_INT_GTM2] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 14,
+ },
+ [IPIC_INT_GTM6] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 15,
+ },
+ [IPIC_INT_PMC] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 16,
+ },
+ [81] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 17,
+ },
+ [82] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 18,
+ },
+ [83] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 19,
+ },
+ [IPIC_INT_GTM3] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 20,
+ },
+ [IPIC_INT_GTM7] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 21,
+ },
+ [86] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 22,
+ },
+ [87] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 23,
+ },
+ [88] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 24,
+ },
+ [89] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 25,
+ },
+ [IPIC_INT_GTM1] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 26,
+ },
+ [IPIC_INT_GTM5] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 27,
+ },
+ [92] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 28,
+ },
+ [93] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 29,
+ },
+ [94] = {
+ .mask = IPIC_SIMSR_L,
+ .bit = 30,
+ },
+};
+
+static inline u32 ipic_read(u32 reg)
+{
+ immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ return in_be32((u32 *)&immr->ipic + (reg >> 2));
+}
+
+static inline void ipic_write(u32 reg, u32 value)
+{
+ immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ out_be32((u32 *)&immr->ipic + (reg >> 2), value);
+}
+
+#define MAKE_MASK(bit) (1 << (31 - (bit)))
+
+static void ipic_unmask_irq(u32 irq)
+{
+ u32 temp;
+
+ temp = ipic_read(ipic_info[irq].mask);
+ temp |= MAKE_MASK(ipic_info[irq].bit);
+ ipic_write(ipic_info[irq].mask, temp);
+}
+
+static void ipic_mask_irq(u32 irq)
+{
+ u32 temp;
+
+ temp = ipic_read(ipic_info[irq].mask);
+ temp &= ~MAKE_MASK(ipic_info[irq].bit);
+ ipic_write(ipic_info[irq].mask, temp);
+}
+
+static void ipic_ack_irq(u32 irq)
+{
+ u32 temp;
+
+ if (ipic_info[irq].ack) {
+ temp = MAKE_MASK(ipic_info[irq].bit);
+ ipic_write(ipic_info[irq].ack, temp);
+ }
+}
+
+static void ipic_mask_irq_and_ack(u32 irq)
+{
+ ipic_mask_irq(irq);
+ ipic_ack_irq(irq);
+}
+
+u32 ipic_get_irq(void)
+{
+ int irq;
+
+ #define IPIC_SIVCR_VECTOR_MASK 0x7f
+ irq = ipic_read(IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK;
+
+ /* 0 --> no irq is pending */
+
+ return irq;
+}
+
+/*
+ * End code copied from Linux
+ */
+
struct irq_action {
interrupt_handler_t *handler;
void *arg;
ulong count;
};
-int interrupt_init_cpu (unsigned *decrementer_count)
+static struct irq_action irq_handlers[NR_IRQS];
+
+int interrupt_init_cpu(unsigned *decrementer_count)
{
volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
@@ -54,44 +422,83 @@ int interrupt_init_cpu (unsigned *decrementer_count)
* Handle external interrupts
*/
-void external_interrupt (struct pt_regs *regs)
+void external_interrupt(struct pt_regs *regs)
{
-}
+ int irq, unmask = 1;
+ irq = ipic_get_irq();
-/*
- * Install and free an interrupt handler.
- */
+ ipic_mask_irq_and_ack(irq);
-void
-irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
-{
-}
+ if (irq_handlers[irq].handler != NULL) {
+ (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
+ } else {
+ printf("\nBogus External Interrupt IRQ %d\n", irq);
+ /*
+ * turn off the bogus interrupt, otherwise it
+ * might repeat forever
+ */
+ unmask = 0;
+ }
+ enable_interrupts();
-void irq_free_handler (int irq)
-{
+ if (unmask)
+ ipic_unmask_irq(irq);
}
-void timer_interrupt_cpu (struct pt_regs *regs)
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ */
+void timer_interrupt_cpu(struct pt_regs *regs)
{
/* nothing to do here */
return;
}
-#if defined(CONFIG_CMD_IRQ)
-
-/* ripped this out of ppc4xx/interrupts.c */
-
/*
- * irqinfo - print information about PCI devices
+ * Install and free an interrupt handler.
*/
-void
-do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char * const argv[])
+void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ printf("irq_install_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler != NULL)
+ printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+ (ulong) handler, (ulong) irq_handlers[irq].handler);
+
+ irq_handlers[irq].handler = handler;
+ irq_handlers[irq].arg = arg;
+
+ ipic_unmask_irq(irq);
+}
+
+
+void irq_free_handler(int irq)
{
+ if (irq < 0 || irq >= NR_IRQS) {
+ printf("irq_free_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ ipic_mask_irq(irq);
+
+ irq_handlers[irq].handler = NULL;
+ irq_handlers[irq].arg = NULL;
}
+
+#if defined(CONFIG_CMD_IRQ)
+void do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+}
#endif
+
+
diff --git a/arch/powerpc/include/asm/mpc83xx_irq.h b/arch/powerpc/include/asm/mpc83xx_irq.h
new file mode 100644
index 0000000..28804b7
--- /dev/null
+++ b/arch/powerpc/include/asm/mpc83xx_irq.h
@@ -0,0 +1,72 @@
+#ifndef _MPC83xx_IRQ_H
+#define _MPC83xx_IRQ_H
+
+#define NR_IRQS 128
+
+/*
+ * Some ipic code copied from the linux 2.6 kernel:
+ * /arch/powerpc/sysdev/ipic.*
+ * /arch/powerpc/include/asm/ipic.h
+ */
+#define IPIC_SICFR 0x00 /* System Global Interrupt Configuration Register */
+#define IPIC_SIVCR 0x04 /* System Global Interrupt Vector Register */
+#define IPIC_SIPNR_H 0x08 /* System Internal Interrupt Pending Register (HIGH) */
+#define IPIC_SIPNR_L 0x0C /* System Internal Interrupt Pending Register (LOW) */
+#define IPIC_SIMSR_H 0x20 /* System Internal Interrupt Mask Register (HIGH) */
+#define IPIC_SIMSR_L 0x24 /* System Internal Interrupt Mask Register (LOW) */
+#define IPIC_SEPNR 0x2C /* System External Interrupt Pending Register */
+#define IPIC_SEMSR 0x38 /* System External Interrupt Mask Register */
+
+struct ipic_info_t {
+ u8 ack; /* pending register offset from base if the irq
+ supports ack operation */
+ u8 mask; /* mask register offset from base */
+ u8 bit; /* register bit position (as per doc)
+ bit mask = 1 << (31 - bit) */
+};
+
+
+/*
+ * This list is specific to the mpc8313e for now.
+ */
+#define IPIC_INT_UART1 (0x09)
+#define IPIC_INT_UART2 (0x0A)
+#define IPIC_INT_SEC (0x0B)
+#define IPIC_INT_1588_1 (0x0C)
+#define IPIC_INT_1588_2 (0x0D)
+#define IPIC_INT_I2C1 (0x0E)
+#define IPIC_INT_I2C2 (0x0F)
+#define IPIC_INT_SPI (0x10)
+#define IPIC_INT_IRQ1 (0x11)
+#define IPIC_INT_IRQ2 (0x12)
+#define IPIC_INT_IRQ3 (0x13)
+#define IPIC_INT_IRQ4 (0x14)
+#define IPIC_INT_TSEC1_TX (0x20)
+#define IPIC_INT_TSEC1_RX (0x21)
+#define IPIC_INT_TSEC1_ERR (0x22)
+#define IPIC_INT_TSEC2_TX (0x23)
+#define IPIC_INT_TSEC2_RX (0x24)
+#define IPIC_INT_TSEC2_ERR (0x25)
+#define IPIC_INT_USB_DR (0x26)
+#define IPIC_INT_IRQ0 (0x30)
+#define IPIC_INT_RTC_SEC (0x40)
+#define IPIC_INT_PIT (0x41)
+#define IPIC_INT_PCI (0x42)
+#define IPIC_INT_RTC_ALR (0x44)
+#define IPIC_INT_MU (0x45)
+#define IPIC_INT_SBA (0x46)
+#define IPIC_INT_DMA (0x47)
+#define IPIC_INT_GTM4 (0x48)
+#define IPIC_INT_GTM8 (0x49)
+#define IPIC_INT_GPIO (0x4A)
+#define IPIC_INT_DDR (0x4C)
+#define IPIC_INT_LBC (0x4D)
+#define IPIC_INT_GTM2 (0x4E)
+#define IPIC_INT_GTM6 (0x4F)
+#define IPIC_INT_PMC (0x50)
+#define IPIC_INT_GTM3 (0x54)
+#define IPIC_INT_GTM7 (0x55)
+#define IPIC_INT_GTM1 (0x5A)
+#define IPIC_INT_GTM5 (0x5B)
+
+#endif /* _MPC83xx_IRQ_H */
--
1.6.0.2
More information about the U-Boot
mailing list