diff options
Diffstat (limited to 'arch/sh/kernel/cpu/irq/intc.c')
-rw-r--r-- | arch/sh/kernel/cpu/irq/intc.c | 93 |
1 files changed, 90 insertions, 3 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c index 84806b2027f8..da5dae787888 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 | { |
@@ -98,17 +101,26 @@ static void write_32(unsigned long addr, unsigned long h, unsigned long data) | |||
98 | 101 | ||
99 | static void modify_8(unsigned long addr, unsigned long h, unsigned long data) | 102 | static void modify_8(unsigned long addr, unsigned long h, unsigned long data) |
100 | { | 103 | { |
104 | unsigned long flags; | ||
105 | local_irq_save(flags); | ||
101 | ctrl_outb(set_field(ctrl_inb(addr), data, h), addr); | 106 | ctrl_outb(set_field(ctrl_inb(addr), data, h), addr); |
107 | local_irq_restore(flags); | ||
102 | } | 108 | } |
103 | 109 | ||
104 | static void modify_16(unsigned long addr, unsigned long h, unsigned long data) | 110 | static void modify_16(unsigned long addr, unsigned long h, unsigned long data) |
105 | { | 111 | { |
112 | unsigned long flags; | ||
113 | local_irq_save(flags); | ||
106 | ctrl_outw(set_field(ctrl_inw(addr), data, h), addr); | 114 | ctrl_outw(set_field(ctrl_inw(addr), data, h), addr); |
115 | local_irq_restore(flags); | ||
107 | } | 116 | } |
108 | 117 | ||
109 | static void modify_32(unsigned long addr, unsigned long h, unsigned long data) | 118 | static void modify_32(unsigned long addr, unsigned long h, unsigned long data) |
110 | { | 119 | { |
120 | unsigned long flags; | ||
121 | local_irq_save(flags); | ||
111 | ctrl_outl(set_field(ctrl_inl(addr), data, h), addr); | 122 | ctrl_outl(set_field(ctrl_inl(addr), data, h), addr); |
123 | local_irq_restore(flags); | ||
112 | } | 124 | } |
113 | 125 | ||
114 | enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 }; | 126 | enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 }; |
@@ -219,6 +231,25 @@ static void intc_disable(unsigned int irq) | |||
219 | } | 231 | } |
220 | } | 232 | } |
221 | 233 | ||
234 | #ifdef CONFIG_CPU_SH3 | ||
235 | static void intc_mask_ack(unsigned int irq) | ||
236 | { | ||
237 | struct intc_desc_int *d = get_intc_desc(irq); | ||
238 | unsigned long handle = ack_handle[irq]; | ||
239 | unsigned long addr; | ||
240 | |||
241 | intc_disable(irq); | ||
242 | |||
243 | /* read register and write zero only to the assocaited bit */ | ||
244 | |||
245 | if (handle) { | ||
246 | addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); | ||
247 | ctrl_inb(addr); | ||
248 | ctrl_outb(0x3f ^ set_field(0, 1, handle), addr); | ||
249 | } | ||
250 | } | ||
251 | #endif | ||
252 | |||
222 | static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, | 253 | static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, |
223 | unsigned int nr_hp, | 254 | unsigned int nr_hp, |
224 | unsigned int irq) | 255 | unsigned int irq) |
@@ -280,7 +311,12 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { | |||
280 | [IRQ_TYPE_EDGE_FALLING] = VALID(0), | 311 | [IRQ_TYPE_EDGE_FALLING] = VALID(0), |
281 | [IRQ_TYPE_EDGE_RISING] = VALID(1), | 312 | [IRQ_TYPE_EDGE_RISING] = VALID(1), |
282 | [IRQ_TYPE_LEVEL_LOW] = VALID(2), | 313 | [IRQ_TYPE_LEVEL_LOW] = VALID(2), |
314 | /* SH7706, SH7707 and SH7709 do not support high level triggered */ | ||
315 | #if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \ | ||
316 | !defined(CONFIG_CPU_SUBTYPE_SH7707) && \ | ||
317 | !defined(CONFIG_CPU_SUBTYPE_SH7709) | ||
283 | [IRQ_TYPE_LEVEL_HIGH] = VALID(3), | 318 | [IRQ_TYPE_LEVEL_HIGH] = VALID(3), |
319 | #endif | ||
284 | }; | 320 | }; |
285 | 321 | ||
286 | static int intc_set_sense(unsigned int irq, unsigned int type) | 322 | static int intc_set_sense(unsigned int irq, unsigned int type) |
@@ -430,6 +466,40 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc, | |||
430 | return 0; | 466 | return 0; |
431 | } | 467 | } |
432 | 468 | ||
469 | #ifdef CONFIG_CPU_SH3 | ||
470 | static unsigned int __init intc_ack_data(struct intc_desc *desc, | ||
471 | struct intc_desc_int *d, | ||
472 | intc_enum enum_id) | ||
473 | { | ||
474 | struct intc_mask_reg *mr = desc->ack_regs; | ||
475 | unsigned int i, j, fn, mode; | ||
476 | unsigned long reg_e, reg_d; | ||
477 | |||
478 | for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) { | ||
479 | mr = desc->ack_regs + i; | ||
480 | |||
481 | for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { | ||
482 | if (mr->enum_ids[j] != enum_id) | ||
483 | continue; | ||
484 | |||
485 | fn = REG_FN_MODIFY_BASE; | ||
486 | mode = MODE_ENABLE_REG; | ||
487 | reg_e = mr->set_reg; | ||
488 | reg_d = mr->set_reg; | ||
489 | |||
490 | fn += (mr->reg_width >> 3) - 1; | ||
491 | return _INTC_MK(fn, mode, | ||
492 | intc_get_reg(d, reg_e), | ||
493 | intc_get_reg(d, reg_d), | ||
494 | 1, | ||
495 | (mr->reg_width - 1) - j); | ||
496 | } | ||
497 | } | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | #endif | ||
502 | |||
433 | static unsigned int __init intc_sense_data(struct intc_desc *desc, | 503 | static unsigned int __init intc_sense_data(struct intc_desc *desc, |
434 | struct intc_desc_int *d, | 504 | struct intc_desc_int *d, |
435 | intc_enum enum_id) | 505 | intc_enum enum_id) |
@@ -530,6 +600,11 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
530 | 600 | ||
531 | /* irq should be disabled by default */ | 601 | /* irq should be disabled by default */ |
532 | d->chip.mask(irq); | 602 | d->chip.mask(irq); |
603 | |||
604 | #ifdef CONFIG_CPU_SH3 | ||
605 | if (desc->ack_regs) | ||
606 | ack_handle[irq] = intc_ack_data(desc, d, enum_id); | ||
607 | #endif | ||
533 | } | 608 | } |
534 | 609 | ||
535 | static unsigned int __init save_reg(struct intc_desc_int *d, | 610 | static unsigned int __init save_reg(struct intc_desc_int *d, |
@@ -560,6 +635,9 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
560 | d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; | 635 | d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; |
561 | d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; | 636 | d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; |
562 | 637 | ||
638 | #ifdef CONFIG_CPU_SH3 | ||
639 | d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0; | ||
640 | #endif | ||
563 | d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg)); | 641 | d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg)); |
564 | #ifdef CONFIG_SMP | 642 | #ifdef CONFIG_SMP |
565 | d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp)); | 643 | d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp)); |
@@ -592,14 +670,23 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
592 | } | 670 | } |
593 | } | 671 | } |
594 | 672 | ||
595 | BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ | ||
596 | |||
597 | d->chip.name = desc->name; | 673 | d->chip.name = desc->name; |
598 | d->chip.mask = intc_disable; | 674 | d->chip.mask = intc_disable; |
599 | d->chip.unmask = intc_enable; | 675 | d->chip.unmask = intc_enable; |
600 | d->chip.mask_ack = intc_disable; | 676 | d->chip.mask_ack = intc_disable; |
601 | d->chip.set_type = intc_set_sense; | 677 | d->chip.set_type = intc_set_sense; |
602 | 678 | ||
679 | #ifdef CONFIG_CPU_SH3 | ||
680 | if (desc->ack_regs) { | ||
681 | for (i = 0; i < desc->nr_ack_regs; i++) | ||
682 | k += save_reg(d, k, desc->ack_regs[i].set_reg, 0); | ||
683 | |||
684 | d->chip.mask_ack = intc_mask_ack; | ||
685 | } | ||
686 | #endif | ||
687 | |||
688 | BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ | ||
689 | |||
603 | for (i = 0; i < desc->nr_vectors; i++) { | 690 | for (i = 0; i < desc->nr_vectors; i++) { |
604 | struct intc_vect *vect = desc->vectors + i; | 691 | struct intc_vect *vect = desc->vectors + i; |
605 | 692 | ||