diff options
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/cpu/irq/intc.c | 79 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/setup-sh3.c | 15 |
2 files changed, 87 insertions, 7 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c index 84806b2027f8..df3695406d80 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 | ||
64 | static unsigned int intc_prio_level[NR_IRQS]; /* for now */ | 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 | static inline struct intc_desc_int *get_intc_desc(unsigned int irq) | 69 | static 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 | ||
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 | static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, | 244 | static 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 | ||
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 | static unsigned int __init intc_sense_data(struct intc_desc *desc, | 489 | static 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 | ||
535 | static unsigned int __init save_reg(struct intc_desc_int *d, | 596 | static 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 | ||
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh3.c b/arch/sh/kernel/cpu/sh3/setup-sh3.c index 28e7d6553091..c98846857855 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh3.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh3.c | |||
@@ -35,15 +35,22 @@ static struct intc_prio_reg prio_registers[] __initdata = { | |||
35 | { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } }, | 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 | static struct intc_sense_reg sense_registers[] __initdata = { | 43 | static struct intc_sense_reg sense_registers[] __initdata = { |
39 | { 0xa4000010, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } }, | 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, | 47 | static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh3-irq0123", |
43 | NULL, NULL, prio_registers, sense_registers); | 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, | 51 | static DECLARE_INTC_DESC_ACK(intc_desc_irq45, "sh3-irq45", |
46 | NULL, NULL, prio_registers, sense_registers); | 52 | vectors_irq45, NULL, NULL, |
53 | prio_registers, sense_registers, ack_registers); | ||
47 | 54 | ||
48 | #define INTC_ICR1 0xa4000010UL | 55 | #define INTC_ICR1 0xa4000010UL |
49 | #define INTC_ICR1_IRQLVL (1<<14) | 56 | #define INTC_ICR1_IRQLVL (1<<14) |