aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/cpm2_pic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/cpm2_pic.c')
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c154
1 files changed, 90 insertions, 64 deletions
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 767ee6651adc..eabfe06fe05c 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -36,9 +36,20 @@
36#include <asm/mpc8260.h> 36#include <asm/mpc8260.h>
37#include <asm/io.h> 37#include <asm/io.h>
38#include <asm/prom.h> 38#include <asm/prom.h>
39#include <asm/fs_pd.h>
39 40
40#include "cpm2_pic.h" 41#include "cpm2_pic.h"
41 42
43/* External IRQS */
44#define CPM2_IRQ_EXT1 19
45#define CPM2_IRQ_EXT7 25
46
47/* Port C IRQS */
48#define CPM2_IRQ_PORTC15 48
49#define CPM2_IRQ_PORTC0 63
50
51static intctl_cpm2_t *cpm2_intctl;
52
42static struct device_node *cpm2_pic_node; 53static struct device_node *cpm2_pic_node;
43static struct irq_host *cpm2_pic_host; 54static struct irq_host *cpm2_pic_host;
44#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) 55#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
@@ -68,68 +79,55 @@ static const u_char irq_to_siubit[] = {
68 24, 25, 26, 27, 28, 29, 30, 31, 79 24, 25, 26, 27, 28, 29, 30, 31,
69}; 80};
70 81
71static void cpm2_mask_irq(unsigned int irq_nr) 82static void cpm2_mask_irq(unsigned int virq)
72{ 83{
73 int bit, word; 84 int bit, word;
74 volatile uint *simr; 85 unsigned int irq_nr = virq_to_hw(virq);
75
76 irq_nr -= CPM_IRQ_OFFSET;
77 86
78 bit = irq_to_siubit[irq_nr]; 87 bit = irq_to_siubit[irq_nr];
79 word = irq_to_siureg[irq_nr]; 88 word = irq_to_siureg[irq_nr];
80 89
81 simr = &(cpm2_intctl->ic_simrh);
82 ppc_cached_irq_mask[word] &= ~(1 << bit); 90 ppc_cached_irq_mask[word] &= ~(1 << bit);
83 simr[word] = ppc_cached_irq_mask[word]; 91 out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
84} 92}
85 93
86static void cpm2_unmask_irq(unsigned int irq_nr) 94static void cpm2_unmask_irq(unsigned int virq)
87{ 95{
88 int bit, word; 96 int bit, word;
89 volatile uint *simr; 97 unsigned int irq_nr = virq_to_hw(virq);
90
91 irq_nr -= CPM_IRQ_OFFSET;
92 98
93 bit = irq_to_siubit[irq_nr]; 99 bit = irq_to_siubit[irq_nr];
94 word = irq_to_siureg[irq_nr]; 100 word = irq_to_siureg[irq_nr];
95 101
96 simr = &(cpm2_intctl->ic_simrh);
97 ppc_cached_irq_mask[word] |= 1 << bit; 102 ppc_cached_irq_mask[word] |= 1 << bit;
98 simr[word] = ppc_cached_irq_mask[word]; 103 out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
99} 104}
100 105
101static void cpm2_mask_and_ack(unsigned int irq_nr) 106static void cpm2_ack(unsigned int virq)
102{ 107{
103 int bit, word; 108 int bit, word;
104 volatile uint *simr, *sipnr; 109 unsigned int irq_nr = virq_to_hw(virq);
105
106 irq_nr -= CPM_IRQ_OFFSET;
107 110
108 bit = irq_to_siubit[irq_nr]; 111 bit = irq_to_siubit[irq_nr];
109 word = irq_to_siureg[irq_nr]; 112 word = irq_to_siureg[irq_nr];
110 113
111 simr = &(cpm2_intctl->ic_simrh); 114 out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
112 sipnr = &(cpm2_intctl->ic_sipnrh);
113 ppc_cached_irq_mask[word] &= ~(1 << bit);
114 simr[word] = ppc_cached_irq_mask[word];
115 sipnr[word] = 1 << bit;
116} 115}
117 116
118static void cpm2_end_irq(unsigned int irq_nr) 117static void cpm2_end_irq(unsigned int virq)
119{ 118{
120 int bit, word; 119 int bit, word;
121 volatile uint *simr; 120 unsigned int irq_nr = virq_to_hw(virq);
122 121
123 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 122 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
124 && irq_desc[irq_nr].action) { 123 && irq_desc[irq_nr].action) {
125 124
126 irq_nr -= CPM_IRQ_OFFSET;
127 bit = irq_to_siubit[irq_nr]; 125 bit = irq_to_siubit[irq_nr];
128 word = irq_to_siureg[irq_nr]; 126 word = irq_to_siureg[irq_nr];
129 127
130 simr = &(cpm2_intctl->ic_simrh);
131 ppc_cached_irq_mask[word] |= 1 << bit; 128 ppc_cached_irq_mask[word] |= 1 << bit;
132 simr[word] = ppc_cached_irq_mask[word]; 129 out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
130
133 /* 131 /*
134 * Work around large numbers of spurious IRQs on PowerPC 82xx 132 * Work around large numbers of spurious IRQs on PowerPC 82xx
135 * systems. 133 * systems.
@@ -138,13 +136,59 @@ static void cpm2_end_irq(unsigned int irq_nr)
138 } 136 }
139} 137}
140 138
139static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
140{
141 unsigned int src = virq_to_hw(virq);
142 struct irq_desc *desc = get_irq_desc(virq);
143 unsigned int vold, vnew, edibit;
144
145 if (flow_type == IRQ_TYPE_NONE)
146 flow_type = IRQ_TYPE_LEVEL_LOW;
147
148 if (flow_type & IRQ_TYPE_EDGE_RISING) {
149 printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n",
150 flow_type);
151 return -EINVAL;
152 }
153
154 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
155 desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
156 if (flow_type & IRQ_TYPE_LEVEL_LOW) {
157 desc->status |= IRQ_LEVEL;
158 desc->handle_irq = handle_level_irq;
159 } else
160 desc->handle_irq = handle_edge_irq;
161
162 /* internal IRQ senses are LEVEL_LOW
163 * EXT IRQ and Port C IRQ senses are programmable
164 */
165 if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
166 edibit = (14 - (src - CPM2_IRQ_EXT1));
167 else
168 if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
169 edibit = (31 - (src - CPM2_IRQ_PORTC15));
170 else
171 return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
172
173 vold = in_be32(&cpm2_intctl->ic_siexr);
174
175 if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
176 vnew = vold | (1 << edibit);
177 else
178 vnew = vold & ~(1 << edibit);
179
180 if (vold != vnew)
181 out_be32(&cpm2_intctl->ic_siexr, vnew);
182 return 0;
183}
184
141static struct irq_chip cpm2_pic = { 185static struct irq_chip cpm2_pic = {
142 .typename = " CPM2 SIU ", 186 .typename = " CPM2 SIU ",
143 .enable = cpm2_unmask_irq, 187 .mask = cpm2_mask_irq,
144 .disable = cpm2_mask_irq,
145 .unmask = cpm2_unmask_irq, 188 .unmask = cpm2_unmask_irq,
146 .mask_ack = cpm2_mask_and_ack, 189 .ack = cpm2_ack,
147 .end = cpm2_end_irq, 190 .eoi = cpm2_end_irq,
191 .set_type = cpm2_set_irq_type,
148}; 192};
149 193
150unsigned int cpm2_get_irq(void) 194unsigned int cpm2_get_irq(void)
@@ -154,17 +198,17 @@ unsigned int cpm2_get_irq(void)
154 198
155 /* For CPM2, read the SIVEC register and shift the bits down 199 /* For CPM2, read the SIVEC register and shift the bits down
156 * to get the irq number. */ 200 * to get the irq number. */
157 bits = cpm2_intctl->ic_sivec; 201 bits = in_be32(&cpm2_intctl->ic_sivec);
158 irq = bits >> 26; 202 irq = bits >> 26;
159 203
160 if (irq == 0) 204 if (irq == 0)
161 return(-1); 205 return(-1);
162 return irq+CPM_IRQ_OFFSET; 206 return irq_linear_revmap(cpm2_pic_host, irq);
163} 207}
164 208
165static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) 209static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
166{ 210{
167 return cpm2_pic_node == NULL || cpm2_pic_node == node; 211 return cpm2_pic_node == node;
168} 212}
169 213
170static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, 214static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
@@ -177,39 +221,21 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
177 return 0; 221 return 0;
178} 222}
179 223
180static void cpm2_host_unmap(struct irq_host *h, unsigned int virq)
181{
182 /* Make sure irq is masked in hardware */
183 cpm2_mask_irq(virq);
184
185 /* remove chip and handler */
186 set_irq_chip_and_handler(virq, NULL, NULL);
187}
188
189static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, 224static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
190 u32 *intspec, unsigned int intsize, 225 u32 *intspec, unsigned int intsize,
191 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 226 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
192{ 227{
193 static const unsigned char map_cpm2_senses[4] = {
194 IRQ_TYPE_LEVEL_LOW,
195 IRQ_TYPE_LEVEL_HIGH,
196 IRQ_TYPE_EDGE_FALLING,
197 IRQ_TYPE_EDGE_RISING,
198 };
199
200 *out_hwirq = intspec[0]; 228 *out_hwirq = intspec[0];
201 if (intsize > 1 && intspec[1] < 4) 229 if (intsize > 1)
202 *out_flags = map_cpm2_senses[intspec[1]]; 230 *out_flags = intspec[1];
203 else 231 else
204 *out_flags = IRQ_TYPE_NONE; 232 *out_flags = IRQ_TYPE_NONE;
205
206 return 0; 233 return 0;
207} 234}
208 235
209static struct irq_host_ops cpm2_pic_host_ops = { 236static struct irq_host_ops cpm2_pic_host_ops = {
210 .match = cpm2_pic_host_match, 237 .match = cpm2_pic_host_match,
211 .map = cpm2_pic_host_map, 238 .map = cpm2_pic_host_map,
212 .unmap = cpm2_host_unmap,
213 .xlate = cpm2_pic_host_xlate, 239 .xlate = cpm2_pic_host_xlate,
214}; 240};
215 241
@@ -217,37 +243,37 @@ void cpm2_pic_init(struct device_node *node)
217{ 243{
218 int i; 244 int i;
219 245
246 cpm2_intctl = cpm2_map(im_intctl);
247
220 /* Clear the CPM IRQ controller, in case it has any bits set 248 /* Clear the CPM IRQ controller, in case it has any bits set
221 * from the bootloader 249 * from the bootloader
222 */ 250 */
223 251
224 /* Mask out everything */ 252 /* Mask out everything */
225 253
226 cpm2_intctl->ic_simrh = 0x00000000; 254 out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
227 cpm2_intctl->ic_simrl = 0x00000000; 255 out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
228 256
229 wmb(); 257 wmb();
230 258
231 /* Ack everything */ 259 /* Ack everything */
232 cpm2_intctl->ic_sipnrh = 0xffffffff; 260 out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
233 cpm2_intctl->ic_sipnrl = 0xffffffff; 261 out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
234 wmb(); 262 wmb();
235 263
236 /* Dummy read of the vector */ 264 /* Dummy read of the vector */
237 i = cpm2_intctl->ic_sivec; 265 i = in_be32(&cpm2_intctl->ic_sivec);
238 rmb(); 266 rmb();
239 267
240 /* Initialize the default interrupt mapping priorities, 268 /* Initialize the default interrupt mapping priorities,
241 * in case the boot rom changed something on us. 269 * in case the boot rom changed something on us.
242 */ 270 */
243 cpm2_intctl->ic_sicr = 0; 271 out_be16(&cpm2_intctl->ic_sicr, 0);
244 cpm2_intctl->ic_scprrh = 0x05309770; 272 out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
245 cpm2_intctl->ic_scprrl = 0x05309770; 273 out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
246 274
247 /* create a legacy host */ 275 /* create a legacy host */
248 if (node) 276 cpm2_pic_node = of_node_get(node);
249 cpm2_pic_node = of_node_get(node);
250
251 cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64); 277 cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64);
252 if (cpm2_pic_host == NULL) { 278 if (cpm2_pic_host == NULL) {
253 printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); 279 printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");