[PATCH] ST SPEAr: Adding support for shared irq layer

Viresh KUMAR viresh.kumar at st.com
Tue Apr 13 05:06:50 EDT 2010


Multiple peripherals in SPEAr share common hardware interrupt lines.
This patch adds support for a shared irq layer, which registers hardware
irqs by itself and exposes virtual irq numbers to peripherals.

Note: Previous patches of "ST SPEAr platform" inclusion in linux are required
to be applied for this patch to get applied.
(Previous ST SPEAr Platform patches are reviewed over LKML and are yet to be
applied by Russell in his tree.)

Signed-off-by: Viresh Kumar <viresh.kumar at st.com>
---
 arch/arm/mach-spear3xx/include/mach/irqs.h     |  101 +++++++++++++++-
 arch/arm/mach-spear3xx/include/mach/spear300.h |   16 +++
 arch/arm/mach-spear3xx/include/mach/spear310.h |   24 ++++
 arch/arm/mach-spear3xx/include/mach/spear320.h |   25 ++++
 arch/arm/mach-spear3xx/spear300.c              |   67 +++++++++++-
 arch/arm/mach-spear3xx/spear310.c              |  148 ++++++++++++++++++++++++
 arch/arm/mach-spear3xx/spear320.c              |  129 +++++++++++++++++++++
 arch/arm/mach-spear6xx/include/mach/irqs.h     |    1 +
 arch/arm/plat-spear/Makefile                   |    2 +
 arch/arm/plat-spear/include/plat/shirq.h       |   69 +++++++++++
 arch/arm/plat-spear/shirq.c                    |  107 +++++++++++++++++
 11 files changed, 681 insertions(+), 8 deletions(-)
 create mode 100644 arch/arm/plat-spear/include/plat/shirq.h
 create mode 100644 arch/arm/plat-spear/shirq.c

diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h
index fe980e0..7f940b8 100644
--- a/arch/arm/mach-spear3xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear3xx/include/mach/irqs.h
@@ -14,7 +14,7 @@
 #ifndef __MACH_IRQS_H
 #define __MACH_IRQS_H
 
-/* IRQ definitions */
+/* SPEAr3xx IRQ definitions */
 #define IRQ_HW_ACCEL_MOD_0			0
 #define IRQ_INTRCOMM_RAS_ARM			1
 #define IRQ_CPU_GPT1_1				2
@@ -50,16 +50,103 @@
 #define IRQ_HW_ACCEL_MOD_1			31
 #define IRQ_VIC_END				32
 
-#define SPEAR_GPIO_INT_BASE	IRQ_VIC_END
+#define VIRQ_START				IRQ_VIC_END
 
+/* SPEAr300 Virtual irq definitions */
 #ifdef CONFIG_MACH_SPEAR300
