diff options
Diffstat (limited to 'arch/sh/kernel/cpu/irq/ipr.c')
-rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 183 |
1 files changed, 63 insertions, 120 deletions
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index f785822cd5de..a0089563cbfc 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,151 +12,92 @@ | |||
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> |
25 | 25 | ||
26 | struct ipr_data { | ||
27 | unsigned int addr; /* Address of Interrupt Priority Register */ | ||
28 | int shift; /* Shifts of the 16-bit data */ | ||
29 | int priority; /* The priority */ | ||
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 | 26 | ||
58 | static void disable_ipr_irq(unsigned int irq) | 27 | static void disable_ipr_irq(unsigned int irq) |
59 | { | 28 | { |
60 | unsigned long val; | 29 | struct ipr_data *p = get_irq_chip_data(irq); |
61 | unsigned int addr = ipr_data[irq].addr; | 30 | int shift = p->shift*4; |
62 | unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); | ||
63 | |||
64 | /* Set the priority in IPR to 0 */ | 31 | /* Set the priority in IPR to 0 */ |
65 | val = ctrl_inw(addr); | 32 | ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << shift)), p->addr); |
66 | val &= mask; | ||
67 | ctrl_outw(val, addr); | ||
68 | } | 33 | } |
69 | 34 | ||
70 | static void enable_ipr_irq(unsigned int irq) | 35 | static void enable_ipr_irq(unsigned int irq) |
71 | { | 36 | { |
72 | unsigned long val; | 37 | struct ipr_data *p = get_irq_chip_data(irq); |
73 | unsigned int addr = ipr_data[irq].addr; | 38 | int shift = p->shift*4; |
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 */ | 39 | /* Set priority in IPR back to original value */ |
78 | val = ctrl_inw(addr); | 40 | ctrl_outw(ctrl_inw(p->addr) | (p->priority << shift), p->addr); |
79 | val |= value; | ||
80 | ctrl_outw(val, addr); | ||
81 | } | 41 | } |
82 | 42 | ||
83 | static void mask_and_ack_ipr(unsigned int irq) | 43 | static struct irq_chip ipr_irq_chip = { |
84 | { | 44 | .name = "IPR", |
85 | disable_ipr_irq(irq); | 45 | .mask = disable_ipr_irq, |
86 | 46 | .unmask = enable_ipr_irq, | |
87 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | 47 | .mask_ack = disable_ipr_irq, |
88 | defined(CONFIG_CPU_SUBTYPE_SH7706) || \ | 48 | }; |
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 | 49 | ||
101 | static void end_ipr_irq(unsigned int irq) | 50 | void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) |
102 | { | 51 | { |
103 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | 52 | int i; |
53 | |||
54 | for (i = 0; i < nr_irqs; i++) { | ||
55 | unsigned int irq = table[i].irq; | ||
56 | disable_irq_nosync(irq); | ||
57 | set_irq_chip_and_handler_name(irq, &ipr_irq_chip, | ||
58 | handle_level_irq, "level"); | ||
59 | set_irq_chip_data(irq, &table[i]); | ||
104 | enable_ipr_irq(irq); | 60 | enable_ipr_irq(irq); |
61 | } | ||
105 | } | 62 | } |
63 | EXPORT_SYMBOL(make_ipr_irq); | ||
106 | 64 | ||
107 | void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) | 65 | static struct ipr_data sys_ipr_map[] = { |
108 | { | ||
109 | 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 | |||
114 | irq_desc[irq].chip = &ipr_irq_type; | ||
115 | disable_ipr_irq(irq); | ||
116 | } | ||
117 | |||
118 | void __init init_IRQ(void) | ||
119 | { | ||
120 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 | 66 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 |
121 | make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); | 67 | { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY }, |
122 | make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); | 68 | { TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY }, |
123 | #ifdef RTC_IRQ | 69 | #ifdef RTC_IRQ |
124 | make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); | 70 | { RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY }, |
125 | #endif | 71 | #endif |
126 | |||
127 | #ifdef SCI_ERI_IRQ | 72 | #ifdef SCI_ERI_IRQ |
128 | make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | 73 | { SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, |
129 | make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | 74 | { SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, |
130 | make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | 75 | { SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, |
131 | #endif | 76 | #endif |
132 | |||
133 | #ifdef SCIF1_ERI_IRQ | 77 | #ifdef SCIF1_ERI_IRQ |
134 | make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | 78 | { SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, |
135 | make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | 79 | { SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, |
136 | make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | 80 | { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, |
137 | make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | 81 | { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, |
138 | #endif | 82 | #endif |
139 | |||
140 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | 83 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) |
141 | make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY); | 84 | { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY }, |
142 | make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | 85 | { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, |
143 | make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | 86 | { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, |
144 | make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | 87 | { VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY }, |
145 | #endif | 88 | #endif |
146 | |||
147 | #ifdef SCIF_ERI_IRQ | 89 | #ifdef SCIF_ERI_IRQ |
148 | make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | 90 | { SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, |
149 | make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | 91 | { SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, |
150 | make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | 92 | { SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, |
151 | make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | 93 | { SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, |
152 | #endif | 94 | #endif |
153 | |||
154 | #ifdef IRDA_ERI_IRQ | 95 | #ifdef IRDA_ERI_IRQ |
155 | make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | 96 | { IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, |
156 | make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | 97 | { IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, |
157 | make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | 98 | { IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, |
158 | make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | 99 | { IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, |
159 | #endif | 100 | #endif |
160 | |||
161 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | 101 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ |
162 | defined(CONFIG_CPU_SUBTYPE_SH7706) || \ | 102 | defined(CONFIG_CPU_SUBTYPE_SH7706) || \ |
163 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | 103 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) |
@@ -171,14 +111,19 @@ void __init init_IRQ(void) | |||
171 | * You should set corresponding bits of PFC to "00" | 111 | * You should set corresponding bits of PFC to "00" |
172 | * to enable these interrupts. | 112 | * to enable these interrupts. |
173 | */ | 113 | */ |
174 | make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY); | 114 | { IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY }, |
175 | make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY); | 115 | { IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY }, |
176 | make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY); | 116 | { IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY }, |
177 | make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY); | 117 | { IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY }, |
178 | make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY); | 118 | { IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY }, |
179 | make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY); | 119 | { IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY }, |
180 | #endif | 120 | #endif |
181 | #endif | 121 | #endif |
122 | }; | ||
123 | |||
124 | void __init init_IRQ(void) | ||
125 | { | ||
126 | make_ipr_irq(sys_ipr_map, ARRAY_SIZE(sys_ipr_map)); | ||
182 | 127 | ||
183 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | 128 | #ifdef CONFIG_CPU_HAS_PINT_IRQ |
184 | init_IRQ_pint(); | 129 | init_IRQ_pint(); |
@@ -200,5 +145,3 @@ int ipr_irq_demux(int irq) | |||
200 | return irq; | 145 | return irq; |
201 | } | 146 | } |
202 | #endif | 147 | #endif |
203 | |||
204 | EXPORT_SYMBOL(make_ipr_irq); | ||