diff options
Diffstat (limited to 'arch/sh/kernel/cpu/irq')
-rw-r--r-- | arch/sh/kernel/cpu/irq/intc2.c | 138 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 102 |
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 | |||
21 | struct intc2_data { | ||
22 | unsigned char msk_offset; | ||
23 | unsigned char msk_shift; | ||
24 | |||
25 | int (*clear_irq) (int); | ||
26 | }; | ||
27 | |||
28 | static struct intc2_data intc2_data[NR_INTC2_IRQS]; | ||
29 | |||
30 | static void enable_intc2_irq(unsigned int irq); | ||
31 | static void disable_intc2_irq(unsigned int irq); | ||
32 | |||
33 | /* shutdown is same as "disable" */ | ||
34 | #define shutdown_intc2_irq disable_intc2_irq | ||
35 | |||
36 | static void mask_and_ack_intc2(unsigned int); | ||
37 | static void end_intc2_irq(unsigned int irq); | ||
38 | |||
39 | static unsigned int startup_intc2_irq(unsigned int irq) | ||
40 | { | ||
41 | enable_intc2_irq(irq); | ||
42 | return 0; /* never anything pending */ | ||
43 | } | ||
44 | |||
45 | static 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 | ||
55 | static void disable_intc2_irq(unsigned int irq) | 19 | static 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 | ||
71 | static void enable_intc2_irq(unsigned int irq) | 26 | static 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 | |||
87 | static void mask_and_ack_intc2(unsigned int irq) | ||
88 | { | ||
89 | disable_intc2_irq(irq); | ||
90 | } | 31 | } |
91 | 32 | ||
92 | static void end_intc2_irq(unsigned int irq) | 33 | static 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 | */ |
111 | void make_intc2_irq(unsigned int irq, | 50 | void 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 | ||
145 | static struct intc2_init { | 73 | static 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 */ | ||
277 | void 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 | }; |
31 | static struct ipr_data ipr_data[NR_IRQS]; | ||
32 | |||
33 | static void enable_ipr_irq(unsigned int irq); | ||
34 | static void disable_ipr_irq(unsigned int irq); | ||
35 | |||
36 | /* shutdown is same as "disable" */ | ||
37 | #define shutdown_ipr_irq disable_ipr_irq | ||
38 | |||
39 | static void mask_and_ack_ipr(unsigned int); | ||
40 | static void end_ipr_irq(unsigned int irq); | ||
41 | |||
42 | static unsigned int startup_ipr_irq(unsigned int irq) | ||
43 | { | ||
44 | enable_ipr_irq(irq); | ||
45 | return 0; /* never anything pending */ | ||
46 | } | ||
47 | |||
48 | static 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 | ||
58 | static void disable_ipr_irq(unsigned int irq) | 32 | static 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 | ||
70 | static void enable_ipr_irq(unsigned int irq) | 39 | static 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 | ||
83 | static void mask_and_ack_ipr(unsigned int irq) | 46 | static 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 | |||
101 | static 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 | ||
107 | void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) | 53 | void 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.. */ | ||
118 | void __init init_IRQ(void) | 70 | void __init init_IRQ(void) |
119 | { | 71 | { |
120 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 | 72 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 |