ARM: 6091/1: ST SPEAr: Adding support for shared irq layer
authorviresh kumar <viresh.kumar@st.com>
Mon, 3 May 2010 08:24:30 +0000 (09:24 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 4 May 2010 15:54:54 +0000 (16:54 +0100)
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.

Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-spear3xx/include/mach/irqs.h
arch/arm/mach-spear3xx/include/mach/spear300.h
arch/arm/mach-spear3xx/include/mach/spear310.h
arch/arm/mach-spear3xx/include/mach/spear320.h
arch/arm/mach-spear3xx/spear300.c
arch/arm/mach-spear3xx/spear310.c
arch/arm/mach-spear3xx/spear320.c
arch/arm/mach-spear6xx/include/mach/irqs.h
arch/arm/plat-spear/Makefile
arch/arm/plat-spear/include/plat/shirq.h [new file with mode: 0644]
arch/arm/plat-spear/shirq.c [new file with mode: 0644]

index fe980e0..7f940b8 100644 (file)
@@ -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
 #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 */
index 40c16f3..ccaa765 100644 (file)
 #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
 
index d4f58d6..b27bb8a 100644 (file)
 
 #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 */
 
index e8ad2ed..cacf17a 100644 (file)
 
 #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_CLR_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 */
 
index 66e7fcd..3560f8c 100644 (file)
@@ -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)
index dd5a572..96a1ab8 100644 (file)
@@ -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)
index 2cedf5e..6a12195 100644 (file)
@@ -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,160 @@ 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,
+               .clear_mask = EMI_IRQ_MASK,
+       }, {
+               .virq = VIRQ_CLCD,
+               .status_mask = CLCD_IRQ_MASK,
+               .clear_mask = CLCD_IRQ_MASK,
+       }, {
+               .virq = VIRQ_SPP,
+               .status_mask = SPP_IRQ_MASK,
+               .clear_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 = INT_CLR_MASK_REG,
+               .reset_to_clear = 1,
+       },
+};
+
+struct shirq_dev_config shirq_ras3_config[] = {
+       {
+               .virq = VIRQ_PLGPIO,
+               .enb_mask = GPIO_IRQ_MASK,
+               .status_mask = GPIO_IRQ_MASK,
+               .clear_mask = GPIO_IRQ_MASK,
+       }, {
+               .virq = VIRQ_I2S_PLAY,
+               .enb_mask = I2S_PLAY_IRQ_MASK,
+               .status_mask = I2S_PLAY_IRQ_MASK,
+               .clear_mask = I2S_PLAY_IRQ_MASK,
+       }, {
+               .virq = VIRQ_I2S_REC,
+               .enb_mask = I2S_REC_IRQ_MASK,
+               .status_mask = I2S_REC_IRQ_MASK,
+               .clear_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,
+               .reset_to_enb = 1,
+               .status_reg = INT_STS_MASK_REG,
+               .status_reg_mask = SHIRQ_RAS3_MASK,
+               .clear_reg = INT_CLR_MASK_REG,
+               .reset_to_clear = 1,
+       },
+};
+
+struct shirq_dev_config shirq_intrcomm_ras_config[] = {
+       {
+               .virq = VIRQ_CANU,
+               .status_mask = CAN_U_IRQ_MASK,
+               .clear_mask = CAN_U_IRQ_MASK,
+       }, {
+               .virq = VIRQ_CANL,
+               .status_mask = CAN_L_IRQ_MASK,
+               .clear_mask = CAN_L_IRQ_MASK,
+       }, {
+               .virq = VIRQ_UART1,
+               .status_mask = UART1_IRQ_MASK,
+               .clear_mask = UART1_IRQ_MASK,
+       }, {
+               .virq = VIRQ_UART2,
+               .status_mask = UART2_IRQ_MASK,
+               .clear_mask = UART2_IRQ_MASK,
+       }, {
+               .virq = VIRQ_SSP1,
+               .status_mask = SSP1_IRQ_MASK,
+               .clear_mask = SSP1_IRQ_MASK,
+       }, {
+               .virq = VIRQ_SSP2,
+               .status_mask = SSP2_IRQ_MASK,
+               .clear_mask = SSP2_IRQ_MASK,
+       }, {
+               .virq = VIRQ_SMII0,
+               .status_mask = SMII0_IRQ_MASK,
+               .clear_mask = SMII0_IRQ_MASK,
+       }, {
+               .virq = VIRQ_MII1_SMII1,
+               .status_mask = MII1_SMII1_IRQ_MASK,
+               .clear_mask = MII1_SMII1_IRQ_MASK,
+       }, {
+               .virq = VIRQ_WAKEUP_SMII0,
+               .status_mask = WAKEUP_SMII0_IRQ_MASK,
+               .clear_mask = WAKEUP_SMII0_IRQ_MASK,
+       }, {
+               .virq = VIRQ_WAKEUP_MII1_SMII1,
+               .status_mask = WAKEUP_MII1_SMII1_IRQ_MASK,
+               .clear_mask = WAKEUP_MII1_SMII1_IRQ_MASK,
+       }, {
+               .virq = VIRQ_I2C,
+               .status_mask = I2C1_IRQ_MASK,
+               .clear_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 = INT_CLR_MASK_REG,
+               .reset_to_clear = 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)
index 08a3abc..8f214b0 100644 (file)
@@ -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)
index 6f4ad5e..eb89540 100644 (file)
@@ -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 (file)
index 0000000..03ed8b5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/plat-spear/include/plat/shirq.h
+ *
+ * SPEAr platform shared irq layer header file
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar<viresh.kumar@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
+ * reset_to_enb: val 1 indicates, we need to clear bit for enabling interrupt
+ * status_reg: status register offset
+ * status_reg_mask: status register valid mask
+ * clear_reg: clear register offset
+ * reset_to_clear: val 1 indicates, we need to clear bit for clearing interrupt
+ */
+struct shirq_regs {
+       void __iomem *base;
+       u32 enb_reg;
+       u32 reset_to_enb;
+       u32 status_reg;
+       u32 status_reg_mask;
+       u32 clear_reg;
+       u32 reset_to_clear;
+};
+
+/*
+ * 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 (file)
index 0000000..2172d69
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * arch/arm/plat-spear/shirq.c
+ *
+ * SPEAr platform shared irq layer source file
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar<viresh.kumar@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);
+       if (shirq->regs.reset_to_enb)
+               val |= shirq->dev_config[id].enb_mask;
+       else
+               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);
+       if (shirq->regs.reset_to_enb)
+               val &= ~(shirq->dev_config[id].enb_mask);
+       else
+               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",
+       .ack            = shirq_irq_mask,
+       .mask           = shirq_irq_mask,
+       .unmask         = shirq_irq_unmask,
+};
+
+static void shirq_handler(unsigned irq, struct irq_desc *desc)
+{
+       u32 i, val, mask;
+       struct spear_shirq *shirq = get_irq_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;
+                       mask = readl(shirq->regs.base + shirq->regs.clear_reg);
+                       if (shirq->regs.reset_to_clear)
+                               mask &= ~shirq->dev_config[i].clear_mask;
+                       else
+                               mask |= shirq->dev_config[i].clear_mask;
+                       writel(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_data(shirq->irq, shirq);
+       return 0;
+}