aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel/irq-mb93091.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/frv/kernel/irq-mb93091.c')
-rw-r--r--arch/frv/kernel/irq-mb93091.c157
1 files changed, 102 insertions, 55 deletions
diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c
index 1381abcd5cc9..369bc0a7443d 100644
--- a/arch/frv/kernel/irq-mb93091.c
+++ b/arch/frv/kernel/irq-mb93091.c
@@ -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 *)(ADDR)) 28#define __reg16(ADDR) (*(volatile unsigned short *)(ADDR))
30 29
@@ -33,83 +32,131 @@
33#define __get_IFR() ({ __reg16(0xffc0000c); }) 32#define __get_IFR() ({ __reg16(0xffc0000c); })
34#define __clr_IFR(M) do { __reg16(0xffc0000c) = ~(M); wmb(); } while(0) 33#define __clr_IFR(M) do { __reg16(0xffc0000c) = ~(M); wmb(); } while(0)
35 34
36static void frv_fpga_doirq(struct irq_source *source);
37static void frv_fpga_control(struct irq_group *group, int irq, int on);
38 35
39/*****************************************************************************/
40/* 36/*
41 * FPGA IRQ multiplexor 37 * on-motherboard FPGA PIC operations
42 */ 38 */
43static struct irq_source frv_fpga[4] = { 39static void frv_fpga_mask(unsigned int irq)
44#define __FPGA(X, M) \ 40{
45 [X] = { \ 41 uint16_t imr = __get_IMR();
46 .muxname = "fpga."#X, \
47 .irqmask = M, \
48 .doirq = frv_fpga_doirq, \
49 }
50 42
51 __FPGA(0, 0x0028), 43 imr |= 1 << (irq - IRQ_BASE_FPGA);
52 __FPGA(1, 0x0050),
53 __FPGA(2, 0x1c00),
54 __FPGA(3, 0x6386),
55};
56 44
57static struct irq_group frv_fpga_irqs = { 45 __set_IMR(imr);
58 .first_irq = IRQ_BASE_FPGA, 46}
59 .control = frv_fpga_control,
60 .sources = {
61 [ 1] = &frv_fpga[3],
62 [ 2] = &frv_fpga[3],
63 [ 3] = &frv_fpga[0],
64 [ 4] = &frv_fpga[1],
65 [ 5] = &frv_fpga[0],
66 [ 6] = &frv_fpga[1],
67 [ 7] = &frv_fpga[3],
68 [ 8] = &frv_fpga[3],
69 [ 9] = &frv_fpga[3],
70 [10] = &frv_fpga[2],
71 [11] = &frv_fpga[2],
72 [12] = &frv_fpga[2],
73 [13] = &frv_fpga[3],
74 [14] = &frv_fpga[3],
75 },
76};
77 47
48static void frv_fpga_ack(unsigned int irq)
49{
50 __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
51}
78 52
79static void frv_fpga_control(struct irq_group *group, int index, int on) 53static void frv_fpga_mask_ack(unsigned int irq)
80{ 54{
81 uint16_t imr = __get_IMR(); 55 uint16_t imr = __get_IMR();
82 56
83 if (on) 57 imr |= 1 << (irq - IRQ_BASE_FPGA);
84 imr &= ~(1 << index); 58 __set_IMR(imr);
85 else 59
86 imr |= 1 << index; 60 __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
61}
62
63static void frv_fpga_unmask(unsigned int irq)
64{
65 uint16_t imr = __get_IMR();
66
67 imr &= ~(1 << (irq - IRQ_BASE_FPGA));
87 68
88 __set_IMR(imr); 69 __set_IMR(imr);
89} 70}
90 71
91static void frv_fpga_doirq(struct irq_source *source) 72static struct irq_chip frv_fpga_pic = {
73 .name = "mb93091",
74 .ack = frv_fpga_ack,
75 .mask = frv_fpga_mask,
76 .mask_ack = frv_fpga_mask_ack,
77 .unmask = frv_fpga_unmask,
78};
79
80/*
81 * FPGA PIC interrupt handler
82 */
83static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs)
92{ 84{
93 uint16_t mask, imr; 85 uint16_t imr, mask = (unsigned long) _mask;
94 86
95 imr = __get_IMR(); 87 imr = __get_IMR();
96 mask = source->irqmask & ~imr & __get_IFR(); 88 mask = mask & ~imr & __get_IFR();
97 if (mask) { 89
98 __set_IMR(imr | mask); 90 /* poll all the triggered IRQs */
99 __clr_IFR(mask); 91 while (mask) {
100 distribute_irqs(&frv_fpga_irqs, mask); 92 int irq;
101 __set_IMR(imr); 93
94 asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask));
95 irq = 31 - irq;
96 mask &= ~(1 << irq);
97
98 generic_handle_irq(IRQ_BASE_FPGA + irq, regs);
102 } 99 }
100
101 return IRQ_HANDLED;
103} 102}
104 103
104/*
105 * define an interrupt action for each FPGA PIC output
106 * - use dev_id to indicate the FPGA PIC input to output mappings
107 */
108static struct irqaction fpga_irq[4] = {
109 [0] = {
110 .handler = fpga_interrupt,
111 .flags = IRQF_DISABLED | IRQF_SHARED,
112 .mask = CPU_MASK_NONE,
113 .name = "fpga.0",
114 .dev_id = (void *) 0x0028UL,
115 },
116 [1] = {
117 .handler = fpga_interrupt,
118 .flags = IRQF_DISABLED | IRQF_SHARED,
119 .mask = CPU_MASK_NONE,
120 .name = "fpga.1",
121 .dev_id = (void *) 0x0050UL,
122 },
123 [2] = {
124 .handler = fpga_interrupt,
125 .flags = IRQF_DISABLED | IRQF_SHARED,
126 .mask = CPU_MASK_NONE,
127 .name = "fpga.2",
128 .dev_id = (void *) 0x1c00UL,
129 },
130 [3] = {
131 .handler = fpga_interrupt,
132 .flags = IRQF_DISABLED | IRQF_SHARED,
133 .mask = CPU_MASK_NONE,
134 .name = "fpga.3",
135 .dev_id = (void *) 0x6386UL,
136 }
137};
138
139/*
140 * initialise the motherboard FPGA's PIC
141 */
105void __init fpga_init(void) 142void __init fpga_init(void)
106{ 143{
144 int irq;
145
146 /* all PIC inputs are all set to be low-level driven, apart from the
147 * NMI button (15) which is fixed at falling-edge
148 */
107 __set_IMR(0x7ffe); 149 __set_IMR(0x7ffe);
108 __clr_IFR(0x0000); 150 __clr_IFR(0x0000);
109 151
110 frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL0); 152 for (irq = IRQ_BASE_FPGA + 1; irq <= IRQ_BASE_FPGA + 14; irq++)
111 frv_irq_route_external(&frv_fpga[1], IRQ_CPU_EXTERNAL1); 153 set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_level_irq);
112 frv_irq_route_external(&frv_fpga[2], IRQ_CPU_EXTERNAL2); 154
113 frv_irq_route_external(&frv_fpga[3], IRQ_CPU_EXTERNAL3); 155 set_irq_chip_and_handler(IRQ_FPGA_NMI, &frv_fpga_pic, handle_edge_irq);
114 frv_irq_set_group(&frv_fpga_irqs); 156
157 /* the FPGA drives the first four external IRQ inputs on the CPU PIC */
158 setup_irq(IRQ_CPU_EXTERNAL0, &fpga_irq[0]);
159 setup_irq(IRQ_CPU_EXTERNAL1, &fpga_irq[1]);
160 setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[2]);
161 setup_irq(IRQ_CPU_EXTERNAL3, &fpga_irq[3]);
115} 162}