aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2009-02-04 15:33:20 -0500
committerGrant Likely <grant.likely@secretlab.ca>2009-02-04 15:33:20 -0500
commit8f2558ded599c10d96a56fbf12849a27f6ab7997 (patch)
tree00e0893df8d0d5a4e9f726c65cce724a61c038ce /arch
parentbc4346fe2733dcca723d6b8f188bc44b54eac847 (diff)
powerpc/5200: Refactor mpc5200 interrupt controller driver
Rework the mpc5200-pic driver to simplify it and fix up the setting of desc->status when set_type is called for internal IRQs (so they are reported as level, not edge). The simplification is due to splitting off the handling of external IRQs into a separate block so they don't need to be handled as exceptions in the normal CRIT, MAIN and PERP paths. Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c147
1 files changed, 59 insertions, 88 deletions
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index c0a955920508..480f806fd0a9 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -190,10 +190,10 @@ static void mpc52xx_extirq_ack(unsigned int virq)
190 190
191static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) 191static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
192{ 192{
193 struct irq_desc *desc = get_irq_desc(virq);
194 u32 ctrl_reg, type; 193 u32 ctrl_reg, type;
195 int irq; 194 int irq;
196 int l2irq; 195 int l2irq;
196 void *handler = handle_level_irq;
197 197
198 irq = irq_map[virq].hwirq; 198 irq = irq_map[virq].hwirq;
199 l2irq = irq & MPC52xx_IRQ_L2_MASK; 199 l2irq = irq & MPC52xx_IRQ_L2_MASK;
@@ -201,32 +201,21 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
201 pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); 201 pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
202 202
203 switch (flow_type) { 203 switch (flow_type) {
204 case IRQF_TRIGGER_HIGH: 204 case IRQF_TRIGGER_HIGH: type = 0; break;
205 type = 0; 205 case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break;
206 break; 206 case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break;
207 case IRQF_TRIGGER_RISING: 207 case IRQF_TRIGGER_LOW: type = 3; break;
208 type = 1;
209 break;
210 case IRQF_TRIGGER_FALLING:
211 type = 2;
212 break;
213 case IRQF_TRIGGER_LOW:
214 type = 3;
215 break;
216 default: 208 default:
217 type = 0; 209 type = 0;
218 } 210 }
219 211
220 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
221 desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
222 if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
223 desc->status |= IRQ_LEVEL;
224
225 ctrl_reg = in_be32(&intr->ctrl); 212 ctrl_reg = in_be32(&intr->ctrl);
226 ctrl_reg &= ~(0x3 << (22 - (l2irq * 2))); 213 ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
227 ctrl_reg |= (type << (22 - (l2irq * 2))); 214 ctrl_reg |= (type << (22 - (l2irq * 2)));
228 out_be32(&intr->ctrl, ctrl_reg); 215 out_be32(&intr->ctrl, ctrl_reg);
229 216
217 __set_irq_handler_unlocked(virq, handler);
218
230 return 0; 219 return 0;
231} 220}
232 221
@@ -241,6 +230,11 @@ static struct irq_chip mpc52xx_extirq_irqchip = {
241/* 230/*
242 * Main interrupt irq_chip 231 * Main interrupt irq_chip
243 */ 232 */
233static int mpc52xx_null_set_type(unsigned int virq, unsigned int flow_type)
234{
235 return 0; /* Do nothing so that the sense mask will get updated */
236}
237
244static void mpc52xx_main_mask(unsigned int virq) 238static void mpc52xx_main_mask(unsigned int virq)
245{ 239{
246 int irq; 240 int irq;
@@ -268,6 +262,7 @@ static struct irq_chip mpc52xx_main_irqchip = {
268 .mask = mpc52xx_main_mask, 262 .mask = mpc52xx_main_mask,
269 .mask_ack = mpc52xx_main_mask, 263 .mask_ack = mpc52xx_main_mask,
270 .unmask = mpc52xx_main_unmask, 264 .unmask = mpc52xx_main_unmask,
265 .set_type = mpc52xx_null_set_type,
271}; 266};
272 267
273/* 268/*
@@ -300,6 +295,7 @@ static struct irq_chip mpc52xx_periph_irqchip = {
300 .mask = mpc52xx_periph_mask, 295 .mask = mpc52xx_periph_mask,
301 .mask_ack = mpc52xx_periph_mask, 296 .mask_ack = mpc52xx_periph_mask,
302 .unmask = mpc52xx_periph_unmask, 297 .unmask = mpc52xx_periph_unmask,
298 .set_type = mpc52xx_null_set_type,
303}; 299};
304 300
305/* 301/*
@@ -343,9 +339,19 @@ static struct irq_chip mpc52xx_sdma_irqchip = {
343 .mask = mpc52xx_sdma_mask, 339 .mask = mpc52xx_sdma_mask,
344 .unmask = mpc52xx_sdma_unmask, 340 .unmask = mpc52xx_sdma_unmask,
345 .ack = mpc52xx_sdma_ack, 341 .ack = mpc52xx_sdma_ack,
342 .set_type = mpc52xx_null_set_type,
346}; 343};
347 344
348/** 345/**
346 * mpc52xx_is_extirq - Returns true if hwirq number is for an external IRQ
347 */
348static int mpc52xx_is_extirq(int l1, int l2)
349{
350 return ((l1 == 0) && (l2 == 0)) ||
351 ((l1 == 1) && (l2 >= 1) && (l2 <= 3));
352}
353
354/**
349 * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property 355 * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
350 */ 356 */
351static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, 357static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
@@ -363,38 +369,23 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
363 369
364 intrvect_l1 = (int)intspec[0]; 370 intrvect_l1 = (int)intspec[0];
365 intrvect_l2 = (int)intspec[1]; 371 intrvect_l2 = (int)intspec[1];
366 intrvect_type = (int)intspec[2]; 372 intrvect_type = (int)intspec[2] & 0x3;
367 373
368 intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & 374 intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
369 MPC52xx_IRQ_L1_MASK; 375 MPC52xx_IRQ_L1_MASK;
370 intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK; 376 intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
371 377
372 pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
373 intrvect_l2);
374
375 *out_hwirq = intrvect_linux; 378 *out_hwirq = intrvect_linux;
376 *out_flags = mpc52xx_map_senses[intrvect_type]; 379 *out_flags = IRQ_TYPE_LEVEL_LOW;
380 if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2))
381 *out_flags = mpc52xx_map_senses[intrvect_type];
377 382
383 pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
384 intrvect_l2);
378 return 0; 385 return 0;
379} 386}
380 387
381/** 388/**
382 * mpc52xx_irqx_gettype - determine the IRQ sense type (level/edge)
383 *
384 * Only external IRQs need this.
385 */
386static int mpc52xx_irqx_gettype(int irq)
387{
388 int type;
389 u32 ctrl_reg;
390
391 ctrl_reg = in_be32(&intr->ctrl);
392 type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
393
394 return mpc52xx_map_senses[type];
395}
396
397/**
398 * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure 389 * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
399 */ 390 */
400static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, 391static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
@@ -402,68 +393,46 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
402{ 393{
403 int l1irq; 394 int l1irq;
404 int l2irq; 395 int l2irq;
405 struct irq_chip *good_irqchip; 396 struct irq_chip *irqchip;
406 void *good_handle; 397 void *hndlr;
407 int type; 398 int type;
399 u32 reg;
408 400
409 l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; 401 l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
410 l2irq = irq & MPC52xx_IRQ_L2_MASK; 402 l2irq = irq & MPC52xx_IRQ_L2_MASK;
411 403
412 /* 404 /*
413 * Most of ours IRQs will be level low 405 * External IRQs are handled differently by the hardware so they are
414 * Only external IRQs on some platform may be others 406 * handled by a dedicated irq_chip structure.
415 */ 407 */
416 type = IRQ_TYPE_LEVEL_LOW; 408 if (mpc52xx_is_extirq(l1irq, l2irq)) {
409 reg = in_be32(&intr->ctrl);
410 type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3];
411 if ((type == IRQ_TYPE_EDGE_FALLING) ||
412 (type == IRQ_TYPE_EDGE_RISING))
413 hndlr = handle_edge_irq;
414 else
415 hndlr = handle_level_irq;
416
417 set_irq_chip_and_handler(virq, &mpc52xx_extirq_irqchip, hndlr);
418 pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n",
419 __func__, l2irq, virq, (int)irq, type);
420 return 0;
421 }
417 422
423 /* It is an internal SOC irq. Choose the correct irq_chip */
418 switch (l1irq) { 424 switch (l1irq) {
419 case MPC52xx_IRQ_L1_CRIT: 425 case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
420 pr_debug("%s: Critical. l2=%x\n", __func__, l2irq); 426 case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
421 427 case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
422 BUG_ON(l2irq != 0);
423
424 type = mpc52xx_irqx_gettype(l2irq);
425 good_irqchip = &mpc52xx_extirq_irqchip;
426 break;
427
428 case MPC52xx_IRQ_L1_MAIN:
429 pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
430
431 if ((l2irq >= 1) && (l2irq <= 3)) {
432 type = mpc52xx_irqx_gettype(l2irq);
433 good_irqchip = &mpc52xx_extirq_irqchip;
434 } else {
435 good_irqchip = &mpc52xx_main_irqchip;
436 }
437 break;
438
439 case MPC52xx_IRQ_L1_PERP:
440 pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
441 good_irqchip = &mpc52xx_periph_irqchip;
442 break;
443
444 case MPC52xx_IRQ_L1_SDMA:
445 pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
446 good_irqchip = &mpc52xx_sdma_irqchip;
447 break;
448
449 default: 428 default:
450 pr_err("%s: invalid virq requested (0x%x)\n", __func__, virq); 429 pr_err("%s: invalid irq: virq=%i, l1=%i, l2=%i\n",
430 __func__, virq, l1irq, l2irq);
451 return -EINVAL; 431 return -EINVAL;
452 } 432 }
453 433
454 switch (type) { 434 set_irq_chip_and_handler(virq, irqchip, handle_level_irq);
455 case IRQ_TYPE_EDGE_FALLING: 435 pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq);
456 case IRQ_TYPE_EDGE_RISING:
457 good_handle = handle_edge_irq;
458 break;
459 default:
460 good_handle = handle_level_irq;
461 }
462
463 set_irq_chip_and_handler(virq, good_irqchip, good_handle);
464
465 pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
466 (int)irq, type);
467 436
468 return 0; 437 return 0;
469} 438}
@@ -502,6 +471,8 @@ void __init mpc52xx_init_irq(void)
502 panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " 471 panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. "
503 "Check node !"); 472 "Check node !");
504 473
474 pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr);
475
505 /* Disable all interrupt sources. */ 476 /* Disable all interrupt sources. */
506 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ 477 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
507 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ 478 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */