From mboxrd@z Thu Jan 1 00:00:00 1970 From: ben-linux@fluff.org (Ben Dooks) Date: Mon, 19 Apr 2010 12:02:44 +0100 Subject: [PATCH] ST SPEAr: Adding support for shared irq layer In-Reply-To: <1271149610-2440-1-git-send-email-viresh.kumar@st.com> References: <1271149610-2440-1-git-send-email-viresh.kumar@st.com> Message-ID: <20100419110243.GC6684@trinity.fluff.org> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On Tue, Apr 13, 2010 at 02:36:50PM +0530, Viresh KUMAR wrote: > 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 > --- > 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 > #include > #include > +#include > > /* 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, > + }, > +}; Hmm, this seems to be an awful lot of data required. Why not just ensure that the each interrupt chip has a 1:1 mapping of bit to interrupt number? > +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 > #include > #include > +#include > > /* 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 > #include > #include > +#include > > /* 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 > + * > + * 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 > +#include > + > +/* > + * 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 > + * > + * 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 > +#include > +#include > +#include > +#include > + > +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 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- -- Ben Q: What's a light-year? A: One-third less calories than a regular year.