Commit d58876e289b0153bf86162aa1a43249e0f0aa03d

Authored by Magnus Damm
Committed by Paul Mundt
1 parent a276e588a9

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>

Showing 3 changed files with 103 additions and 7 deletions Side-by-side Diff

arch/sh/kernel/cpu/irq/intc.c
1 1 /*
2 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 6 * Based on intc2.c and ipr.c
7 7 *
... ... @@ -62,6 +62,9 @@
62 62 #endif
63 63  
64 64 static unsigned int intc_prio_level[NR_IRQS]; /* for now */
  65 +#ifdef CONFIG_CPU_SH3
  66 +static unsigned long ack_handle[NR_IRQS];
  67 +#endif
65 68  
66 69 static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
67 70 {
... ... @@ -219,6 +222,25 @@
219 222 }
220 223 }
221 224  
  225 +#ifdef CONFIG_CPU_SH3
  226 +static 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 +
222 244 static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
223 245 unsigned int nr_hp,
224 246 unsigned int irq)
... ... @@ -430,6 +452,40 @@
430 452 return 0;
431 453 }
432 454  
  455 +#ifdef CONFIG_CPU_SH3
  456 +static 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 +
433 489 static unsigned int __init intc_sense_data(struct intc_desc *desc,
434 490 struct intc_desc_int *d,
435 491 intc_enum enum_id)
... ... @@ -530,6 +586,11 @@
530 586  
531 587 /* irq should be disabled by default */
532 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  
535 596 static unsigned int __init save_reg(struct intc_desc_int *d,
... ... @@ -560,6 +621,9 @@
560 621 d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
561 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 627 d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
564 628 #ifdef CONFIG_SMP
565 629 d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
566 630  
... ... @@ -592,13 +656,22 @@
592 656 }
593 657 }
594 658  
595   - BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
596   -
597 659 d->chip.name = desc->name;
598 660 d->chip.mask = intc_disable;
599 661 d->chip.unmask = intc_enable;
600 662 d->chip.mask_ack = intc_disable;
601 663 d->chip.set_type = intc_set_sense;
  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 */
602 675  
603 676 for (i = 0; i < desc->nr_vectors; i++) {
604 677 struct intc_vect *vect = desc->vectors + i;
arch/sh/kernel/cpu/sh3/setup-sh3.c
... ... @@ -35,15 +35,22 @@
35 35 { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
36 36 };
37 37  
  38 +static struct intc_mask_reg ack_registers[] __initdata = {
  39 + { 0xa4000004, 0, 8, /* IRR0 */
  40 + { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
  41 +};
  42 +
38 43 static struct intc_sense_reg sense_registers[] __initdata = {
39 44 { 0xa4000010, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
40 45 };
41 46  
42   -static DECLARE_INTC_DESC(intc_desc_irq0123, "sh3-irq0123", vectors_irq0123,
43   - NULL, NULL, prio_registers, sense_registers);
  47 +static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh3-irq0123",
  48 + vectors_irq0123, NULL, NULL,
  49 + prio_registers, sense_registers, ack_registers);
44 50  
45   -static DECLARE_INTC_DESC(intc_desc_irq45, "sh3-irq45", vectors_irq45,
46   - NULL, NULL, prio_registers, sense_registers);
  51 +static DECLARE_INTC_DESC_ACK(intc_desc_irq45, "sh3-irq45",
  52 + vectors_irq45, NULL, NULL,
  53 + prio_registers, sense_registers, ack_registers);
47 54  
48 55 #define INTC_ICR1 0xa4000010UL
49 56 #define INTC_ICR1_IRQLVL (1<<14)
include/asm-sh/hw_irq.h
... ... @@ -79,6 +79,10 @@
79 79 struct intc_sense_reg *sense_regs;
80 80 unsigned int nr_sense_regs;
81 81 char *name;
  82 +#ifdef CONFIG_CPU_SH3
  83 + struct intc_mask_reg *ack_regs;
  84 + unsigned int nr_ack_regs;
  85 +#endif
82 86 };
83 87  
84 88 #define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
... ... @@ -90,6 +94,18 @@
90 94 _INTC_ARRAY(sense_regs), \
91 95 chipname, \
92 96 }
  97 +
  98 +#ifdef CONFIG_CPU_SH3
  99 +#define DECLARE_INTC_DESC_ACK(symbol, chipname, vectors, groups, \
  100 + mask_regs, prio_regs, sense_regs, ack_regs) \
  101 +struct intc_desc symbol __initdata = { \
  102 + _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \
  103 + _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \
  104 + _INTC_ARRAY(sense_regs), \
  105 + chipname, \
  106 + _INTC_ARRAY(ack_regs), \
  107 +}
  108 +#endif
93 109  
94 110 void __init register_intc_controller(struct intc_desc *desc);
95 111 int intc_set_priority(unsigned int irq, unsigned int prio);