[U-Boot] [PATCH v2 2/2] mpc83xx: Implement interrupt support for mpc83xx

Joe Hershberger joe.hershberger at ni.com
Fri Oct 7 01:37:02 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>
---
Changes for v2:
  - Shorten some lines containing constants copied from Linux

 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..fc77134
--- /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 Reg */
+#define IPIC_SIVCR	0x04 /* System Global Interrupt Vector Register */
+#define IPIC_SIPNR_H	0x08 /* System Internal Interrupt Pending Reg (HIGH) */
+#define IPIC_SIPNR_L	0x0C /* System Internal Interrupt Pending Reg (LOW) */
+#define IPIC_SIMSR_H	0x20 /* System Internal Interrupt Mask Reg (HIGH) */
+#define IPIC_SIMSR_L	0x24 /* System Internal Interrupt Mask Reg (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