diff options
Diffstat (limited to 'arch/frv/kernel/irq-mb93093.c')
-rw-r--r-- | arch/frv/kernel/irq-mb93093.c | 115 |
1 files changed, 75 insertions, 40 deletions
diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c index 48b2a6420888..a43a22158956 100644 --- a/arch/frv/kernel/irq-mb93093.c +++ b/arch/frv/kernel/irq-mb93093.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* irq-mb93093.c: MB93093 FPGA interrupt handling | 1 | /* irq-mb93093.c: MB93093 FPGA interrupt handling |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -24,7 +24,6 @@ | |||
24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | #include <asm/irc-regs.h> | 26 | #include <asm/irc-regs.h> |
27 | #include <asm/irq-routing.h> | ||
28 | 27 | ||
29 | #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) | 28 | #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) |
30 | 29 | ||
@@ -33,66 +32,102 @@ | |||
33 | #define __get_IFR() ({ __reg16(0x02); }) | 32 | #define __get_IFR() ({ __reg16(0x02); }) |
34 | #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) | 33 | #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) |
35 | 34 | ||
36 | static void frv_fpga_doirq(struct irq_source *source); | ||
37 | static void frv_fpga_control(struct irq_group *group, int irq, int on); | ||
38 | |||
39 | /*****************************************************************************/ | ||
40 | /* | 35 | /* |
41 | * FPGA IRQ multiplexor | 36 | * off-CPU FPGA PIC operations |
42 | */ | 37 | */ |
43 | static struct irq_source frv_fpga[4] = { | 38 | static void frv_fpga_mask(unsigned int irq) |
44 | #define __FPGA(X, M) \ | 39 | { |
45 | [X] = { \ | 40 | uint16_t imr = __get_IMR(); |
46 | .muxname = "fpga."#X, \ | ||
47 | .irqmask = M, \ | ||
48 | .doirq = frv_fpga_doirq, \ | ||
49 | } | ||
50 | 41 | ||
51 | __FPGA(0, 0x0700), | 42 | imr |= 1 << (irq - IRQ_BASE_FPGA); |
52 | }; | 43 | __set_IMR(imr); |
44 | } | ||
53 | 45 | ||
54 | static struct irq_group frv_fpga_irqs = { | 46 | static void frv_fpga_ack(unsigned int irq) |
55 | .first_irq = IRQ_BASE_FPGA, | 47 | { |
56 | .control = frv_fpga_control, | 48 | __clr_IFR(1 << (irq - IRQ_BASE_FPGA)); |
57 | .sources = { | 49 | } |
58 | [ 8] = &frv_fpga[0], | 50 | |
59 | [ 9] = &frv_fpga[0], | 51 | static void frv_fpga_mask_ack(unsigned int irq) |
60 | [10] = &frv_fpga[0], | 52 | { |
61 | }, | 53 | uint16_t imr = __get_IMR(); |
62 | }; | ||
63 | 54 | ||
55 | imr |= 1 << (irq - IRQ_BASE_FPGA); | ||
56 | __set_IMR(imr); | ||
57 | |||
58 | __clr_IFR(1 << (irq - IRQ_BASE_FPGA)); | ||
59 | } | ||
64 | 60 | ||
65 | static void frv_fpga_control(struct irq_group *group, int index, int on) | 61 | static void frv_fpga_unmask(unsigned int irq) |
66 | { | 62 | { |
67 | uint16_t imr = __get_IMR(); | 63 | uint16_t imr = __get_IMR(); |
68 | 64 | ||
69 | if (on) | 65 | imr &= ~(1 << (irq - IRQ_BASE_FPGA)); |
70 | imr &= ~(1 << index); | ||
71 | else | ||
72 | imr |= 1 << index; | ||
73 | 66 | ||
74 | __set_IMR(imr); | 67 | __set_IMR(imr); |
75 | } | 68 | } |
76 | 69 | ||
77 | static void frv_fpga_doirq(struct irq_source *source) | 70 | static struct irq_chip frv_fpga_pic = { |
71 | .name = "mb93093", | ||
72 | .ack = frv_fpga_ack, | ||
73 | .mask = frv_fpga_mask, | ||
74 | .mask_ack = frv_fpga_mask_ack, | ||
75 | .unmask = frv_fpga_unmask, | ||
76 | .end = frv_fpga_end, | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * FPGA PIC interrupt handler | ||
81 | */ | ||
82 | static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) | ||
78 | { | 83 | { |
79 | uint16_t mask, imr; | 84 | uint16_t imr, mask = (unsigned long) _mask; |
80 | 85 | ||
81 | imr = __get_IMR(); | 86 | imr = __get_IMR(); |
82 | mask = source->irqmask & ~imr & __get_IFR(); | 87 | mask = mask & ~imr & __get_IFR(); |
83 | if (mask) { | 88 | |
84 | __set_IMR(imr | mask); | 89 | /* poll all the triggered IRQs */ |
85 | __clr_IFR(mask); | 90 | while (mask) { |
86 | distribute_irqs(&frv_fpga_irqs, mask); | 91 | int irq; |
87 | __set_IMR(imr); | 92 | |
93 | asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask)); | ||
94 | irq = 31 - irq; | ||
95 | mask &= ~(1 << irq); | ||
96 | |||
97 | generic_irq_handle(IRQ_BASE_FPGA + irq, regs); | ||
88 | } | 98 | } |
99 | |||
100 | return IRQ_HANDLED; | ||
89 | } | 101 | } |
90 | 102 | ||
103 | /* | ||
104 | * define an interrupt action for each FPGA PIC output | ||
105 | * - use dev_id to indicate the FPGA PIC input to output mappings | ||
106 | */ | ||
107 | static struct irqaction fpga_irq[1] = { | ||
108 | [0] = { | ||
109 | .handler = fpga_interrupt, | ||
110 | .flags = IRQF_DISABLED, | ||
111 | .mask = CPU_MASK_NONE, | ||
112 | .name = "fpga.0", | ||
113 | .dev_id = (void *) 0x0700UL, | ||
114 | } | ||
115 | }; | ||
116 | |||
117 | /* | ||
118 | * initialise the motherboard FPGA's PIC | ||
119 | */ | ||
91 | void __init fpga_init(void) | 120 | void __init fpga_init(void) |
92 | { | 121 | { |
122 | int irq; | ||
123 | |||
124 | /* all PIC inputs are all set to be edge triggered */ | ||
93 | __set_IMR(0x0700); | 125 | __set_IMR(0x0700); |
94 | __clr_IFR(0x0000); | 126 | __clr_IFR(0x0000); |
95 | 127 | ||
96 | frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL2); | 128 | for (irq = IRQ_BASE_FPGA + 8; irq <= IRQ_BASE_FPGA + 10; irq++) |
97 | frv_irq_set_group(&frv_fpga_irqs); | 129 | set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_edge_irq); |
130 | |||
131 | /* the FPGA drives external IRQ input #2 on the CPU PIC */ | ||
132 | setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[0]); | ||
98 | } | 133 | } |