summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/cpu/irq
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/irq')
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile2
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c63
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c61
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c220
4 files changed, 63 insertions, 283 deletions
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 1c23308cfc25..60bfc05cf354 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -4,6 +4,6 @@
obj-y += imask.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
-obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
+obj-$(CONFIG_CPU_HAS_INTC_IRQ) += intc.o
obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index d8e22f4ff0f0..cc5221390e09 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -13,36 +13,31 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <asm/smp.h>
-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
-#define INTC2_BASE 0xfe080000
-#define INTC2_INTMSK (INTC2_BASE + 0x40)
-#define INTC2_INTMSKCLR (INTC2_BASE + 0x60)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785)
-#define INTC2_BASE 0xffd40000
-#define INTC2_INTMSK (INTC2_BASE + 0x38)
-#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c)
-#endif
+static inline struct intc2_desc *get_intc2_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+ return (void *)((char *)chip - offsetof(struct intc2_desc, chip));
+}
static void disable_intc2_irq(unsigned int irq)
{
struct intc2_data *p = get_irq_chip_data(irq);
- ctrl_outl(1 << p->msk_shift, INTC2_INTMSK + p->msk_offset);
+ struct intc2_desc *d = get_intc2_desc(irq);
+
+ ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset +
+ (hard_smp_processor_id() * 4));
}
static void enable_intc2_irq(unsigned int irq)
{
struct intc2_data *p = get_irq_chip_data(irq);
- ctrl_outl(1 << p->msk_shift, INTC2_INTMSKCLR + p->msk_offset);
-}
+ struct intc2_desc *d = get_intc2_desc(irq);
-static struct irq_chip intc2_irq_chip = {
- .name = "INTC2",
- .mask = disable_intc2_irq,
- .unmask = enable_intc2_irq,
- .mask_ack = disable_intc2_irq,
-};
+ ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset +
+ (hard_smp_processor_id() * 4));
+}
/*
* Setup an INTC2 style interrupt.
@@ -56,30 +51,36 @@ static struct irq_chip intc2_irq_chip = {
*
* in the intc2_data table.
*/
-void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs)
+void register_intc2_controller(struct intc2_desc *desc)
{
int i;
- for (i = 0; i < nr_irqs; i++) {
+ desc->chip.mask = disable_intc2_irq;
+ desc->chip.unmask = enable_intc2_irq;
+ desc->chip.mask_ack = disable_intc2_irq;
+
+ for (i = 0; i < desc->nr_irqs; i++) {
unsigned long ipr, flags;
- struct intc2_data *p = table + i;
+ struct intc2_data *p = desc->intc2_data + i;
disable_irq_nosync(p->irq);
- /* Set the priority level */
- local_irq_save(flags);
+ if (desc->prio_base) {
+ /* Set the priority level */
+ local_irq_save(flags);
- ipr = ctrl_inl(INTC2_BASE + p->ipr_offset);
- ipr &= ~(0xf << p->ipr_shift);
- ipr |= p->priority << p->ipr_shift;
- ctrl_outl(ipr, INTC2_BASE + p->ipr_offset);
+ ipr = ctrl_inl(desc->prio_base + p->ipr_offset);
+ ipr &= ~(0xf << p->ipr_shift);
+ ipr |= p->priority << p->ipr_shift;
+ ctrl_outl(ipr, desc->prio_base + p->ipr_offset);
- local_irq_restore(flags);
+ local_irq_restore(flags);
+ }
- set_irq_chip_and_handler_name(p->irq, &intc2_irq_chip,
+ set_irq_chip_and_handler_name(p->irq, &desc->chip,
handle_level_irq, "level");
set_irq_chip_data(p->irq, p);
- enable_intc2_irq(p->irq);
+ disable_intc2_irq(p->irq);
}
}
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 210280b6fddf..5da325414880 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -8,7 +8,7 @@
*
* 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
*
@@ -22,58 +22,57 @@
#include <linux/io.h>
#include <linux/interrupt.h>
+static inline struct ipr_desc *get_ipr_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+ return (void *)((char *)chip - offsetof(struct ipr_desc, chip));
+}
+
static void disable_ipr_irq(unsigned int irq)
{
struct ipr_data *p = get_irq_chip_data(irq);
+ unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
/* Set the priority in IPR to 0 */
- ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr);
+ ctrl_outw(ctrl_inw(addr) & (0xffff ^ (0xf << p->shift)), addr);
}
static void enable_ipr_irq(unsigned int irq)
{
struct ipr_data *p = get_irq_chip_data(irq);
+ unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
/* Set priority in IPR back to original value */
- ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr);
+ ctrl_outw(ctrl_inw(addr) | (p->priority << p->shift), addr);
}
-static struct irq_chip ipr_irq_chip = {
- .name = "IPR",
- .mask = disable_ipr_irq,
- .unmask = enable_ipr_irq,
- .mask_ack = disable_ipr_irq,
-};
-
-unsigned int map_ipridx_to_addr(int idx) __attribute__ ((weak));
-unsigned int map_ipridx_to_addr(int idx)
-{
- return 0;
-}
+/*
+ * 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 make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
+void register_ipr_controller(struct ipr_desc *desc)
{
int i;
- for (i = 0; i < nr_irqs; i++) {
- unsigned int irq = table[i].irq;
+ desc->chip.mask = disable_ipr_irq;
+ desc->chip.unmask = enable_ipr_irq;
+ desc->chip.mask_ack = disable_ipr_irq;
- if (!irq)
- irq = table[i].irq = i;
+ for (i = 0; i < desc->nr_irqs; i++) {
+ struct ipr_data *p = desc->ipr_data + i;
- /* could the IPR index be mapped, if not we ignore this */
- if (!table[i].addr) {
- table[i].addr = map_ipridx_to_addr(table[i].ipr_idx);
- if (!table[i].addr)
- continue;
- }
+ BUG_ON(p->ipr_idx >= desc->nr_offsets);
+ BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
- disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &ipr_irq_chip,
+ disable_irq_nosync(p->irq);
+ set_irq_chip_and_handler_name(p->irq, &desc->chip,
handle_level_irq, "level");
- set_irq_chip_data(irq, &table[i]);
- enable_ipr_irq(irq);
+ set_irq_chip_data(p->irq, p);
+ disable_ipr_irq(p->irq);
}
}
-EXPORT_SYMBOL(make_ipr_irq);
+
+EXPORT_SYMBOL(register_ipr_controller);
#if !defined(CONFIG_CPU_HAS_PINT_IRQ)
int ipr_irq_demux(int irq)
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
deleted file mode 100644
index 67602685df1a..000000000000
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ /dev/null
@@ -1,220 +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>
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
-#define INTC_INTER 0xA4000014UL
-#define INTC_IPRD 0xA4000018UL
-#define INTC_ICR2 0xA4000012UL
-
-/* PFC */
-#define PORT_PACR 0xA4000100UL
-#define PORT_PBCR 0xA4000102UL
-#define PORT_PCCR 0xA4000104UL
-#define PORT_PDCR 0xA4000106UL
-#define PORT_PECR 0xA4000108UL
-#define PORT_PFCR 0xA400010AUL
-#define PORT_PGCR 0xA400010CUL
-#define PORT_PHCR 0xA400010EUL
-#define PORT_PJCR 0xA4000110UL
-#define PORT_PKCR 0xA4000112UL
-#define PORT_PLCR 0xA4000114UL
-#define PORT_PMCR 0xA4000118UL
-#define PORT_PNCR 0xA400011AUL
-#define PORT_PECR2 0xA4050148UL
-#define PORT_PFCR2 0xA405014AUL
-#define PORT_PNCR2 0xA405015AUL
-
-/* I/O port */
-#define PORT_PADR 0xA4000120UL
-#define PORT_PBDR 0xA4000122UL
-#define PORT_PCDR 0xA4000124UL
-#define PORT_PDDR 0xA4000126UL
-#define PORT_PEDR 0xA4000128UL
-#define PORT_PFDR 0xA400012AUL
-#define PORT_PGDR 0xA400012CUL
-#define PORT_PHDR 0xA400012EUL
-#define PORT_PJDR 0xA4000130UL
-#define PORT_PKDR 0xA4000132UL
-#define PORT_PLDR 0xA4000134UL
-#define PORT_PMDR 0xA4000138UL
-#define PORT_PNDR 0xA400013AUL
-
-#define PINT0_IRQ 40
-#define PINT8_IRQ 41
-#define PINT_IRQ_BASE 86
-
-#define PINT0_IPR_ADDR INTC_IPRD
-#define PINT0_IPR_POS 3
-#define PINT0_PRIORITY 2
-
-#define PINT8_IPR_ADDR INTC_IPRD
-#define PINT8_IPR_POS 2
-#define PINT8_PRIORITY 2
-
-#endif /* CONFIG_CPU_SUBTYPE_SH7705 */
-
-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);
-}
-
-static struct ipr_data pint_ipr_map[] = {
- { PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY },
- { PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY },
-};
-
-void __init init_IRQ_pint(void)
-{
- int i;
-
- make_ipr_irq(pint_ipr_map, ARRAY_SIZE(pint_ipr_map));
-
- 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_SH7705) || 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_SH7705) || 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;
-}
-