From mboxrd@z Thu Jan 1 00:00:00 1970 From: stanleymiao@gmail.com (stanleymiao at gmail.com) Date: Thu, 14 Oct 2010 16:38:09 +0800 Subject: [PATCH 3/3] Add irqs definition and handler for Mindspeed Comcerto platform In-Reply-To: <1287045489-1133-3-git-send-email-stanleymiao@gmail.com> References: <1287045489-1133-1-git-send-email-stanleymiao@gmail.com> <1287045489-1133-2-git-send-email-stanleymiao@gmail.com> <1287045489-1133-3-git-send-email-stanleymiao@gmail.com> Message-ID: <1287045489-1133-4-git-send-email-stanleymiao@gmail.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org From: Stanley.Miao the Comcerto interrupt controller supports more than 32 peripheral interrupts, so two interrupt status registers and associated mask registers are required. Signed-off-by: Stanley.Miao --- arch/arm/mach-comcerto/Makefile | 2 +- arch/arm/mach-comcerto/board-c1kmfcn_evm.c | 1 + arch/arm/mach-comcerto/comcerto-1000.c | 41 ++++ .../arm/mach-comcerto/include/mach/comcerto-1000.h | 1 + .../include/mach/comcerto-1000/intr.h | 78 ++++++++ .../include/mach/comcerto-1000/irqs.h | 121 ++++++++++++ arch/arm/mach-comcerto/include/mach/hardware.h | 1 + arch/arm/mach-comcerto/include/mach/irq.h | 155 +++++++++++++++ arch/arm/mach-comcerto/include/mach/irqs.h | 21 ++ arch/arm/mach-comcerto/irq.c | 200 ++++++++++++++++++++ 10 files changed, 620 insertions(+), 1 deletions(-) create mode 100644 arch/arm/mach-comcerto/include/mach/comcerto-1000/intr.h create mode 100644 arch/arm/mach-comcerto/include/mach/comcerto-1000/irqs.h create mode 100644 arch/arm/mach-comcerto/include/mach/irq.h create mode 100644 arch/arm/mach-comcerto/include/mach/irqs.h create mode 100644 arch/arm/mach-comcerto/irq.c diff --git a/arch/arm/mach-comcerto/Makefile b/arch/arm/mach-comcerto/Makefile index c514d20..b4c369d 100644 --- a/arch/arm/mach-comcerto/Makefile +++ b/arch/arm/mach-comcerto/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := time.o +obj-y := irq.o time.o obj-$(CONFIG_ARCH_M83XXX) += comcerto-1000.o obj-$(CONFIG_EVM_C1KMFCN_EVM) += board-c1kmfcn_evm.o diff --git a/arch/arm/mach-comcerto/board-c1kmfcn_evm.c b/arch/arm/mach-comcerto/board-c1kmfcn_evm.c index 74a7da3..3dd0b6f 100644 --- a/arch/arm/mach-comcerto/board-c1kmfcn_evm.c +++ b/arch/arm/mach-comcerto/board-c1kmfcn_evm.c @@ -69,6 +69,7 @@ static void __init platform_map_io(void) static void __init platform_irq_init(void) { + device_irq_init(); } static void __init platform_init(void) diff --git a/arch/arm/mach-comcerto/comcerto-1000.c b/arch/arm/mach-comcerto/comcerto-1000.c index 09032ea..2503871 100644 --- a/arch/arm/mach-comcerto/comcerto-1000.c +++ b/arch/arm/mach-comcerto/comcerto-1000.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include /*********************************************************** * Virtual address Mapping * @@ -144,3 +146,42 @@ void __init device_map_io(void) iotable_init(comcerto_io_desc, ARRAY_SIZE(comcerto_io_desc)); } +/* IRQ configuration table */ +static struct comcerto_irq_desc comcerto_irq_table[] __initdata = { + {IRQ_EMAC0_BATCH, handle_level_irq, 1}, + {IRQ_EMAC1_BATCH, handle_level_irq, 2}, + {IRQ_ARAM, comcerto_handle_secondary_level_irq, 3}, + {IRQ_PCIe0_EXT, handle_level_irq, 4}, + {IRQ_PCIe1_EXT, handle_level_irq, 5}, + {IRQ_PCIe0_INT, comcerto_handle_secondary_level_irq, 6}, + {IRQ_PCIe1_INT, comcerto_handle_secondary_level_irq, 7}, + {IRQ_USB0, comcerto_handle_secondary_level_irq, 8}, + {STATUS_REG_1, NULL, 9}, + {IRQ_PTP0, handle_level_irq, 10}, + {IRQ_TIMER1, comcerto_handle_secondary_level_irq, 11}, + {IRQ_TIMER3, comcerto_handle_secondary_level_irq, 12}, + {IRQ_TIMER4, comcerto_handle_secondary_level_irq, 13}, + {IRQ_TIMER5, comcerto_handle_secondary_level_irq, 14}, + {IRQ_SPI, comcerto_handle_secondary_level_irq, 15}, + {IRQ_EMAC0, comcerto_handle_secondary_level_irq, 16}, + {IRQ_EMAC1, comcerto_handle_secondary_level_irq, 17}, + {IRQ_IPSEC_WRAP, handle_level_irq, 18}, + {IRQ_I2C, comcerto_handle_secondary_level_irq, 19}, + {IRQ_CSP_PMU, handle_level_irq, -1}, + {IRQ_UART1, comcerto_handle_secondary_level_irq, -1}, + {IRQ_UART0, comcerto_handle_secondary_level_irq, -1}, + {IRQ_G2, handle_level_irq, -1}, + {IRQ_G1, handle_level_irq, -1}, + {IRQ_G0, handle_level_irq, -1}, + {IRQ_FPP, handle_level_irq, -1}, + {IRQ_CSPVED1RX, handle_level_irq, -1}, + {IRQ_CSPVED0RX, handle_level_irq, -1}, + {IRQ_SPDRV_ACP_REQ, handle_level_irq, -1}, + {IRQ_SPDRV_ACP_WORK_DONE, handle_level_irq, -1} +}; + +void __init device_irq_init(void) +{ + comcerto_irq_init(comcerto_irq_table, ARRAY_SIZE(comcerto_irq_table)); +} + diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-1000.h b/arch/arm/mach-comcerto/include/mach/comcerto-1000.h index 10086c4..ac9cd21 100644 --- a/arch/arm/mach-comcerto/include/mach/comcerto-1000.h +++ b/arch/arm/mach-comcerto/include/mach/comcerto-1000.h @@ -90,5 +90,6 @@ #define APB_VADDR(x) ((x) - COMCERTO_AHB_APB_BASE + APB_VADDR_BASE) #include +#include #endif diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-1000/intr.h b/arch/arm/mach-comcerto/include/mach/comcerto-1000/intr.h new file mode 100644 index 0000000..61c2e3a --- /dev/null +++ b/arch/arm/mach-comcerto/include/mach/comcerto-1000/intr.h @@ -0,0 +1,78 @@ +/* + * arch/arm/mach-comcerto/include/mach/comcerto-1000/intr.h + * + * Copyright (C) 2008 Mindspeed Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTINTCULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __INTR__H__ +#define __INTR__H__ + +/* Comcerto Interrupt Controller */ +#define COMCERTO_INTC_STATUS_REG_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x00)) +#define COMCERTO_INTC_CLEAR_STATUS_REG_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x00)) +#define COMCERTO_INTC_SET_STATUS_REG_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x04)) +#define COMCERTO_INTC_ARM0_IRQMASK_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x08)) +#define COMCERTO_INTC_ARM0_FIQMASK_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x0C)) +#define COMCERTO_INTC_ARM1_IRQMASK_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x10)) +#define COMCERTO_INTC_ARM1_FIQMASK_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x14)) +#define COMCERTO_INTC_ARM1_CONTROL_REG APB_VADDR((COMCERTO_APB_INTC_BASE + 0x18)) +#define COMCERTO_INTC_IRQ_ACK_TEST_REG APB_VADDR((COMCERTO_APB_INTC_BASE + 0x1C)) +#define COMCERTO_INTC_STATUS_REG_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x20)) +#define COMCERTO_INTC_CLEAR_STATUS_REG_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x20)) +#define COMCERTO_INTC_SET_STATUS_REG_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x24)) +#define COMCERTO_INTC_ARM0_IRQMASK_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x28)) +#define COMCERTO_INTC_ARM0_FIQMASK_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x2C)) +#define COMCERTO_INTC_ARM1_IRQMASK_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x30)) +#define COMCERTO_INTC_ARM1_FIQMASK_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x34)) +#define COMCERTO_INTC_STATUS_MASK_REG_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x38)) +#define COMCERTO_INTC_ARM0_PRTY_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x40)) +#define COMCERTO_INTC_ARM0_PRTY_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x44)) +#define COMCERTO_INTC_ARM0_PRTY_2 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x48)) +#define COMCERTO_INTC_ARM0_PRTY_3 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x4C)) +#define COMCERTO_INTC_ARM0_PRTY_4 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x50)) +#define COMCERTO_INTC_ARM0_PRTY_5 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x54)) +#define COMCERTO_INTC_ARM0_PRTY_6 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x58)) +#define COMCERTO_INTC_ARM0_PRTY_7 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x5C)) +#define COMCERTO_INTC_ARM0_IRQ_WNR APB_VADDR((COMCERTO_APB_INTC_BASE + 0x60)) +#define COMCERTO_INTC_ARM0_SELFCLEAR APB_VADDR((COMCERTO_APB_INTC_BASE + 0x64)) +#define COMCERTO_INTC_FIQ_PRTY_EN APB_VADDR((COMCERTO_APB_INTC_BASE + 0x68)) +#define COMCERTO_INTC_TDMA_STS APB_VADDR((COMCERTO_APB_INTC_BASE + 0x70)) +#define COMCERTO_INTC_TDMA_CTRL APB_VADDR((COMCERTO_APB_INTC_BASE + 0x74)) +#define COMCERTO_INTC_TDMA_SET APB_VADDR((COMCERTO_APB_INTC_BASE + 0x78)) +#define COMCERTO_INTC_ARM1_PRTY_0 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x80)) +#define COMCERTO_INTC_ARM1_PRTY_1 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x84)) +#define COMCERTO_INTC_ARM1_PRTY_2 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x88)) +#define COMCERTO_INTC_ARM1_PRTY_3 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x8C)) +#define COMCERTO_INTC_ARM1_PRTY_4 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x90)) +#define COMCERTO_INTC_ARM1_PRTY_5 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x94)) +#define COMCERTO_INTC_ARM1_PRTY_6 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x98)) +#define COMCERTO_INTC_ARM1_PRTY_7 APB_VADDR((COMCERTO_APB_INTC_BASE + 0x9C)) +#define COMCERTO_INTC_ARM1_IRQ_WNR APB_VADDR((COMCERTO_APB_INTC_BASE + 0xA0)) +#define COMCERTO_INTC_ARM0_IRQ_WNR_VBA APB_VADDR((COMCERTO_APB_INTC_BASE + 0xB0)) +#define COMCERTO_INTC_ARM1_IRQ_WNR_VBA APB_VADDR((COMCERTO_APB_INTC_BASE + 0xB4)) +#define COMCERTO_INTC_ARM0_STS_VEC_ADDR(nb) APB_VADDR((COMCERTO_APB_INTC_BASE + 0x100 + 4nb)) +#define COMCERTO_INTC_ARM1_STS_VEC_ADDR(nb) APB_VADDR((COMCERTO_APB_INTC_BASE + 0x180 + 4nb)) + +#define COMCERTO_INTC_CSP_IRQMASK_0 COMCERTO_INTC_ARM0_IRQMASK_0 +#define COMCERTO_INTC_CSP_IRQMASK_1 COMCERTO_INTC_ARM0_IRQMASK_1 +#define COMCERTO_INTC_CSP_FIQMASK_0 COMCERTO_INTC_ARM0_FIQMASK_0 +#define COMCERTO_INTC_CSP_FIQMASK_1 COMCERTO_INTC_ARM0_FIQMASK_1 + +#define COMCERTO_INTC_CSP_IRQ_WNR COMCERTO_INTC_ARM0_IRQ_WNR +#define COMCERTO_INTC_CSP_PRTY_0 COMCERTO_INTC_ARM0_PRTY_0 + +#endif diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-1000/irqs.h b/arch/arm/mach-comcerto/include/mach/comcerto-1000/irqs.h new file mode 100644 index 0000000..7f59a77 --- /dev/null +++ b/arch/arm/mach-comcerto/include/mach/comcerto-1000/irqs.h @@ -0,0 +1,121 @@ +/* + * arch/arm/mach-comcerto/include/mach/comcerto-1000/irqs.h + * + * Copyright (C) 2008 Mindspeed Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __COMCERTO_IRQS_H__ +#define __COMCERTO_IRQS_H__ + +/* INTC0 32 First IRQs*/ +#define IRQ_TIMER0 31 +#define IRQ_TIMER1 30 +#define IRQ_TIMER2 29 +#define IRQ_TIMER3 28 +#define IRQ_TIMER4 27 +#define IRQ_TIMER5 26 +/* #define IRQ_Reserved 25*/ +#define IRQ_EMAC1_BATCH 24 +#define IRQ_EMAC0_BATCH 23 +#define IRQ_ARAM 22 +#define IRQ_I2C 21 +#define IRQ_THERMAL 20 +#define IRQ_HWFAULT 19 +#define IRQ_DDRC 18 +#define IRQ_PCIe1_INT 17 +#define IRQ_PCIe1_EXT 16 +#define IRQ_PCIe0_INT 15 +#define IRQ_PCIe0_EXT 14 +#define IRQ_MDMA1 13 +#define IRQ_MDMA0 12 +#define IRQ_SPI 11 +#define IRQ_IPSEC_CORE 10 +#define IRQ_IPSEC_WRAP 9 +#define IRQ_TDMA 8 +#define IRQ_EMAC1 7 +#define IRQ_EMAC0 6 +#define IRQ_USB0 5 +#define IRQ_TDM_TIMER 4 +#define IRQ_PTP2 3 +#define IRQ_PTP1 2 +#define IRQ_PTP0 1 +#define STATUS_REG_1 0 + +/* INTC1 32 next IRQs*/ +/* #define IRQ_Reserved 31*/ +/* #define IRQ_Reserved 30*/ +/* #define IRQ_Reserved 29*/ +#define IRQ_TDMA_TxAHBErr (28 + 32) +#define IRQ_TDMA_RxAHBErr (27 + 32) +#define IRQ_UART1 (26 + 32) +#define IRQ_CSP_HIDRV (25 + 32) +#define IRQ_CSPVED1TX (24 + 32) +#define IRQ_CSPVED1RX (23 + 32) +#define IRQ_CSPVED0TX (22 + 32) +#define IRQ_CSPVED0RX (21 + 32) +#define IRQ_TOHOST (20 + 32) +#define IRQ_FROMHOST (19 + 32) +#define IRQ_MSP_PMU (18 + 32) +#define IRQ_CSP_PMU (17 + 32) +/* #define IRQ_Reserved 16*/ +/* #define IRQ_Reserved 15*/ +/* #define IRQ_Reserved 14*/ +#define IRQ_SPDRV_ACP_REQ (13 + 32) +#define IRQ_SPDRV_ACP_WORK_DONE (12 + 32) +#define IRQ_VED (11 + 32) +#define IRQ_TDMA_IND (10 + 32) +#define IRQ_UART0 (9 + 32) +#define IRQ_G7 (8 + 32) +#define IRQ_G6 (7 + 32) +#define IRQ_G5 (6 + 32) +#define IRQ_G4 (5 + 32) +#define IRQ_G3 (4 + 32) +#define IRQ_G2 (3 + 32) +#define IRQ_G1 (2 + 32) +#define IRQ_G0 (1 + 32) +#define STATUS_REG_0 (0 + 32) + +/* Software decoded interrupts used by PCIE */ +#define IRQ_PCIE0_MSI0 64 +#define IRQ_PCIE0_MSI1 65 +#define IRQ_PCIE0_MSI2 66 +#define IRQ_PCIE0_MSI3 67 + +#define IRQ_PCIE0_INTA 68 +#define IRQ_PCIE0_INTB 69 +#define IRQ_PCIE0_INTC 70 +#define IRQ_PCIE0_INTD 71 + +#define IRQ_PCIE1_MSI0 72 +#define IRQ_PCIE1_MSI1 73 +#define IRQ_PCIE1_MSI2 74 +#define IRQ_PCIE1_MSI3 75 + +#define IRQ_PCIE1_INTA 76 +#define IRQ_PCIE1_INTB 77 +#define IRQ_PCIE1_INTC 78 +#define IRQ_PCIE1_INTD 79 + + +#define NR_IRQS 80 + +#define IRQ_TIMERB IRQ_TIMER1 +#define IRQ_FPP IRQ_CSP_HIDRV + +#define FPP_IRQ_FROMHOST IRQ_FROMHOST +#define FPP_IRQ_TOHOST IRQ_TOHOST +#define FPP_IRQ_EVENT IRQ_FPP +#endif diff --git a/arch/arm/mach-comcerto/include/mach/hardware.h b/arch/arm/mach-comcerto/include/mach/hardware.h index 577289d..da023b2 100644 --- a/arch/arm/mach-comcerto/include/mach/hardware.h +++ b/arch/arm/mach-comcerto/include/mach/hardware.h @@ -32,6 +32,7 @@ struct sys_timer; extern struct sys_timer comcerto_timer; extern void device_map_io(void); +extern void device_irq_init(void); #endif #endif diff --git a/arch/arm/mach-comcerto/include/mach/irq.h b/arch/arm/mach-comcerto/include/mach/irq.h new file mode 100644 index 0000000..b5b8a54 --- /dev/null +++ b/arch/arm/mach-comcerto/include/mach/irq.h @@ -0,0 +1,155 @@ +/* + * arch/arm/mach-comcerto/include/mach/irq.h + * + * Copyright (C) 2004,2008 Mindspeed Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_IRQ_H +#define __ASM_ARCH_IRQ_H + +#include +#include + +extern spinlock_t comcerto_irq_lock; +extern int noirqdebug; + +struct comcerto_irq_desc { + char num; + irq_flow_handler_t handler; + unsigned int prio; +}; + +void comcerto_handle_secondary_level_irq(unsigned int irq, struct irq_desc *); +void __init comcerto_irq_init(struct comcerto_irq_desc *irq_table, int size); + +/* For all devices with priority support we provide a call to change STATUS1 + * priority from the EVM-specific code. Priority value should be in [0..31] + * range. + */ +void __init comcerto_irq_status1_priority_set(unsigned char priority); + +static inline u32 comcerto_irq_to_mask(unsigned int irq) +{ + return 1 << ((irq) & 0x1f); +} + +static inline void comcerto_irq_mask_0(unsigned int irq) +{ + unsigned long flags; + unsigned long mask; + + spin_lock_irqsave(&comcerto_irq_lock, flags); + mask = __raw_readl(COMCERTO_INTC_CSP_IRQMASK_0); + mask &= ~comcerto_irq_to_mask(irq); + __raw_writel(mask, COMCERTO_INTC_CSP_IRQMASK_0); + spin_unlock_irqrestore(&comcerto_irq_lock, flags); +} + +static inline void comcerto_irq_mask_1(unsigned int irq) +{ + unsigned long flags; + unsigned long mask; + + spin_lock_irqsave(&comcerto_irq_lock, flags); + mask = __raw_readl(COMCERTO_INTC_CSP_IRQMASK_1); + mask &= ~comcerto_irq_to_mask(irq); + __raw_writel(mask, COMCERTO_INTC_CSP_IRQMASK_1); + spin_unlock_irqrestore(&comcerto_irq_lock, flags); +} + +static inline void comcerto_irq_mask(unsigned int irq) +{ + if (irq < 32) + comcerto_irq_mask_0(irq); + else + comcerto_irq_mask_1(irq); +} + +static inline void comcerto_irq_ack_0(unsigned int irq) +{ + __raw_writel(comcerto_irq_to_mask(irq), COMCERTO_INTC_STATUS_REG_0); +} + +static inline void comcerto_irq_ack_1(unsigned int irq) +{ + __raw_writel(comcerto_irq_to_mask(irq), COMCERTO_INTC_STATUS_REG_1); +} + +static inline void comcerto_irq_ack(unsigned int irq) +{ + if (irq < 32) + comcerto_irq_ack_0(irq); + else + comcerto_irq_ack_1(irq); +} + +static inline void comcerto_irq_unmask_0(unsigned int irq) +{ + unsigned long flags; + unsigned long mask; + + spin_lock_irqsave(&comcerto_irq_lock, flags); + mask = __raw_readl(COMCERTO_INTC_CSP_IRQMASK_0); + mask |= comcerto_irq_to_mask(irq); + __raw_writel(mask, COMCERTO_INTC_CSP_IRQMASK_0); + spin_unlock_irqrestore(&comcerto_irq_lock, flags); +} + +static inline void comcerto_irq_unmask_1(unsigned int irq) +{ + unsigned long flags; + unsigned long mask; + + spin_lock_irqsave(&comcerto_irq_lock, flags); + mask = __raw_readl(COMCERTO_INTC_CSP_IRQMASK_1); + mask |= comcerto_irq_to_mask(irq); + __raw_writel(mask, COMCERTO_INTC_CSP_IRQMASK_1); + spin_unlock_irqrestore(&comcerto_irq_lock, flags); +} + +static inline void comcerto_irq_unmask(unsigned int irq) +{ + if (irq < 32) + comcerto_irq_unmask_0(irq); + else + comcerto_irq_unmask_1(irq); +} + +static inline void comcerto_softirq_set(unsigned int irq) +{ + void *reg; + + if (irq < 32) + reg = (void *)COMCERTO_INTC_SET_STATUS_REG_0; + else + reg = (void *)COMCERTO_INTC_SET_STATUS_REG_1; + + __raw_writel(comcerto_irq_to_mask(irq), reg); +} + +static inline int comcerto_softirq_check(unsigned int irq) +{ + void *reg; + + if (irq < 32) + reg = (void *)COMCERTO_INTC_STATUS_REG_0; + else + reg = (void *)COMCERTO_INTC_STATUS_REG_1; + + return __raw_readl(reg) & comcerto_irq_to_mask(irq) ? 1 : 0; +} + +#endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-comcerto/include/mach/irqs.h b/arch/arm/mach-comcerto/include/mach/irqs.h new file mode 100644 index 0000000..409281b --- /dev/null +++ b/arch/arm/mach-comcerto/include/mach/irqs.h @@ -0,0 +1,21 @@ +/* + * arch/arm/mach-comcerto/include/mach/irqs.h + * + * Copyright (C) 2004,2005 Mindspeed Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#if defined(CONFIG_ARCH_M83XXX) + #include +#else + #error "Unsupported CPU" +#endif + +#endif /* __ASM_ARCH_IRQS_H */ diff --git a/arch/arm/mach-comcerto/irq.c b/arch/arm/mach-comcerto/irq.c new file mode 100644 index 0000000..4288ba1 --- /dev/null +++ b/arch/arm/mach-comcerto/irq.c @@ -0,0 +1,200 @@ +/* + * linux/arch/arm/mach-comcerto/irq.c + * + * Copyright (C) 2004-2008 Mindspeed Technologies, Inc. + * Copyright (c) 2010 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +spinlock_t comcerto_irq_lock; + +static void comcerto_irq_mask_ack_0(unsigned int irq) +{ + comcerto_irq_mask_0(irq); + comcerto_irq_ack_0(irq); +} + +static void comcerto_irq_mask_ack_1(unsigned int irq) +{ + comcerto_irq_mask_1(irq); + comcerto_irq_ack_1(irq); +} + +static int comcerto_set_irq_type_0(unsigned int irq, unsigned int type) +{ + return 0; +} + +static int comcerto_set_irq_type_1(unsigned int irq, unsigned int type) +{ + return 0; +} + +static struct irq_chip comcerto_irq_chip_0 = { + .name = "Comcerto INTC0", + .disable = comcerto_irq_mask_0, + .ack = comcerto_irq_ack_0, + .mask = comcerto_irq_mask_0, + .unmask = comcerto_irq_unmask_0, + .set_type = comcerto_set_irq_type_0, + .mask_ack = comcerto_irq_mask_ack_0, +}; + +static struct irq_chip comcerto_irq_chip_1 = { + .name = "Comcerto INTC1", + .disable = comcerto_irq_mask_1, + .ack = comcerto_irq_ack_1, + .mask = comcerto_irq_mask_1, + .unmask = comcerto_irq_unmask_1, + .set_type = comcerto_set_irq_type_1, + .mask_ack = comcerto_irq_mask_ack_1, +}; + +void comcerto_handle_secondary_level_irq(unsigned int irq, + struct irq_desc *desc) +{ + struct irqaction *action; + irqreturn_t action_ret; + + raw_spin_lock(&desc->lock); + desc->chip->mask(irq); + + if (unlikely(desc->status & IRQ_INPROGRESS)) + goto out_unlock; + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + kstat_incr_irqs_this_cpu(irq, desc); + /* + * If its disabled or no action available + * keep it masked and get out of here + */ + action = desc->action; + if (unlikely(!action || (desc->status & IRQ_DISABLED))) { + desc->status |= IRQ_PENDING; + goto out_unlock; + } + + desc->status |= IRQ_INPROGRESS; + desc->status &= ~IRQ_PENDING; + raw_spin_unlock(&desc->lock); + + action_ret = handle_IRQ_event(irq, action); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); + + raw_spin_lock(&desc->lock); + desc->status &= ~IRQ_INPROGRESS; + + desc->chip->ack(irq); + + if (unlikely(desc->status & IRQ_ONESHOT)) + desc->status |= IRQ_MASKED; + else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) + desc->chip->unmask(irq); +out_unlock: + raw_spin_unlock(&desc->lock); +} + +static u8 comcerto_status0_priorities[32] __initdata = {0, }; + +static __init void comcerto_irq_priority_set(unsigned int irq, unsigned int prio) +{ + unsigned int prio_reg, prio_shift, prio_mask, tmp; + + /* we store +1 priority to reserve zero for non-used slots */ + comcerto_status0_priorities[irq] = prio + 1; + prio_reg = COMCERTO_INTC_CSP_PRTY_0 + 4 * (prio / 4); + prio_shift = ((prio % 4) << 3); + prio_mask = 0x1f << prio_shift; + tmp = __raw_readl(prio_reg) & ~prio_mask; + tmp |= irq << prio_shift; + __raw_writel(tmp, prio_reg); +} + +void __init comcerto_irq_status1_priority_set(unsigned char priority) +{ + int i; + unsigned long flags; + + if ((priority & ~31) != 0) + BUG(); + + priority++; /* */ + + spin_lock_irqsave(&comcerto_irq_lock, flags); + + /* look@all interrupts except STATUS1 and + * fix all priorities >= specified */ + for (i = 1; i < 32; i++) + if (comcerto_status0_priorities[i] >= priority \ + && comcerto_status0_priorities[i] > 0) + comcerto_status0_priorities[i]++; + + comcerto_status0_priorities[0] = priority; + + /* program all non-zero priorities, + * don't forget to decrement priority value taken from array */ + for (i = 0; i < 32; i++) + if (comcerto_status0_priorities[i] > 0) + comcerto_irq_priority_set(i, comcerto_status0_priorities[i] - 1); + + spin_unlock_irqrestore(&comcerto_irq_lock, flags); +} + +void __init comcerto_irq_init(struct comcerto_irq_desc *irq_table, int size) +{ + unsigned int irq; + int i; + + spin_lock_init(&comcerto_irq_lock); + + /* mask all interrupts */ + __raw_writel(0, COMCERTO_INTC_CSP_IRQMASK_0); + __raw_writel(0, COMCERTO_INTC_CSP_IRQMASK_1); + + for (i = 0; i < size; i++) { + irq = irq_table[i].num; + + /* setup interrupt handler and priority */ + if (irq < 32) { + /* All STATUS0 interrupts must be setup from + * the single table declared in comcerto-xxx.c + * file. Use description index as a priority. + */ + comcerto_irq_priority_set(irq, irq_table[i].prio); + set_irq_chip(irq, &comcerto_irq_chip_0); + } else + set_irq_chip(irq, &comcerto_irq_chip_1); + + if (irq_table[i].handler != NULL) { + set_irq_handler(irq, irq_table[i].handler); + set_irq_flags(irq, IRQF_VALID); + } + } +} -- 1.5.4.3