aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/irq/intc.c
diff options
context:
space:
mode:
authorMagnus Damm <magnus.damm@gmail.com>2008-04-24 08:36:34 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-05-08 06:52:03 -0400
commitd58876e289b0153bf86162aa1a43249e0f0aa03d (patch)
treebcba99bfb89b61142a81a651958c10e4c9828778 /arch/sh/kernel/cpu/irq/intc.c
parenta276e588a92737889c21e736f2bbed8aecda25fb (diff)
sh: add interrupt ack code to sh3
This patch adds interrupt acknowledge code for external interrupt sources on sh3 processors. Only really required for edge triggered interrupts, but we ack regardless of sense configuration. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/irq/intc.c')
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c79
1 files changed, 76 insertions, 3 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 84806b2027f..df3695406d8 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Shared interrupt handling code for IPR and INTC2 types of IRQs. 2 * Shared interrupt handling code for IPR and INTC2 types of IRQs.
3 * 3 *
4 * Copyright (C) 2007 Magnus Damm 4 * Copyright (C) 2007, 2008 Magnus Damm
5 * 5 *
6 * Based on intc2.c and ipr.c 6 * Based on intc2.c and ipr.c
7 * 7 *
@@ -62,6 +62,9 @@ struct intc_desc_int {
62#endif 62#endif
63 63
64static unsigned int intc_prio_level[NR_IRQS]; /* for now */ 64static unsigned int intc_prio_level[NR_IRQS]; /* for now */
65#ifdef CONFIG_CPU_SH3
66static unsigned long ack_handle[NR_IRQS];
67#endif
65 68
66static inline struct intc_desc_int *get_intc_desc(unsigned int irq) 69static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
67{ 70{
@@ -219,6 +222,25 @@ static void intc_disable(unsigned int irq)
219 } 222 }
220} 223}
221 224
225#ifdef CONFIG_CPU_SH3
226static void intc_mask_ack(unsigned int irq)
227{
228 struct intc_desc_int *d = get_intc_desc(irq);
229 unsigned long handle = ack_handle[irq];
230 unsigned long addr;
231
232 intc_disable(irq);
233
234 /* read register and write zero only to the assocaited bit */
235
236 if (handle) {
237 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
238 ctrl_inb(addr);
239 ctrl_outb(0x3f ^ set_field(0, 1, handle), addr);
240 }
241}
242#endif
243
222static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, 244static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
223 unsigned int nr_hp, 245 unsigned int nr_hp,
224 unsigned int irq) 246 unsigned int irq)
@@ -430,6 +452,40 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
430 return 0; 452 return 0;
431} 453}
432 454
455#ifdef CONFIG_CPU_SH3
456static unsigned int __init intc_ack_data(struct intc_desc *desc,
457 struct intc_desc_int *d,
458 intc_enum enum_id)
459{
460 struct intc_mask_reg *mr = desc->ack_regs;
461 unsigned int i, j, fn, mode;
462 unsigned long reg_e, reg_d;
463
464 for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) {
465 mr = desc->ack_regs + i;
466
467 for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
468 if (mr->enum_ids[j] != enum_id)
469 continue;
470
471 fn = REG_FN_MODIFY_BASE;
472 mode = MODE_ENABLE_REG;
473 reg_e = mr->set_reg;
474 reg_d = mr->set_reg;
475
476 fn += (mr->reg_width >> 3) - 1;
477 return _INTC_MK(fn, mode,
478 intc_get_reg(d, reg_e),
479 intc_get_reg(d, reg_d),
480 1,
481 (mr->reg_width - 1) - j);
482 }
483 }
484
485 return 0;
486}
487#endif
488
433static unsigned int __init intc_sense_data(struct intc_desc *desc, 489static unsigned int __init intc_sense_data(struct intc_desc *desc,
434 struct intc_desc_int *d, 490 struct intc_desc_int *d,
435 intc_enum enum_id) 491 intc_enum enum_id)
@@ -530,6 +586,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
530 586
531 /* irq should be disabled by default */ 587 /* irq should be disabled by default */
532 d->chip.mask(irq); 588 d->chip.mask(irq);
589
590#ifdef CONFIG_CPU_SH3
591 if (desc->ack_regs)
592 ack_handle[irq] = intc_ack_data(desc, d, enum_id);
593#endif
533} 594}
534 595
535static unsigned int __init save_reg(struct intc_desc_int *d, 596static unsigned int __init save_reg(struct intc_desc_int *d,
@@ -560,6 +621,9 @@ void __init register_intc_controller(struct intc_desc *desc)
560 d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; 621 d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
561 d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; 622 d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
562 623
624#ifdef CONFIG_CPU_SH3
625 d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
626#endif
563 d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg)); 627 d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
564#ifdef CONFIG_SMP 628#ifdef CONFIG_SMP
565 d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp)); 629 d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
@@ -592,14 +656,23 @@ void __init register_intc_controller(struct intc_desc *desc)
592 } 656 }
593 } 657 }
594 658
595 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
596
597 d->chip.name = desc->name; 659 d->chip.name = desc->name;
598 d->chip.mask = intc_disable; 660 d->chip.mask = intc_disable;
599 d->chip.unmask = intc_enable; 661 d->chip.unmask = intc_enable;
600 d->chip.mask_ack = intc_disable; 662 d->chip.mask_ack = intc_disable;
601 d->chip.set_type = intc_set_sense; 663 d->chip.set_type = intc_set_sense;
602 664
665#ifdef CONFIG_CPU_SH3
666 if (desc->ack_regs) {
667 for (i = 0; i < desc->nr_ack_regs; i++)
668 k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
669
670 d->chip.mask_ack = intc_mask_ack;
671 }
672#endif
673
674 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
675
603 for (i = 0; i < desc->nr_vectors; i++) { 676 for (i = 0; i < desc->nr_vectors; i++) {
604 struct intc_vect *vect = desc->vectors + i; 677 struct intc_vect *vect = desc->vectors + i;
605 678