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, 101 insertions, 56 deletions
diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c
index 1381abcd5cc9..635d23437666 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,129 @@
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_enable(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
57static struct irq_group frv_fpga_irqs = {
58 .first_irq = IRQ_BASE_FPGA,
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 44
45 __set_IMR(imr);
46}
78 47
79static void frv_fpga_control(struct irq_group *group, int index, int on) 48static void frv_fpga_disable(unsigned int irq)
80{ 49{
81 uint16_t imr = __get_IMR(); 50 uint16_t imr = __get_IMR();
82 51
83 if (on) 52 imr |= 1 << (irq - IRQ_BASE_FPGA);
84 imr &= ~(1 << index);
85 else
86 imr |= 1 << index;
87 53
88 __set_IMR(imr); 54 __set_IMR(imr);
89} 55}
90 56
91static void frv_fpga_doirq(struct irq_source *source) 57static void frv_fpga_ack(unsigned int irq)
58{
59 __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
60}
61
62static void frv_fpga_end(unsigned int irq)
63{
64}
65
66static struct irq_chip frv_fpga_pic = {
67 .name = "mb93091",
68 .enable = frv_fpga_enable,
69 .disable = frv_fpga_disable,
70 .ack = frv_fpga_ack,
71 .mask = frv_fpga_disable,
72 .unmask = frv_fpga_enable,
73 .end = frv_fpga_end,
74};
75
76/*
77 * FPGA PIC interrupt handler
78 */
79static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs)
92{ 80{
93 uint16_t mask, imr; 81 uint16_t imr, mask = (unsigned long) _mask;
82 irqreturn_t iret = 0;
94 83
95 imr = __get_IMR(); 84 imr = __get_IMR();
96 mask = source->irqmask & ~imr & __get_IFR(); 85 mask = mask & ~imr & __get_IFR();
97 if (mask) { 86
98 __set_IMR(imr | mask); 87 /* poll all the triggered IRQs */
99 __clr_IFR(mask); 88 while (mask) {
100 distribute_irqs(&frv_fpga_irqs, mask); 89 int irq;
101 __set_IMR(imr); 90
91 asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask));
92 irq = 31 - irq;
93 mask &= ~(1 << irq);
94
95 if (__do_IRQ(IRQ_BASE_FPGA + irq, regs))
96 iret |= IRQ_HANDLED;
102 } 97 }
98
99 return iret;
103} 100}
104 101
102/*
103 * define an interrupt action for each FPGA PIC output
104 * - use dev_id to indicate the FPGA PIC input to output mappings
105 */
106static struct irqaction fpga_irq[4] = {
107 [0] = {
108 .handler = fpga_interrupt,
109 .flags = IRQF_DISABLED | IRQF_SHARED,
110 .mask = CPU_MASK_NONE,
111 .name = "fpga.0",
112 .dev_id = (void *) 0x0028UL,
113 },
114 [1] = {
115 .handler = fpga_interrupt,
116 .flags = IRQF_DISABLED | IRQF_SHARED,
117 .mask = CPU_MASK_NONE,
118 .name = "fpga.1",
119 .dev_id = (void *) 0x0050UL,
120 },
121 [2] = {
122 .handler = fpga_interrupt,
123 .flags = IRQF_DISABLED | IRQF_SHARED,
124 .mask = CPU_MASK_NONE,
125 .name = "fpga.2",
126 .dev_id = (void *) 0x1c00UL,
127 },
128 [3] = {
129 .handler = fpga_interrupt,
130 .flags = IRQF_DISABLED | IRQF_SHARED,
131 .mask = CPU_MASK_NONE,
132 .name = "fpga.3",
133 .dev_id = (void *) 0x6386UL,
134 }
135};
136
137/*
138 * initialise the motherboard FPGA's PIC
139 */
105void __init fpga_init(void) 140void __init fpga_init(void)
106{ 141{
142 int irq;
143
144 /* all PIC inputs are all set to be low-level driven, apart from the
145 * NMI button (15) which is fixed at falling-edge
146 */
107 __set_IMR(0x7ffe); 147 __set_IMR(0x7ffe);
108 __clr_IFR(0x0000); 148 __clr_IFR(0x0000);
109 149
110 frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL0); 150 for (irq = IRQ_BASE_FPGA + 1; irq <= IRQ_BASE_FPGA + 14; irq++)
111 frv_irq_route_external(&frv_fpga[1], IRQ_CPU_EXTERNAL1); 151 set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_level_irq);
112 frv_irq_route_external(&frv_fpga[2], IRQ_CPU_EXTERNAL2); 152
113 frv_irq_route_external(&frv_fpga[3], IRQ_CPU_EXTERNAL3); 153 set_irq_chip_and_handler(IRQ_FPGA_NMI, &frv_fpga_pic, handle_edge_irq);
114 frv_irq_set_group(&frv_fpga_irqs); 154
155 /* the FPGA drives the first four external IRQ inputs on the CPU PIC */
156 setup_irq(IRQ_CPU_EXTERNAL0, &fpga_irq[0]);
157 setup_irq(IRQ_CPU_EXTERNAL1, &fpga_irq[1]);
158 setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[2]);
159 setup_irq(IRQ_CPU_EXTERNAL3, &fpga_irq[3]);
115} 160}