-#define SPEAR_GPIO1_INT_BASE	(SPEAR_GPIO_INT_BASE + 8)
-#define SPEAR_GPIO_INT_END	(SPEAR_GPIO1_INT_BASE + 8)
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define VIRQ_IT_PERS_S				(VIRQ_START + 0)
+#define VIRQ_IT_CHANGE_S			(VIRQ_START + 1)
+#define VIRQ_I2S				(VIRQ_START + 2)
+#define VIRQ_TDM				(VIRQ_START + 3)
+#define VIRQ_CAMERA_L				(VIRQ_START + 4)
+#define VIRQ_CAMERA_F				(VIRQ_START + 5)
+#define VIRQ_CAMERA_V				(VIRQ_START + 6)
+#define VIRQ_KEYBOARD				(VIRQ_START + 7)
+#define VIRQ_GPIO1				(VIRQ_START + 8)
+
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define IRQ_CLCD				IRQ_GEN_RAS_3
+
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define IRQ_SDIO				IRQ_INTRCOMM_RAS_ARM
+
+/* GPIO pins virtual irqs */
+#define SPEAR_GPIO_INT_BASE			(VIRQ_START + 9)
+#define SPEAR_GPIO1_INT_BASE			(SPEAR_GPIO_INT_BASE + 8)
+#define SPEAR_GPIO_INT_END			(SPEAR_GPIO1_INT_BASE + 8)
+
+/* SPEAr310 Virtual irq definitions */
+#elif defined(CONFIG_MACH_SPEAR310)
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define VIRQ_SMII0				(VIRQ_START + 0)
+#define VIRQ_SMII1				(VIRQ_START + 1)
+#define VIRQ_SMII2				(VIRQ_START + 2)
+#define VIRQ_SMII3				(VIRQ_START + 3)
+#define VIRQ_WAKEUP_SMII0			(VIRQ_START + 4)
+#define VIRQ_WAKEUP_SMII1			(VIRQ_START + 5)
+#define VIRQ_WAKEUP_SMII2			(VIRQ_START + 6)
+#define VIRQ_WAKEUP_SMII3			(VIRQ_START + 7)
+
+/* IRQs sharing IRQ_GEN_RAS_2 */
+#define VIRQ_UART1				(VIRQ_START + 8)
+#define VIRQ_UART2				(VIRQ_START + 9)
+#define VIRQ_UART3				(VIRQ_START + 10)
+#define VIRQ_UART4				(VIRQ_START + 11)
+#define VIRQ_UART5				(VIRQ_START + 12)
+
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define VIRQ_EMI				(VIRQ_START + 13)
+#define VIRQ_PLGPIO				(VIRQ_START + 14)
+
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define VIRQ_TDM_HDLC				(VIRQ_START + 15)
+#define VIRQ_RS485_0				(VIRQ_START + 16)
+#define VIRQ_RS485_1				(VIRQ_START + 17)
+
+/* GPIO pins virtual irqs */
+#define SPEAR_GPIO_INT_BASE			(VIRQ_START + 18)
+
+/* SPEAr320 Virtual irq definitions */
 #else
-#define SPEAR_GPIO_INT_END	(SPEAR_GPIO_INT_BASE + 8)
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define VIRQ_EMI				(VIRQ_START + 0)
+#define VIRQ_CLCD				(VIRQ_START + 1)
+#define VIRQ_SPP				(VIRQ_START + 2)
+
+/* IRQs sharing IRQ_GEN_RAS_2 */
+#define IRQ_SDIO				IRQ_GEN_RAS_2
+
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define VIRQ_PLGPIO				(VIRQ_START + 3)
+#define VIRQ_I2S_PLAY				(VIRQ_START + 4)
+#define VIRQ_I2S_REC				(VIRQ_START + 5)
+
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define VIRQ_CANU				(VIRQ_START + 6)
+#define VIRQ_CANL				(VIRQ_START + 7)
+#define VIRQ_UART1				(VIRQ_START + 8)
+#define VIRQ_UART2				(VIRQ_START + 9)
+#define VIRQ_SSP1				(VIRQ_START + 10)
+#define VIRQ_SSP2				(VIRQ_START + 11)
+#define VIRQ_SMII0				(VIRQ_START + 12)
+#define VIRQ_MII1_SMII1				(VIRQ_START + 13)
+#define VIRQ_WAKEUP_SMII0			(VIRQ_START + 14)
+#define VIRQ_WAKEUP_MII1_SMII1			(VIRQ_START + 15)
+#define VIRQ_I2C				(VIRQ_START + 16)
+
+/* GPIO pins virtual irqs */
+#define SPEAR_GPIO_INT_BASE			(VIRQ_START + 17)
+
+#endif
+
+/* PLGPIO Virtual IRQs */
+#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
+#define SPEAR_PLGPIO_INT_BASE			(SPEAR_GPIO_INT_BASE + 8)
+#define SPEAR_GPIO_INT_END			(SPEAR_PLGPIO_INT_BASE + 102)
 #endif
 
-#define VIRTUAL_IRQS		(SPEAR_GPIO_INT_END - IRQ_VIC_END)
-#define NR_IRQS			(IRQ_VIC_END + VIRTUAL_IRQS)
+#define VIRQ_END				SPEAR_GPIO_INT_END
+#define NR_IRQS					VIRQ_END
 
 #endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear300.h b/arch/arm/mach-spear3xx/include/mach/spear300.h
index 40c16f3..ccaa765 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear300.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear300.h
@@ -20,6 +20,22 @@
 #define SPEAR300_TELECOM_BASE		0x50000000
 #define SPEAR300_TELECOM_SIZE		0x10000000
 
