diff options
Diffstat (limited to 'arch/sh/kernel/cpu/irq')
| -rw-r--r-- | arch/sh/kernel/cpu/irq/Makefile | 8 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/irq/imask.c | 76 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/irq/intc-sh5.c | 197 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/irq/intc2.c | 284 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 229 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/irq/maskreg.c | 93 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/irq/pint.c | 164 |
7 files changed, 279 insertions, 772 deletions
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index 1c034c283f5..f0c7025a67d 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile @@ -1,8 +1,6 @@ # # Makefile for the Linux/SuperH CPU-specifc IRQ handlers. # -obj-y += ipr.o imask.o - -obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o -obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o -obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o +obj-$(CONFIG_SUPERH32) += imask.o +obj-$(CONFIG_CPU_SH5) += intc-sh5.o +obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o diff --git a/arch/sh/kernel/cpu/irq/imask.c b/arch/sh/kernel/cpu/irq/imask.c index a33ae3e0a5a..e7f1745bd12 100644 --- a/arch/sh/kernel/cpu/irq/imask.c +++ b/arch/sh/kernel/cpu/irq/imask.c @@ -18,42 +18,23 @@ #include <linux/spinlock.h> #include <linux/cache.h> #include <linux/irq.h> -#include <asm/system.h> +#include <linux/bitmap.h> #include <asm/irq.h> /* Bitmap of IRQ masked */ -static unsigned long imask_mask = 0x7fff; -static int interrupt_priority = 0; - -static void enable_imask_irq(unsigned int irq); -static void disable_imask_irq(unsigned int irq); -static void shutdown_imask_irq(unsigned int irq); -static void mask_and_ack_imask(unsigned int); -static void end_imask_irq(unsigned int irq); - #define IMASK_PRIORITY 15 -static unsigned int startup_imask_irq(unsigned int irq) -{ - /* Nothing to do */ - return 0; /* never anything pending */ -} +static DECLARE_BITMAP(imask_mask, IMASK_PRIORITY); +static int interrupt_priority; -static struct hw_interrupt_type imask_irq_type = { - .typename = "SR.IMASK", - .startup = startup_imask_irq, - .shutdown = shutdown_imask_irq, - .enable = enable_imask_irq, - .disable = disable_imask_irq, - .ack = mask_and_ack_imask, - .end = end_imask_irq -}; - -void static inline set_interrupt_registers(int ip) +static inline void set_interrupt_registers(int ip) { unsigned long __dummy; - asm volatile("ldc %2, r6_bank\n\t" + asm volatile( +#ifdef CONFIG_CPU_HAS_SR_RB + "ldc %2, r6_bank\n\t" +#endif "stc sr, %0\n\t" "and #0xf0, %0\n\t" "shlr2 %0\n\t" @@ -69,42 +50,35 @@ void static inline set_interrupt_registers(int ip) : "t"); } -static void disable_imask_irq(unsigned int irq) +static void mask_imask_irq(struct irq_data *data) { - clear_bit(irq, &imask_mask); + unsigned int irq = data->irq; + + clear_bit(irq, imask_mask); if (interrupt_priority < IMASK_PRIORITY - irq) interrupt_priority = IMASK_PRIORITY - irq; - set_interrupt_registers(interrupt_priority); } -static void enable_imask_irq(unsigned int irq) +static void unmask_imask_irq(struct irq_data *data) { - set_bit(irq, &imask_mask); - interrupt_priority = IMASK_PRIORITY - ffz(imask_mask); + unsigned int irq = data->irq; + set_bit(irq, imask_mask); + interrupt_priority = IMASK_PRIORITY - + find_first_zero_bit(imask_mask, IMASK_PRIORITY); set_interrupt_registers(interrupt_priority); } -static void mask_and_ack_imask(unsigned int irq) -{ - disable_imask_irq(irq); -} - -static void end_imask_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_imask_irq(irq); -} - -static void shutdown_imask_irq(unsigned int irq) -{ - /* Nothing to do */ -} +static struct irq_chip imask_irq_chip = { + .name = "SR.IMASK", + .irq_mask = mask_imask_irq, + .irq_unmask = unmask_imask_irq, + .irq_mask_ack = mask_imask_irq, +}; void make_imask_irq(unsigned int irq) { - disable_irq_nosync(irq); - irq_desc[irq].chip = &imask_irq_type; - enable_irq(irq); + irq_set_chip_and_handler_name(irq, &imask_irq_chip, handle_level_irq, + "level"); } diff --git a/arch/sh/kernel/cpu/irq/intc-sh5.c b/arch/sh/kernel/cpu/irq/intc-sh5.c new file mode 100644 index 00000000000..9e056a3a0c7 --- /dev/null +++ b/arch/sh/kernel/cpu/irq/intc-sh5.c @@ -0,0 +1,197 @@ +/* + * arch/sh/kernel/cpu/irq/intc-sh5.c + * + * Interrupt Controller support for SH5 INTC. + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + * Per-interrupt selective. IRLM=0 (Fixed priority) is not + * supported being useless without a cascaded interrupt + * controller. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <cpu/irq.h> +#include <asm/page.h> + +/* + * Maybe the generic Peripheral block could move to a more + * generic include file. INTC Block will be defined here + * and only here to make INTC self-contained in a single + * file. + */ +#define INTC_BLOCK_OFFSET 0x01000000 + +/* Base */ +#define INTC_BASE PHYS_PERIPHERAL_BLOCK + \ + INTC_BLOCK_OFFSET + +/* Address */ +#define INTC_ICR_SET (intc_virt + 0x0) +#define INTC_ICR_CLEAR (intc_virt + 0x8) +#define INTC_INTPRI_0 (intc_virt + 0x10) +#define INTC_INTSRC_0 (intc_virt + 0x50) +#define INTC_INTSRC_1 (intc_virt + 0x58) +#define INTC_INTREQ_0 (intc_virt + 0x60) +#define INTC_INTREQ_1 (intc_virt + 0x68) +#define INTC_INTENB_0 (intc_virt + 0x70) +#define INTC_INTENB_1 (intc_virt + 0x78) +#define INTC_INTDSB_0 (intc_virt + 0x80) +#define INTC_INTDSB_1 (intc_virt + 0x88) + +#define INTC_ICR_IRLM 0x1 +#define INTC_INTPRI_PREGS 8 /* 8 Priority Registers */ +#define INTC_INTPRI_PPREG 8 /* 8 Priorities per Register */ + + +/* + * Mapper between the vector ordinal and the IRQ number + * passed to kernel/device drivers. + */ +int intc_evt_to_irq[(0xE20/0x20)+1] = { + -1, -1, -1, -1, -1, -1, -1, -1, /* 0x000 - 0x0E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0x100 - 0x1E0 */ + 0, 0, 0, 0, 0, 1, 0, 0, /* 0x200 - 0x2E0 */ + 2, 0, 0, 3, 0, 0, 0, -1, /* 0x300 - 0x3E0 */ + 32, 33, 34, 35, 36, 37, 38, -1, /* 0x400 - 0x4E0 */ + -1, -1, -1, 63, -1, -1, -1, -1, /* 0x500 - 0x5E0 */ + -1, -1, 18, 19, 20, 21, 22, -1, /* 0x600 - 0x6E0 */ + 39, 40, 41, 42, -1, -1, -1, -1, /* 0x700 - 0x7E0 */ + 4, 5, 6, 7, -1, -1, -1, -1, /* 0x800 - 0x8E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0x900 - 0x9E0 */ + 12, 13, 14, 15, 16, 17, -1, -1, /* 0xA00 - 0xAE0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB00 - 0xBE0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC00 - 0xCE0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD00 - 0xDE0 */ + -1, -1 /* 0xE00 - 0xE20 */ +}; + +static unsigned long intc_virt; +static int irlm; /* IRL mode */ + +static void enable_intc_irq(struct irq_data *data) +{ + unsigned int irq = data->irq; + unsigned long reg; + unsigned long bitmask; + + if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY)) + printk("Trying to use straight IRL0-3 with an encoding platform.\n"); + + if (irq < 32) { + reg = INTC_INTENB_0; + bitmask = 1 << irq; + } else { + reg = INTC_INTENB_1; + bitmask = 1 << (irq - 32); + } + + __raw_writel(bitmask, reg); +} + +static void disable_intc_irq(struct irq_data *data) +{ + unsigned int irq = data->irq; + unsigned long reg; + unsigned long bitmask; + + if (irq < 32) { + reg = INTC_INTDSB_0; + bitmask = 1 << irq; + } else { + reg = INTC_INTDSB_1; + bitmask = 1 << (irq - 32); + } + + __raw_writel(bitmask, reg); +} + +static struct irq_chip intc_irq_type = { + .name = "INTC", + .irq_enable = enable_intc_irq, + .irq_disable = disable_intc_irq, +}; + +void __init plat_irq_setup(void) +{ + unsigned long long __dummy0, __dummy1=~0x00000000100000f0; + unsigned long reg; + int i; + + intc_virt = (unsigned long)ioremap_nocache(INTC_BASE, 1024); + if (!intc_virt) { + panic("Unable to remap INTC\n"); + } + + + /* Set default: per-line enable/disable, priority driven ack/eoi */ + for (i = 0; i < NR_INTC_IRQS; i++) + irq_set_chip_and_handler(i, &intc_irq_type, handle_level_irq); + + + /* Disable all interrupts and set all priorities to 0 to avoid trouble */ + __raw_writel(-1, INTC_INTDSB_0); + __raw_writel(-1, INTC_INTDSB_1); + + for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8) + __raw_writel( NO_PRIORITY, reg); + + +#ifdef CONFIG_SH_CAYMAN + { + unsigned long data; + + /* Set IRLM */ + /* If all the priorities are set to 'no priority', then + * assume we are using encoded mode. + */ + irlm = platform_int_priority[IRQ_IRL0] + + platform_int_priority[IRQ_IRL1] + + platform_int_priority[IRQ_IRL2] + + platform_int_priority[IRQ_IRL3]; + if (irlm == NO_PRIORITY) { + /* IRLM = 0 */ + reg = INTC_ICR_CLEAR; + i = IRQ_INTA; + printk("Trying to use encoded IRL0-3. IRLs unsupported.\n"); + } else { + /* IRLM = 1 */ + reg = INTC_ICR_SET; + i = IRQ_IRL0; + } + __raw_writel(INTC_ICR_IRLM, reg); + + /* Set interrupt priorities according to platform description */ + for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) { + data |= platform_int_priority[i] << + ((i % INTC_INTPRI_PPREG) * 4); + if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) { + /* Upon the 7th, set Priority Register */ + __raw_writel(data, reg); + data = 0; + reg += 8; + } + } + } +#endif + + /* + * And now let interrupts come in. + * sti() is not enough, we need to + * lower priority, too. + */ + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "and %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy0) + : "r" (__dummy1)); +} diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c deleted file mode 100644 index e30e4b7aa70..00000000000 --- a/arch/sh/kernel/cpu/irq/intc2.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Interrupt handling for INTC2-based IRQ. - * - * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) - * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org) - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * These are the "new Hitachi style" interrupts, as present on the - * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/machvec.h> - -struct intc2_data { - unsigned char msk_offset; - unsigned char msk_shift; - - int (*clear_irq) (int); -}; - -static struct intc2_data intc2_data[NR_INTC2_IRQS]; - -static void enable_intc2_irq(unsigned int irq); -static void disable_intc2_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_intc2_irq disable_intc2_irq - -static void mask_and_ack_intc2(unsigned int); -static void end_intc2_irq(unsigned int irq); - -static unsigned int startup_intc2_irq(unsigned int irq) -{ - enable_intc2_irq(irq); - return 0; /* never anything pending */ -} - -static struct hw_interrupt_type intc2_irq_type = { - .typename = "INTC2-IRQ", - .startup = startup_intc2_irq, - .shutdown = shutdown_intc2_irq, - .enable = enable_intc2_irq, - .disable = disable_intc2_irq, - .ack = mask_and_ack_intc2, - .end = end_intc2_irq -}; - -static void disable_intc2_irq(unsigned int irq) -{ - int irq_offset = irq - INTC2_FIRST_IRQ; - int msk_shift, msk_offset; - - /* Sanity check */ - if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) - return; - - msk_shift = intc2_data[irq_offset].msk_shift; - msk_offset = intc2_data[irq_offset].msk_offset; - - ctrl_outl(1 << msk_shift, - INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset); -} - -static void enable_intc2_irq(unsigned int irq) -{ - int irq_offset = irq - INTC2_FIRST_IRQ; - int msk_shift, msk_offset; - - /* Sanity check */ - if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) - return; - - msk_shift = intc2_data[irq_offset].msk_shift; - msk_offset = intc2_data[irq_offset].msk_offset; - - ctrl_outl(1 << msk_shift, - INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset); -} - -static void mask_and_ack_intc2(unsigned int irq) -{ - disable_intc2_irq(irq); -} - -static void end_intc2_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_intc2_irq(irq); - - if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)) - intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq); -} - -/* - * Setup an INTC2 style interrupt. - * NOTE: Unlike IPR interrupts, parameters are not shifted by this code, - * allowing the use of the numbers straight out of the datasheet. - * For example: - * PIO1 which is INTPRI00[19,16] and INTMSK00[13] - * would be: ^ ^ ^ ^ - * | | | | - * make_intc2_irq(84, 0, 16, 0, 13); - */ -void make_intc2_irq(unsigned int irq, - unsigned int ipr_offset, unsigned int ipr_shift, - unsigned int msk_offset, unsigned int msk_shift, - unsigned int priority) -{ - int irq_offset = irq - INTC2_FIRST_IRQ; - unsigned int flags; - unsigned long ipr; - - if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) - return; - - disable_irq_nosync(irq); - - /* Fill the data we need */ - intc2_data[irq_offset].msk_offset = msk_offset; - intc2_data[irq_offset].msk_shift = msk_shift; - intc2_data[irq_offset].clear_irq = NULL; - - /* Set the priority level */ - local_irq_save(flags); - - ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset); - ipr &= ~(0xf << ipr_shift); - ipr |= priority << ipr_shift; - ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset); - - local_irq_restore(flags); - - irq_desc[irq].chip = &intc2_irq_type; - - disable_intc2_irq(irq); -} - -static struct intc2_init { - unsigned short irq; - unsigned char ipr_offset, ipr_shift; - unsigned char msk_offset, msk_shift; - unsigned char priority; -} intc2_init_data[] __initdata = { -#if defined(CONFIG_CPU_SUBTYPE_ST40) - {64, 0, 0, 0, 0, 13}, /* PCI serr */ - {65, 0, 4, 0, 1, 13}, /* PCI err */ - {66, 0, 4, 0, 2, 13}, /* PCI ad */ - {67, 0, 4, 0, 3, 13}, /* PCI pwd down */ - {72, 0, 8, 0, 5, 13}, /* DMAC INT0 */ - {73, 0, 8, 0, 6, 13}, /* DMAC INT1 */ - {74, 0, 8, 0, 7, 13}, /* DMAC INT2 */ - {75, 0, 8, 0, 8, 13}, /* DMAC INT3 */ - {76, 0, 8, 0, 9, 13}, /* DMAC INT4 */ - {78, 0, 8, 0, 11, 13}, /* DMAC ERR */ - {80, 0, 12, 0, 12, 13}, /* PIO0 */ - {84, 0, 16, 0, 13, 13}, /* PIO1 */ - {88, 0, 20, 0, 14, 13}, /* PIO2 */ - {112, 4, 0, 4, 0, 13}, /* Mailbox */ - #ifdef CONFIG_CPU_SUBTYPE_ST40GX1 - {116, 4, 4, 4, 4, 13}, /* SSC0 */ - {120, 4, 8, 4, 8, 13}, /* IR Blaster */ - {124, 4, 12, 4, 12, 13}, /* USB host */ - {128, 4, 16, 4, 16, 13}, /* Video processor BLITTER */ - {132, 4, 20, 4, 20, 13}, /* UART0 */ - {134, 4, 20, 4, 22, 13}, /* UART2 */ - {136, 4, 24, 4, 24, 13}, /* IO_PIO0 */ - {140, 4, 28, 4, 28, 13}, /* EMPI */ - {144, 8, 0, 8, 0, 13}, /* MAFE */ - {148, 8, 4, 8, 4, 13}, /* PWM */ - {152, 8, 8, 8, 8, 13}, /* SSC1 */ - {156, 8, 12, 8, 12, 13}, /* IO_PIO1 */ - {160, 8, 16, 8, 16, 13}, /* USB target */ - {164, 8, 20, 8, 20, 13}, /* UART1 */ - {168, 8, 24, 8, 24, 13}, /* Teletext */ - {172, 8, 28, 8, 28, 13}, /* VideoSync VTG */ - {173, 8, 28, 8, 29, 13}, /* VideoSync DVP0 */ - {174, 8, 28, 8, 30, 13}, /* VideoSync DVP1 */ -#endif -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) -/* - * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0 - */ - /* INTPRIO0 | INTMSK0 */ - {48, 0, 28, 0, 31, 3}, /* IRQ 4 */ - {49, 0, 24, 0, 30, 3}, /* IRQ 3 */ - {50, 0, 20, 0, 29, 3}, /* IRQ 2 */ - {51, 0, 16, 0, 28, 3}, /* IRQ 1 */ - /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */ - /* INTPRIO4 | INTMSK0 */ - {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */ - {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */ - {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */ - {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */ - {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */ - {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */ - {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */ - {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */ - /* INTPRIO8 | INTMSK0 */ - {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */ - {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */ - {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */ - {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */ - {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */ - {65, 8, 24, 0, 16, 3}, /* LCDC */ - /* 66, 67 unused */ - {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */ - {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */ - {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */ - /* 71 unused */ - {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */ - {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */ - {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */ - {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */ - {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */ - {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */ - {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */ - {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */ - /* | INTMSK4 */ - {80, 8, 4, 4, 23, 3}, /* SIM_ERI */ - {81, 8, 4, 4, 22, 3}, /* SIM_RXI */ - {82, 8, 4, 4, 21, 3}, /* SIM_TXI */ - {83, 8, 4, 4, 20, 3}, /* SIM_TEI */ - {84, 8, 0, 4, 19, 3}, /* HSPII */ - /* INTPRIOC | INTMSK4 */ - /* 85-87 unused/reserved */ - {88, 12, 20, 4, 18, 3}, /* MMCI0 */ - {89, 12, 20, 4, 17, 3}, /* MMCI1 */ - {90, 12, 20, 4, 16, 3}, /* MMCI2 */ - {91, 12, 20, 4, 15, 3}, /* MMCI3 */ - {92, 12, 12, 4, 6, 3}, /* MFI (unsure, bug? in my 7760 manual*/ - /* 93-107 reserved/undocumented */ - {108,12, 4, 4, 1, 3}, /* ADC */ - {109,12, 0, 4, 0, 3}, /* CMTI */ - /* 110-111 reserved/unused */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) - { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2}, - { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY }, - { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY }, - { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY }, - { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - - { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - - { PCIC0_IRQ, 0x10, 8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY }, - { PCIC1_IRQ, 0x10, 0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY }, - { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY }, - { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY }, - { PCIC4_IRQ, 0x14, 8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY }, -#endif -}; - -void __init init_IRQ_intc2(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(intc2_init_data); i++) { - struct intc2_init *p = intc2_init_data + i; - make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift, - p-> msk_offset, p->msk_shift, p->priority); - } -} - -/* Adds a termination callback to the interrupt */ -void intc2_add_clear_irq(int irq, int (*fn)(int)) -{ - if (unlikely(irq < INTC2_FIRST_IRQ)) - return; - - intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn; -} - diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index f785822cd5d..5de6dff5c21 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c @@ -1,204 +1,83 @@ /* - * arch/sh/kernel/cpu/irq/ipr.c + * Interrupt handling for IPR-based IRQ. * * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi * Copyright (C) 2000 Kazumoto Kojima - * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> - * - * Interrupt handling for IPR-based IRQ. + * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> + * Copyright (C) 2006 Paul Mundt * * Supported system: * On-chip supporting modules (TMU, RTC, etc.). - * On-chip supporting modules for SH7709/SH7709A/SH7729/SH7300. + * On-chip supporting modules for SH7709/SH7709A/SH7729. * Hitachi SolutionEngine external I/O: * MS7709SE01, MS7709ASE01, and MS7750SE01 * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. */ - #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> #include <linux/irq.h> +#include <linux/kernel.h> #include <linux/module.h> +#include <linux/topology.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/machvec.h> - -struct ipr_data { - unsigned int addr; /* Address of Interrupt Priority Register */ - int shift; /* Shifts of the 16-bit data */ - int priority; /* The priority */ -}; -static struct ipr_data ipr_data[NR_IRQS]; - -static void enable_ipr_irq(unsigned int irq); -static void disable_ipr_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_ipr_irq disable_ipr_irq - -static void mask_and_ack_ipr(unsigned int); -static void end_ipr_irq(unsigned int irq); - -static unsigned int startup_ipr_irq(unsigned int irq) +static inline struct ipr_desc *get_ipr_desc(struct irq_data *data) { - enable_ipr_irq(irq); - return 0; /* never anything pending */ + struct irq_chip *chip = irq_data_get_irq_chip(data); + return container_of(chip, struct ipr_desc, chip); } -static struct hw_interrupt_type ipr_irq_type = { - .typename = "IPR-IRQ", - .startup = startup_ipr_irq, - .shutdown = shutdown_ipr_irq, - .enable = enable_ipr_irq, - .disable = disable_ipr_irq, - .ack = mask_and_ack_ipr, - .end = end_ipr_irq -}; - -static void disable_ipr_irq(unsigned int irq) +static void disable_ipr_irq(struct irq_data *data) { - unsigned long val; - unsigned int addr = ipr_data[irq].addr; - unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); - + struct ipr_data *p = irq_data_get_irq_chip_data(data); + unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx]; /* Set the priority in IPR to 0 */ - val = ctrl_inw(addr); - val &= mask; - ctrl_outw(val, addr); + __raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr); + (void)__raw_readw(addr); /* Read back to flush write posting */ } -static void enable_ipr_irq(unsigned int irq) +static void enable_ipr_irq(struct irq_data *data) { - unsigned long val; - unsigned int addr = ipr_data[irq].addr; - int priority = ipr_data[irq].priority; - unsigned short value = (priority << ipr_data[irq].shift); - + struct ipr_data *p = irq_data_get_irq_chip_data(data); + unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx]; /* Set priority in IPR back to original value */ - val = ctrl_inw(addr); - val |= value; - ctrl_outw(val, addr); + __raw_writew(__raw_readw(addr) | (p->priority << p->shift), addr); } -static void mask_and_ack_ipr(unsigned int irq) +/* + * The shift value is now the number of bits to shift, not the number of + * bits/4. This is to make it easier to read the value directly from the + * datasheets. The IPR address is calculated using the ipr_offset table. + */ +void register_ipr_controller(struct ipr_desc *desc) { - disable_ipr_irq(irq); - -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) - /* This is needed when we use edge triggered setting */ - /* XXX: Is it really needed? */ - if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) { - /* Clear external interrupt request */ - int a = ctrl_inb(INTC_IRR0); - a &= ~(1 << (irq - IRQ0_IRQ)); - ctrl_outb(a, INTC_IRR0); + int i; + + desc->chip.irq_mask = disable_ipr_irq; + desc->chip.irq_unmask = enable_ipr_irq; + + for (i = 0; i < desc->nr_irqs; i++) { + struct ipr_data *p = desc->ipr_data + i; + int res; + + BUG_ON(p->ipr_idx >= desc->nr_offsets); + BUG_ON(!desc->ipr_offsets[p->ipr_idx]); + + res = irq_alloc_desc_at(p->irq, numa_node_id()); + if (unlikely(res != p->irq && res != -EEXIST)) { + printk(KERN_INFO "can not get irq_desc for %d\n", + p->irq); + continue; + } + + disable_irq_nosync(p->irq); + irq_set_chip_and_handler_name(p->irq, &desc->chip, + handle_level_irq, "level"); + irq_set_chip_data(p->irq, p); + disable_ipr_irq(irq_get_irq_data(p->irq)); } -#endif } - -static void end_ipr_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_ipr_irq(irq); -} - -void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) -{ - disable_irq_nosync(irq); - ipr_data[irq].addr = addr; - ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */ - ipr_data[irq].priority = priority; - - irq_desc[irq].chip = &ipr_irq_type; - disable_ipr_irq(irq); -} - -void __init init_IRQ(void) -{ -#ifndef CONFIG_CPU_SUBTYPE_SH7780 - make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); - make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); -#ifdef RTC_IRQ - make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); -#endif - -#ifdef SCI_ERI_IRQ - make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); - make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); - make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); -#endif - -#ifdef SCIF1_ERI_IRQ - make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); - make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); - make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); - make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7300) - make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY); - make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); - make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); - make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); -#endif - -#ifdef SCIF_ERI_IRQ - make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); - make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); - make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); - make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); -#endif - -#ifdef IRDA_ERI_IRQ - make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); - make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); - make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); - make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) - /* - * Initialize the Interrupt Controller (INTC) - * registers to their power on values - */ - - /* - * Enable external irq (INTC IRQ mode). - * You should set corresponding bits of PFC to "00" - * to enable these interrupts. - */ - make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY); - make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY); - make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY); - make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY); - make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY); - make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY); -#endif -#endif - -#ifdef CONFIG_CPU_HAS_PINT_IRQ - init_IRQ_pint(); -#endif - -#ifdef CONFIG_CPU_HAS_INTC2_IRQ - init_IRQ_intc2(); -#endif - /* Perform the machine specific initialisation */ - if (sh_mv.mv_init_irq != NULL) - sh_mv.mv_init_irq(); - - irq_ctx_init(smp_processor_id()); -} - -#if !defined(CONFIG_CPU_HAS_PINT_IRQ) -int ipr_irq_demux(int irq) -{ - return irq; -} -#endif - -EXPORT_SYMBOL(make_ipr_irq); +EXPORT_SYMBOL(register_ipr_controller); diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c deleted file mode 100644 index 492db31b3ca..00000000000 --- a/arch/sh/kernel/cpu/irq/maskreg.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Interrupt handling for Simple external interrupt mask register - * - * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp> - * - * This is for the machine which have single 16 bit register - * for masking external IRQ individually. - * Each bit of the register is for masking each interrupt. - * - * This file may be copied or modified under the terms of the GNU - * General Public License. See linux/COPYING for more information. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <asm/system.h> -#include <asm/io.h> - -/* address of external interrupt mask register */ -unsigned long irq_mask_register; - -/* forward declaration */ -static unsigned int startup_maskreg_irq(unsigned int irq); -static void shutdown_maskreg_irq(unsigned int irq); -static void enable_maskreg_irq(unsigned int irq); -static void disable_maskreg_irq(unsigned int irq); -static void mask_and_ack_maskreg(unsigned int); -static void end_maskreg_irq(unsigned int irq); - -/* hw_interrupt_type */ -static struct hw_interrupt_type maskreg_irq_type = { - .typename = "Mask Register", - .startup = startup_maskreg_irq, - .shutdown = shutdown_maskreg_irq, - .enable = enable_maskreg_irq, - .disable = disable_maskreg_irq, - .ack = mask_and_ack_maskreg, - .end = end_maskreg_irq -}; - -/* actual implementatin */ -static unsigned int startup_maskreg_irq(unsigned int irq) -{ - enable_maskreg_irq(irq); - return 0; /* never anything pending */ -} - -static void shutdown_maskreg_irq(unsigned int irq) -{ - disable_maskreg_irq(irq); -} - -static void disable_maskreg_irq(unsigned int irq) -{ - unsigned short val, mask = 0x01 << irq; - - BUG_ON(!irq_mask_register); - - /* Set "irq"th bit */ - val = ctrl_inw(irq_mask_register); - val |= mask; - ctrl_outw(val, irq_mask_register); -} - -static void enable_maskreg_irq(unsigned int irq) -{ - unsigned short val, mask = ~(0x01 << irq); - - BUG_ON(!irq_mask_register); - - /* Clear "irq"th bit */ - val = ctrl_inw(irq_mask_register); - val &= mask; - ctrl_outw(val, irq_mask_register); -} - -static void mask_and_ack_maskreg(unsigned int irq) -{ - disable_maskreg_irq(irq); -} - -static void end_maskreg_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_maskreg_irq(irq); -} - -void make_maskreg_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].handler = &maskreg_irq_type; - disable_maskreg_irq(irq); -} diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c deleted file mode 100644 index 17f47b373d6..00000000000 --- a/arch/sh/kernel/cpu/irq/pint.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * arch/sh/kernel/cpu/irq/pint.c - Interrupt handling for PINT-based IRQs. - * - * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi - * Copyright (C) 2000 Kazumoto Kojima - * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/module.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/machvec.h> - -static unsigned char pint_map[256]; -static unsigned long portcr_mask; - -static void enable_pint_irq(unsigned int irq); -static void disable_pint_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_pint_irq disable_pint_irq - -static void mask_and_ack_pint(unsigned int); -static void end_pint_irq(unsigned int irq); - -static unsigned int startup_pint_irq(unsigned int irq) -{ - enable_pint_irq(irq); - return 0; /* never anything pending */ -} - -static struct hw_interrupt_type pint_irq_type = { - .typename = "PINT-IRQ", - .startup = startup_pint_irq, - .shutdown = shutdown_pint_irq, - .enable = enable_pint_irq, - .disable = disable_pint_irq, - .ack = mask_and_ack_pint, - .end = end_pint_irq -}; - -static void disable_pint_irq(unsigned int irq) -{ - unsigned long val; - - val = ctrl_inw(INTC_INTER); - val &= ~(1 << (irq - PINT_IRQ_BASE)); - ctrl_outw(val, INTC_INTER); /* disable PINTn */ - portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2); -} - -static void enable_pint_irq(unsigned int irq) -{ - unsigned long val; - - val = ctrl_inw(INTC_INTER); - val |= 1 << (irq - PINT_IRQ_BASE); - ctrl_outw(val, INTC_INTER); /* enable PINTn */ - portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2; -} - -static void mask_and_ack_pint(unsigned int irq) -{ - disable_pint_irq(irq); -} - -static void end_pint_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_pint_irq(irq); -} - -void make_pint_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].chip = &pint_irq_type; - disable_pint_irq(irq); -} - -void __init init_IRQ_pint(void) -{ - int i; - - make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY); - make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY); - - enable_irq(PINT0_IRQ); - enable_irq(PINT8_IRQ); - - for(i = 0; i < 16; i++) - make_pint_irq(PINT_IRQ_BASE + i); - - for(i = 0; i < 256; i++) { - if (i & 1) - pint_map[i] = 0; - else if (i & 2) - pint_map[i] = 1; - else if (i & 4) - pint_map[i] = 2; - else if (i & 8) - pint_map[i] = 3; - else if (i & 0x10) - pint_map[i] = 4; - else if (i & 0x20) - pint_map[i] = 5; - else if (i & 0x40) - pint_map[i] = 6; - else if (i & 0x80) - pint_map[i] = 7; - } -} - -int ipr_irq_demux(int irq) -{ - unsigned long creg, dreg, d, sav; - - if (irq == PINT0_IRQ) { -#if defined(CONFIG_CPU_SUBTYPE_SH7707) - creg = PORT_PACR; - dreg = PORT_PADR; -#else - creg = PORT_PCCR; - dreg = PORT_PCDR; -#endif - sav = ctrl_inw(creg); - ctrl_outw(sav | portcr_mask, creg); - d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & - ctrl_inw(INTC_INTER) & 0xff; - ctrl_outw(sav, creg); - - if (d == 0) - return irq; - - return PINT_IRQ_BASE + pint_map[d]; - } else if (irq == PINT8_IRQ) { -#if defined(CONFIG_CPU_SUBTYPE_SH7707) - creg = PORT_PBCR; - dreg = PORT_PBDR; -#else - creg = PORT_PFCR; - dreg = PORT_PFDR; -#endif - sav = ctrl_inw(creg); - ctrl_outw(sav | (portcr_mask >> 16), creg); - d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & - (ctrl_inw(INTC_INTER) >> 8) & 0xff; - ctrl_outw(sav, creg); - - if (d == 0) - return irq; - - return PINT_IRQ_BASE + 8 + pint_map[d]; - } - - return irq; -} - |
