aboutsummaryrefslogtreecommitdiffstats
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/intc2.c138
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c102
2 files changed, 51 insertions, 189 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index e30e4b7aa70e..d4b2bb7e08c7 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -10,93 +10,32 @@
10 * These are the "new Hitachi style" interrupts, as present on the 10 * These are the "new Hitachi style" interrupts, as present on the
11 * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. 11 * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
12 */ 12 */
13
14#include <linux/kernel.h> 13#include <linux/kernel.h>
15#include <linux/init.h> 14#include <linux/init.h>
16#include <linux/irq.h> 15#include <linux/irq.h>
17#include <asm/system.h> 16#include <asm/system.h>
18#include <asm/io.h> 17#include <asm/io.h>
19#include <asm/machvec.h>
20
21struct intc2_data {
22 unsigned char msk_offset;
23 unsigned char msk_shift;
24
25 int (*clear_irq) (int);
26};
27
28static struct intc2_data intc2_data[NR_INTC2_IRQS];
29
30static void enable_intc2_irq(unsigned int irq);
31static void disable_intc2_irq(unsigned int irq);
32
33/* shutdown is same as "disable" */
34#define shutdown_intc2_irq disable_intc2_irq
35
36static void mask_and_ack_intc2(unsigned int);
37static void end_intc2_irq(unsigned int irq);
38
39static unsigned int startup_intc2_irq(unsigned int irq)
40{
41 enable_intc2_irq(irq);
42 return 0; /* never anything pending */
43}
44
45static struct hw_interrupt_type intc2_irq_type = {
46 .typename = "INTC2-IRQ",
47 .startup = startup_intc2_irq,
48 .shutdown = shutdown_intc2_irq,
49 .enable = enable_intc2_irq,
50 .disable = disable_intc2_irq,
51 .ack = mask_and_ack_intc2,
52 .end = end_intc2_irq
53};
54 18
55static void disable_intc2_irq(unsigned int irq) 19static void disable_intc2_irq(unsigned int irq)
56{ 20{
57 int irq_offset = irq - INTC2_FIRST_IRQ; 21 struct intc2_data *p = get_irq_chip_data(irq);
58 int msk_shift, msk_offset; 22 ctrl_outl(1 << p->msk_shift,
59 23 INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset);
60 /* Sanity check */
61 if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
62 return;
63
64 msk_shift = intc2_data[irq_offset].msk_shift;
65 msk_offset = intc2_data[irq_offset].msk_offset;
66
67 ctrl_outl(1 << msk_shift,
68 INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset);
69} 24}
70 25
71static void enable_intc2_irq(unsigned int irq) 26static void enable_intc2_irq(unsigned int irq)
72{ 27{
73 int irq_offset = irq - INTC2_FIRST_IRQ; 28 struct intc2_data *p = get_irq_chip_data(irq);
74 int msk_shift, msk_offset; 29 ctrl_outl(1 << p->msk_shift,
75 30 INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset);
76 /* Sanity check */
77 if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
78 return;
79
80 msk_shift = intc2_data[irq_offset].msk_shift;
81 msk_offset = intc2_data[irq_offset].msk_offset;
82
83 ctrl_outl(1 << msk_shift,
84 INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset);
85}
86
87static void mask_and_ack_intc2(unsigned int irq)
88{
89 disable_intc2_irq(irq);
90} 31}
91 32
92static void end_intc2_irq(unsigned int irq) 33static struct irq_chip intc2_irq_chip = {
93{ 34 .typename = "intc2",
94 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 35 .mask = disable_intc2_irq,
95 enable_intc2_irq(irq); 36 .unmask = enable_intc2_irq,
96 37 .mask_ack = disable_intc2_irq,
97 if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)) 38};
98 intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq);
99}
100 39
101/* 40/*
102 * Setup an INTC2 style interrupt. 41 * Setup an INTC2 style interrupt.
@@ -108,46 +47,30 @@ static void end_intc2_irq(unsigned int irq)
108 * | | | | 47 * | | | |
109 * make_intc2_irq(84, 0, 16, 0, 13); 48 * make_intc2_irq(84, 0, 16, 0, 13);
110 */ 49 */
111void make_intc2_irq(unsigned int irq, 50void make_intc2_irq(struct intc2_data *p)
112 unsigned int ipr_offset, unsigned int ipr_shift,
113 unsigned int msk_offset, unsigned int msk_shift,
114 unsigned int priority)
115{ 51{
116 int irq_offset = irq - INTC2_FIRST_IRQ;
117 unsigned int flags; 52 unsigned int flags;
118 unsigned long ipr; 53 unsigned long ipr;
119 54
120 if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) 55 disable_irq_nosync(p->irq);
121 return;
122
123 disable_irq_nosync(irq);
124
125 /* Fill the data we need */
126 intc2_data[irq_offset].msk_offset = msk_offset;
127 intc2_data[irq_offset].msk_shift = msk_shift;
128 intc2_data[irq_offset].clear_irq = NULL;
129 56
130 /* Set the priority level */ 57 /* Set the priority level */
131 local_irq_save(flags); 58 local_irq_save(flags);
132 59
133 ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset); 60 ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset);
134 ipr &= ~(0xf << ipr_shift); 61 ipr &= ~(0xf << p->ipr_shift);
135 ipr |= priority << ipr_shift; 62 ipr |= p->priority << p->ipr_shift;
136 ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset); 63 ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset);
137 64
138 local_irq_restore(flags); 65 local_irq_restore(flags);
139 66
140 irq_desc[irq].chip = &intc2_irq_type; 67 set_irq_chip_and_handler(p->irq, &intc2_irq_chip, handle_level_irq);
68 set_irq_chip_data(p->irq, p);
141 69
142 disable_intc2_irq(irq); 70 enable_intc2_irq(p->irq);
143} 71}
144 72
145static struct intc2_init { 73static struct intc2_data intc2_irq_table[] = {
146 unsigned short irq;
147 unsigned char ipr_offset, ipr_shift;
148 unsigned char msk_offset, msk_shift;
149 unsigned char priority;
150} intc2_init_data[] __initdata = {
151#if defined(CONFIG_CPU_SUBTYPE_ST40) 74#if defined(CONFIG_CPU_SUBTYPE_ST40)
152 {64, 0, 0, 0, 0, 13}, /* PCI serr */ 75 {64, 0, 0, 0, 0, 13}, /* PCI serr */
153 {65, 0, 4, 0, 1, 13}, /* PCI err */ 76 {65, 0, 4, 0, 1, 13}, /* PCI err */
@@ -266,19 +189,6 @@ void __init init_IRQ_intc2(void)
266{ 189{
267 int i; 190 int i;
268 191
269 for (i = 0; i < ARRAY_SIZE(intc2_init_data); i++) { 192 for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++)
270 struct intc2_init *p = intc2_init_data + i; 193 make_intc2_irq(intc2_irq_table + i);
271 make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
272 p-> msk_offset, p->msk_shift, p->priority);
273 }
274}
275
276/* Adds a termination callback to the interrupt */
277void intc2_add_clear_irq(int irq, int (*fn)(int))
278{
279 if (unlikely(irq < INTC2_FIRST_IRQ))
280 return;
281
282 intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
283} 194}
284
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index f785822cd5de..8944abdf6e1c 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -1,11 +1,10 @@
1/* 1/*
2 * arch/sh/kernel/cpu/irq/ipr.c 2 * Interrupt handling for IPR-based IRQ.
3 * 3 *
4 * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi 4 * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
5 * Copyright (C) 2000 Kazumoto Kojima 5 * Copyright (C) 2000 Kazumoto Kojima
6 * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> 6 * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
7 * 7 * Copyright (C) 2006 Paul Mundt
8 * Interrupt handling for IPR-based IRQ.
9 * 8 *
10 * Supported system: 9 * Supported system:
11 * On-chip supporting modules (TMU, RTC, etc.). 10 * On-chip supporting modules (TMU, RTC, etc.).
@@ -13,12 +12,13 @@
13 * Hitachi SolutionEngine external I/O: 12 * Hitachi SolutionEngine external I/O:
14 * MS7709SE01, MS7709ASE01, and MS7750SE01 13 * MS7709SE01, MS7709ASE01, and MS7750SE01
15 * 14 *
15 * This file is subject to the terms and conditions of the GNU General Public
16 * License. See the file "COPYING" in the main directory of this archive
17 * for more details.
16 */ 18 */
17
18#include <linux/init.h> 19#include <linux/init.h>
19#include <linux/irq.h> 20#include <linux/irq.h>
20#include <linux/module.h> 21#include <linux/module.h>
21
22#include <asm/system.h> 22#include <asm/system.h>
23#include <asm/io.h> 23#include <asm/io.h>
24#include <asm/machvec.h> 24#include <asm/machvec.h>
@@ -28,93 +28,45 @@ struct ipr_data {
28 int shift; /* Shifts of the 16-bit data */ 28 int shift; /* Shifts of the 16-bit data */
29 int priority; /* The priority */ 29 int priority; /* The priority */
30}; 30};
31static struct ipr_data ipr_data[NR_IRQS];
32
33static void enable_ipr_irq(unsigned int irq);
34static void disable_ipr_irq(unsigned int irq);
35
36/* shutdown is same as "disable" */
37#define shutdown_ipr_irq disable_ipr_irq
38
39static void mask_and_ack_ipr(unsigned int);
40static void end_ipr_irq(unsigned int irq);
41
42static unsigned int startup_ipr_irq(unsigned int irq)
43{
44 enable_ipr_irq(irq);
45 return 0; /* never anything pending */
46}
47
48static struct hw_interrupt_type ipr_irq_type = {
49 .typename = "IPR-IRQ",
50 .startup = startup_ipr_irq,
51 .shutdown = shutdown_ipr_irq,
52 .enable = enable_ipr_irq,
53 .disable = disable_ipr_irq,
54 .ack = mask_and_ack_ipr,
55 .end = end_ipr_irq
56};
57 31
58static void disable_ipr_irq(unsigned int irq) 32static void disable_ipr_irq(unsigned int irq)
59{ 33{
60 unsigned long val; 34 struct ipr_data *p = get_irq_chip_data(irq);
61 unsigned int addr = ipr_data[irq].addr;
62 unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
63
64 /* Set the priority in IPR to 0 */ 35 /* Set the priority in IPR to 0 */
65 val = ctrl_inw(addr); 36 ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr);
66 val &= mask;
67 ctrl_outw(val, addr);
68} 37}
69 38
70static void enable_ipr_irq(unsigned int irq) 39static void enable_ipr_irq(unsigned int irq)
71{ 40{
72 unsigned long val; 41 struct ipr_data *p = get_irq_chip_data(irq);
73 unsigned int addr = ipr_data[irq].addr;
74 int priority = ipr_data[irq].priority;
75 unsigned short value = (priority << ipr_data[irq].shift);
76
77 /* Set priority in IPR back to original value */ 42 /* Set priority in IPR back to original value */
78 val = ctrl_inw(addr); 43 ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr);
79 val |= value;
80 ctrl_outw(val, addr);
81} 44}
82 45
83static void mask_and_ack_ipr(unsigned int irq) 46static struct irq_chip ipr_irq_chip = {
84{ 47 .name = "ipr",
85 disable_ipr_irq(irq); 48 .mask = disable_ipr_irq,
86 49 .unmask = enable_ipr_irq,
87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 50 .mask_ack = disable_ipr_irq,
88 defined(CONFIG_CPU_SUBTYPE_SH7706) || \ 51};
89 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
90 /* This is needed when we use edge triggered setting */
91 /* XXX: Is it really needed? */
92 if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) {
93 /* Clear external interrupt request */
94 int a = ctrl_inb(INTC_IRR0);
95 a &= ~(1 << (irq - IRQ0_IRQ));
96 ctrl_outb(a, INTC_IRR0);
97 }
98#endif
99}
100
101static void end_ipr_irq(unsigned int irq)
102{
103 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
104 enable_ipr_irq(irq);
105}
106 52
107void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) 53void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
108{ 54{
55 struct ipr_data ipr_data;
56
109 disable_irq_nosync(irq); 57 disable_irq_nosync(irq);
110 ipr_data[irq].addr = addr;
111 ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
112 ipr_data[irq].priority = priority;
113 58
114 irq_desc[irq].chip = &ipr_irq_type; 59 ipr_data.addr = addr;
115 disable_ipr_irq(irq); 60 ipr_data.shift = pos*4; /* POSition (0-3) x 4 means shift */
61 ipr_data.priority = priority;
62
63 set_irq_chip_and_handler(irq, &ipr_irq_chip, handle_level_irq);
64 set_irq_chip_data(irq, &ipr_data);
65
66 enable_ipr_irq(irq);
116} 67}
117 68
69/* XXX: This needs to die a horrible death.. */
118void __init init_IRQ(void) 70void __init init_IRQ(void)
119{ 71{
120#ifndef CONFIG_CPU_SUBTYPE_SH7780 72#ifndef CONFIG_CPU_SUBTYPE_SH7780