+/* Interrupt registers offsets and masks */
+#define SPEAR300_TELECOM_REG_SIZE	0x00010000
+#define INT_ENB_MASK_REG		0x54
+#define INT_STS_MASK_REG		0x58
+#define IT_PERS_S_IRQ_MASK		(1 << 0)
+#define IT_CHANGE_S_IRQ_MASK		(1 << 1)
+#define I2S_IRQ_MASK			(1 << 2)
+#define TDM_IRQ_MASK			(1 << 3)
+#define CAMERA_L_IRQ_MASK		(1 << 4)
+#define CAMERA_F_IRQ_MASK		(1 << 5)
+#define CAMERA_V_IRQ_MASK		(1 << 6)
+#define KEYBOARD_IRQ_MASK		(1 << 7)
+#define GPIO1_IRQ_MASK			(1 << 8)
+
+#define SHIRQ_RAS1_MASK			0x1FF
+
 #define SPEAR300_CLCD_BASE		0x60000000
 #define SPEAR300_CLCD_SIZE		0x10000000
 
diff --git a/arch/arm/mach-spear3xx/include/mach/spear310.h b/arch/arm/mach-spear3xx/include/mach/spear310.h
index d4f58d6..b27bb8a 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear310.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear310.h
@@ -40,6 +40,30 @@
 
 #define SPEAR310_SOC_CONFIG_BASE	0xB4000000
 #define SPEAR310_SOC_CONFIG_SIZE	0x00000070
+/* Interrupt registers offsets and masks */
+#define INT_STS_MASK_REG		0x04
+#define SMII0_IRQ_MASK			(1 << 0)
+#define SMII1_IRQ_MASK			(1 << 1)
+#define SMII2_IRQ_MASK			(1 << 2)
+#define SMII3_IRQ_MASK			(1 << 3)
+#define WAKEUP_SMII0_IRQ_MASK		(1 << 4)
+#define WAKEUP_SMII1_IRQ_MASK		(1 << 5)
+#define WAKEUP_SMII2_IRQ_MASK		(1 << 6)
+#define WAKEUP_SMII3_IRQ_MASK		(1 << 7)
+#define UART1_IRQ_MASK			(1 << 8)
+#define UART2_IRQ_MASK			(1 << 9)
+#define UART3_IRQ_MASK			(1 << 10)
+#define UART4_IRQ_MASK			(1 << 11)
+#define UART5_IRQ_MASK			(1 << 12)
+#define EMI_IRQ_MASK			(1 << 13)
+#define TDM_HDLC_IRQ_MASK		(1 << 14)
+#define RS485_0_IRQ_MASK		(1 << 15)
+#define RS485_1_IRQ_MASK		(1 << 16)
+
+#define SHIRQ_RAS1_MASK			0x000FF
+#define SHIRQ_RAS2_MASK			0x01F00
+#define SHIRQ_RAS3_MASK			0x02000
+#define SHIRQ_INTRCOMM_RAS_MASK		0x1C000
 
 #endif /* __MACH_SPEAR310_H */
 
diff --git a/arch/arm/mach-spear3xx/include/mach/spear320.h b/arch/arm/mach-spear3xx/include/mach/spear320.h
index e8ad2ed..b1c3dfb 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear320.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear320.h
@@ -64,6 +64,31 @@
 
 #define SPEAR320_SOC_CONFIG_BASE	0xB4000000
 #define SPEAR320_SOC_CONFIG_SIZE	0x00000070
+/* Interrupt registers offsets and masks */
+#define INT_STS_MASK_REG		0x04
+#define INT_ENB_MASK_REG		0x08
+#define GPIO_IRQ_MASK			(1 << 0)
+#define I2S_PLAY_IRQ_MASK		(1 << 1)
+#define I2S_REC_IRQ_MASK		(1 << 2)
+#define EMI_IRQ_MASK			(1 << 7)
+#define CLCD_IRQ_MASK			(1 << 8)
+#define SPP_IRQ_MASK			(1 << 9)
+#define SDIO_IRQ_MASK			(1 << 10)
+#define CAN_U_IRQ_MASK			(1 << 11)
+#define CAN_L_IRQ_MASK			(1 << 12)
+#define UART1_IRQ_MASK			(1 << 13)
+#define UART2_IRQ_MASK			(1 << 14)
+#define SSP1_IRQ_MASK			(1 << 15)
+#define SSP2_IRQ_MASK			(1 << 16)
+#define SMII0_IRQ_MASK			(1 << 17)
+#define MII1_SMII1_IRQ_MASK		(1 << 18)
+#define WAKEUP_SMII0_IRQ_MASK		(1 << 19)
+#define WAKEUP_MII1_SMII1_IRQ_MASK	(1 << 20)
+#define I2C1_IRQ_MASK			(1 << 21)
+
+#define SHIRQ_RAS1_MASK			0x000380
+#define SHIRQ_RAS3_MASK			0x000007
+#define SHIRQ_INTRCOMM_RAS_MASK		0x3FF800
 
 #endif /* __MACH_SPEAR320_H */
 
diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c
index 66e7fcd..3560f8c 100644
--- a/arch/arm/mach-spear3xx/spear300.c
+++ b/arch/arm/mach-spear3xx/spear300.c
@@ -17,6 +17,7 @@
 #include <asm/irq.h>
 #include <mach/generic.h>
 #include <mach/spear.h>
+#include <plat/shirq.h>
 
 /* pad multiplexing support */
 /* muxing registers */
@@ -386,14 +387,78 @@ struct amba_device gpio1_device = {
 		.end = SPEAR300_GPIO_BASE + SPEAR300_GPIO_SIZE - 1,
 		.flags = IORESOURCE_MEM,
 	},
-	.irq = {IRQ_GEN_RAS_1, NO_IRQ},
+	.irq = {VIRQ_GPIO1, NO_IRQ},
+};
+
+/* spear3xx shared irq */
+struct shirq_dev_config shirq_ras1_config[] = {
+	{
+		.virq = VIRQ_IT_PERS_S,
+		.enb_mask = IT_PERS_S_IRQ_MASK,
+		.status_mask = IT_PERS_S_IRQ_MASK,
+	}, {
+		.virq = VIRQ_IT_CHANGE_S,
+		.enb_mask = IT_CHANGE_S_IRQ_MASK,
+		.status_mask = IT_CHANGE_S_IRQ_MASK,
+	}, {
+		.virq = VIRQ_I2S,
+		.enb_mask = I2S_IRQ_MASK,
+		.status_mask = I2S_IRQ_MASK,
+	}, {
+		.virq = VIRQ_TDM,
+		.enb_mask = TDM_IRQ_MASK,
+		.status_mask = TDM_IRQ_MASK,
+	}, {
+		.virq = VIRQ_CAMERA_L,
+		.enb_mask = CAMERA_L_IRQ_MASK,
+		.status_mask = CAMERA_L_IRQ_MASK,
+	}, {
+		.virq = VIRQ_CAMERA_F,
+		.enb_mask = CAMERA_F_IRQ_MASK,
+		.status_mask = CAMERA_F_IRQ_MASK,
+	}, {
+		.virq = VIRQ_CAMERA_V,
+		.enb_mask = CAMERA_V_IRQ_MASK,
+		.status_mask = CAMERA_V_IRQ_MASK,
+	}, {
+		.virq = VIRQ_KEYBOARD,
+		.enb_mask = KEYBOARD_IRQ_MASK,
+		.status_mask = KEYBOARD_IRQ_MASK,
+	}, {
+		.virq = VIRQ_GPIO1,
+		.enb_mask = GPIO1_IRQ_MASK,
+		.status_mask = GPIO1_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_ras1 = {
+	.irq = IRQ_GEN_RAS_1,
+	.dev_config = shirq_ras1_config,
+	.dev_count = ARRAY_SIZE(shirq_ras1_config),
+	.regs = {
+		.enb_reg = INT_ENB_MASK_REG,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_RAS1_MASK,
+		.clear_reg = -1,
+	},
 };
 
 /* spear300 routines */
 void __init spear300_init(void)
 {
+	int ret = 0;
+
 	/* call spear3xx family common init function */
 	spear3xx_init();
+
+	/* shared irq registeration */
+	shirq_ras1.regs.base =
+		ioremap(SPEAR300_TELECOM_BASE, SPEAR300_TELECOM_REG_SIZE);
+	if (shirq_ras1.regs.base) {
+		ret = spear_shirq_register(&shirq_ras1);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ\n");
+	}
 }
 
 void spear300_pmx_init(void)
diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c
index dd5a572..96a1ab8 100644
--- a/arch/arm/mach-spear3xx/spear310.c
+++ b/arch/arm/mach-spear3xx/spear310.c
@@ -15,6 +15,7 @@
 #include <asm/irq.h>
 #include <mach/generic.h>
 #include <mach/spear.h>
+#include <plat/shirq.h>
 
 /* pad multiplexing support */
 /* muxing registers */
@@ -140,11 +141,158 @@ struct pmx_driver pmx_driver = {
 
 /* Add spear310 specific devices here */
 
+/* spear3xx shared irq */
+struct shirq_dev_config shirq_ras1_config[] = {
+	{
+		.virq = VIRQ_SMII0,
+		.status_mask = SMII0_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SMII1,
+		.status_mask = SMII1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SMII2,
+		.status_mask = SMII2_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SMII3,
+		.status_mask = SMII3_IRQ_MASK,
+	}, {
+		.virq = VIRQ_WAKEUP_SMII0,
+		.status_mask = WAKEUP_SMII0_IRQ_MASK,
+	}, {
+		.virq = VIRQ_WAKEUP_SMII1,
+		.status_mask = WAKEUP_SMII1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_WAKEUP_SMII2,
+		.status_mask = WAKEUP_SMII2_IRQ_MASK,
+	}, {
+		.virq = VIRQ_WAKEUP_SMII3,
+		.status_mask = WAKEUP_SMII3_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_ras1 = {
+	.irq = IRQ_GEN_RAS_1,
+	.dev_config = shirq_ras1_config,
+	.dev_count = ARRAY_SIZE(shirq_ras1_config),
+	.regs = {
+		.enb_reg = -1,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_RAS1_MASK,
+		.clear_reg = -1,
+	},
+};
+
+struct shirq_dev_config shirq_ras2_config[] = {
+	{
+		.virq = VIRQ_UART1,
+		.status_mask = UART1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_UART2,
+		.status_mask = UART2_IRQ_MASK,
+	}, {
+		.virq = VIRQ_UART3,
+		.status_mask = UART3_IRQ_MASK,
+	}, {
+		.virq = VIRQ_UART4,
+		.status_mask = UART4_IRQ_MASK,
+	}, {
+		.virq = VIRQ_UART5,
+		.status_mask = UART5_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_ras2 = {
+	.irq = IRQ_GEN_RAS_2,
+	.dev_config = shirq_ras2_config,
+	.dev_count = ARRAY_SIZE(shirq_ras2_config),
+	.regs = {
+		.enb_reg = -1,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_RAS2_MASK,
+		.clear_reg = -1,
+	},
+};
+
+struct shirq_dev_config shirq_ras3_config[] = {
+	{
+		.virq = VIRQ_EMI,
+		.status_mask = EMI_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_ras3 = {
+	.irq = IRQ_GEN_RAS_3,
+	.dev_config = shirq_ras3_config,
+	.dev_count = ARRAY_SIZE(shirq_ras3_config),
+	.regs = {
+		.enb_reg = -1,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_RAS3_MASK,
+		.clear_reg = -1,
+	},
+};
+
+struct shirq_dev_config shirq_intrcomm_ras_config[] = {
+	{
+		.virq = VIRQ_TDM_HDLC,
+		.status_mask = TDM_HDLC_IRQ_MASK,
+	}, {
+		.virq = VIRQ_RS485_0,
+		.status_mask = RS485_0_IRQ_MASK,
+	}, {
+		.virq = VIRQ_RS485_1,
+		.status_mask = RS485_1_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_intrcomm_ras = {
+	.irq = IRQ_INTRCOMM_RAS_ARM,
+	.dev_config = shirq_intrcomm_ras_config,
+	.dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config),
+	.regs = {
+		.enb_reg = -1,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_INTRCOMM_RAS_MASK,
+		.clear_reg = -1,
+	},
+};
+
 /* spear310 routines */
 void __init spear310_init(void)
 {
+	void __iomem *base;
+	int ret = 0;
+
 	/* call spear3xx family common init function */
 	spear3xx_init();
+
+	/* shared irq registeration */
+	base = ioremap(SPEAR310_SOC_CONFIG_BASE, SPEAR310_SOC_CONFIG_SIZE);
+	if (base) {
+		/* shirq 1 */
+		shirq_ras1.regs.base = base;
+		ret = spear_shirq_register(&shirq_ras1);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 1\n");
+
+		/* shirq 2 */
+		shirq_ras2.regs.base = base;
+		ret = spear_shirq_register(&shirq_ras2);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 2\n");
+
+		/* shirq 3 */
+		shirq_ras3.regs.base = base;
+		ret = spear_shirq_register(&shirq_ras3);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 3\n");
+
+		/* shirq 4 */
+		shirq_intrcomm_ras.regs.base = base;
+		ret = spear_shirq_register(&shirq_intrcomm_ras);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 4\n");
+	}
 }
 
 void spear310_pmx_init(void)
diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c
index 2cedf5e..a04f263 100644
--- a/arch/arm/mach-spear3xx/spear320.c
+++ b/arch/arm/mach-spear3xx/spear320.c
@@ -15,6 +15,7 @@
 #include <asm/irq.h>
 #include <mach/generic.h>
 #include <mach/spear.h>
+#include <plat/shirq.h>
 
 /* pad multiplexing support */
 /* muxing registers */
@@ -385,11 +386,139 @@ struct pmx_driver pmx_driver = {
 
 /* Add spear320 specific devices here */
 
+/* spear3xx shared irq */
+struct shirq_dev_config shirq_ras1_config[] = {
+	{
+		.virq = VIRQ_EMI,
+		.status_mask = EMI_IRQ_MASK,
+	}, {
+		.virq = VIRQ_CLCD,
+		.status_mask = CLCD_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SPP,
+		.status_mask = SPP_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_ras1 = {
+	.irq = IRQ_GEN_RAS_1,
+	.dev_config = shirq_ras1_config,
+	.dev_count = ARRAY_SIZE(shirq_ras1_config),
+	.regs = {
+		.enb_reg = -1,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_RAS1_MASK,
+		.clear_reg = -1,
+	},
+};
+
+struct shirq_dev_config shirq_ras3_config[] = {
+	{
+		.virq = VIRQ_PLGPIO,
+		.enb_mask = GPIO_IRQ_MASK,
+		.status_mask = GPIO_IRQ_MASK,
+	}, {
+		.virq = VIRQ_I2S_PLAY,
+		.enb_mask = I2S_PLAY_IRQ_MASK,
+		.status_mask = I2S_PLAY_IRQ_MASK,
+	}, {
+		.virq = VIRQ_I2S_REC,
+		.enb_mask = I2S_REC_IRQ_MASK,
+		.status_mask = I2S_REC_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_ras3 = {
+	.irq = IRQ_GEN_RAS_3,
+	.dev_config = shirq_ras3_config,
+	.dev_count = ARRAY_SIZE(shirq_ras3_config),
+	.regs = {
+		.enb_reg = INT_ENB_MASK_REG,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_RAS3_MASK,
+		.clear_reg = -1,
+	},
+};
+
+struct shirq_dev_config shirq_intrcomm_ras_config[] = {
+	{
+		.virq = VIRQ_CANU,
+		.status_mask = CAN_U_IRQ_MASK,
+	}, {
+		.virq = VIRQ_CANL,
+		.status_mask = CAN_L_IRQ_MASK,
+	}, {
+		.virq = VIRQ_UART1,
+		.status_mask = UART1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_UART2,
+		.status_mask = UART2_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SSP1,
+		.status_mask = SSP1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SSP2,
+		.status_mask = SSP2_IRQ_MASK,
+	}, {
+		.virq = VIRQ_SMII0,
+		.status_mask = SMII0_IRQ_MASK,
+	}, {
+		.virq = VIRQ_MII1_SMII1,
+		.status_mask = MII1_SMII1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_WAKEUP_SMII0,
+		.status_mask = WAKEUP_SMII0_IRQ_MASK,
+	}, {
+		.virq = VIRQ_WAKEUP_MII1_SMII1,
+		.status_mask = WAKEUP_MII1_SMII1_IRQ_MASK,
+	}, {
+		.virq = VIRQ_I2C,
+		.status_mask = I2C1_IRQ_MASK,
+	},
+};
+
+struct spear_shirq shirq_intrcomm_ras = {
+	.irq = IRQ_INTRCOMM_RAS_ARM,
+	.dev_config = shirq_intrcomm_ras_config,
+	.dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config),
+	.regs = {
+		.enb_reg = -1,
+		.status_reg = INT_STS_MASK_REG,
+		.status_reg_mask = SHIRQ_INTRCOMM_RAS_MASK,
+		.clear_reg = -1,
+	},
+};
+
 /* spear320 routines */
 void __init spear320_init(void)
 {
+	void __iomem *base;
+	int ret = 0;
+
 	/* call spear3xx family common init function */
 	spear3xx_init();
+
+	/* shared irq registeration */
+	base = ioremap(SPEAR320_SOC_CONFIG_BASE, SPEAR320_SOC_CONFIG_SIZE);
+	if (base) {
+		/* shirq 1 */
+		shirq_ras1.regs.base = base;
+		ret = spear_shirq_register(&shirq_ras1);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 1\n");
+
+		/* shirq 3 */
+		shirq_ras3.regs.base = base;
+		ret = spear_shirq_register(&shirq_ras3);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 3\n");
+
+		/* shirq 4 */
+		shirq_intrcomm_ras.regs.base = base;
+		ret = spear_shirq_register(&shirq_intrcomm_ras);
+		if (ret)
+			printk(KERN_ERR "Error registering Shared IRQ 4\n");
+	}
 }
 
 void spear320_pmx_init(void)
diff --git a/arch/arm/mach-spear6xx/include/mach/irqs.h b/arch/arm/mach-spear6xx/include/mach/irqs.h
index 08a3abc..8f214b0 100755
--- a/arch/arm/mach-spear6xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear6xx/include/mach/irqs.h
@@ -85,6 +85,7 @@
 
 #define IRQ_VIC_END				64
 
+/* GPIO pins virtual irqs */
 #define SPEAR_GPIO_INT_BASE	IRQ_VIC_END
 #define SPEAR_GPIO0_INT_BASE	SPEAR_GPIO_INT_BASE
 #define SPEAR_GPIO1_INT_BASE	(SPEAR_GPIO0_INT_BASE + 8)
diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile
index 6f4ad5e..eb89540 100644
--- a/arch/arm/plat-spear/Makefile
+++ b/arch/arm/plat-spear/Makefile
@@ -4,3 +4,5 @@
 
 # Common support
 obj-y	:= clock.o padmux.o time.o
+
+obj-$(CONFIG_ARCH_SPEAR3XX)	+= shirq.o
diff --git a/arch/arm/plat-spear/include/plat/shirq.h b/arch/arm/plat-spear/include/plat/shirq.h
new file mode 100644
index 0000000..bb7b4a9
--- /dev/null
+++ b/arch/arm/plat-spear/include/plat/shirq.h
@@ -0,0 +1,69 @@
+/*
+ * arch/arm/plat-spear/include/plat/shirq.h
+ *
+ * SPEAr platform shared irq layer header file
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar<viresh.kumar at st.com>
+ *
+ * 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.
+ */
+
+#ifndef __PLAT_SHIRQ_H
+#define __PLAT_SHIRQ_H
+
+#include <linux/irq.h>
+#include <linux/types.h>
+
+/*
+ * struct shirq_dev_config: shared irq device configuration
+ *
+ * virq: virtual irq number of device
+ * enb_mask: enable mask of device
+ * status_mask: status mask of device
+ * clear_mask: clear mask of device
+ */
+struct shirq_dev_config {
+	u32 virq;
+	u32 enb_mask;
+	u32 status_mask;
+	u32 clear_mask;
+};
+
+/*
+ * struct shirq_regs: shared irq register configuration
+ *
+ * base: base address of shared irq register
+ * enb_reg: enable register offset
+ * status_reg: status register offset
+ * status_reg_mask: status register valid mask
+ * clear_reg: clear register offset
+ */
+struct shirq_regs {
+	void __iomem *base;
+	u32 enb_reg;
+	u32 status_reg;
+	u32 status_reg_mask;
+	u32 clear_reg;
+};
+
+/*
+ * struct spear_shirq: shared irq structure
+ *
+ * irq: hardware irq number
+ * dev_config: array of device config structures which are using "irq" line
+ * dev_count: size of dev_config array
+ * regs: register configuration for shared irq block
+ */
+struct spear_shirq {
+	u32 irq;
+	struct shirq_dev_config *dev_config;
+	u32 dev_count;
+	struct shirq_regs regs;
+};
+
+int spear_shirq_register(struct spear_shirq *shirq);
+
+#endif /* __PLAT_SHIRQ_H */
diff --git a/arch/arm/plat-spear/shirq.c b/arch/arm/plat-spear/shirq.c
new file mode 100644
index 0000000..4f84406
--- /dev/null
+++ b/arch/arm/plat-spear/shirq.c
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/plat-spear/shirq.c
+ *
+ * SPEAr platform shared irq layer source file
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar<viresh.kumar at st.com>
+ *
+ * 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 <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <plat/shirq.h>
+
+struct spear_shirq *shirq;
+static DEFINE_SPINLOCK(lock);
+
+static void shirq_irq_mask(unsigned irq)
+{
+	struct spear_shirq *shirq = get_irq_chip_data(irq);
+	u32 val, id = irq - shirq->dev_config[0].virq;
+	unsigned long flags;
+
+	if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
+		return;
+
+	spin_lock_irqsave(&lock, flags);
+	val = readl(shirq->regs.base + shirq->regs.enb_reg);
+	val &= ~(shirq->dev_config[id].enb_mask);
+	writel(val, shirq->regs.base + shirq->regs.enb_reg);
+	spin_unlock_irqrestore(&lock, flags);
+}
+
+static void shirq_irq_unmask(unsigned irq)
+{
+	struct spear_shirq *shirq = get_irq_chip_data(irq);
+	u32 val, id = irq - shirq->dev_config[0].virq;
+	unsigned long flags;
+
+	if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
+		return;
+
+	spin_lock_irqsave(&lock, flags);
+	val = readl(shirq->regs.base + shirq->regs.enb_reg);
+	val |= shirq->dev_config[id].enb_mask;
+	writel(val, shirq->regs.base + shirq->regs.enb_reg);
+	spin_unlock_irqrestore(&lock, flags);
+}
+
+static struct irq_chip shirq_chip = {
+	.name		= "spear_shirq",
+	.mask		= shirq_irq_mask,
+	.unmask		= shirq_irq_unmask,
+};
+
+static void shirq_handler(unsigned irq, struct irq_desc *desc)
+{
+	u32 i, val;
+	struct spear_shirq *shirq = get_irq_chip_data(irq);
+
+	desc->chip->ack(irq);
+	while ((val = readl(shirq->regs.base + shirq->regs.status_reg) &
+				shirq->regs.status_reg_mask)) {
+		for (i = 0; (i < shirq->dev_count) && val; i++) {
+			if (!(shirq->dev_config[i].status_mask & val))
+				continue;
+
+			generic_handle_irq(shirq->dev_config[i].virq);
+
+			/* clear interrupt */
+			val &= ~shirq->dev_config[i].status_mask;
+			if ((shirq->regs.clear_reg == -1) ||
+					shirq->dev_config[i].clear_mask == -1)
+				continue;
+			writel(shirq->dev_config[i].clear_mask, shirq->regs.base
+					+ shirq->regs.clear_reg);
+		}
+	}
+	desc->chip->unmask(irq);
+}
+
+int spear_shirq_register(struct spear_shirq *shirq)
+{
+	int i;
+
+	if (!shirq || !shirq->dev_config || !shirq->regs.base)
+		return -EFAULT;
+
+	if (!shirq->dev_count)
+		return -EINVAL;
+
+	set_irq_chained_handler(shirq->irq, shirq_handler);
+	for (i = 0; i < shirq->dev_count; i++) {
+		set_irq_chip(shirq->dev_config[i].virq, &shirq_chip);
+		set_irq_handler(shirq->dev_config[i].virq, handle_simple_irq);
+		set_irq_flags(shirq->dev_config[i].virq, IRQF_VALID);
+		set_irq_chip_data(shirq->dev_config[i].virq, shirq);
+	}
+
+	set_irq_chip_data(shirq->irq, shirq);
+	return 0;
+}
-- 
1.6.0.2




More information about the linux-arm-kernel mailing list