Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-omap1/fpga.c
10817 views
1
/*
2
* linux/arch/arm/mach-omap1/fpga.c
3
*
4
* Interrupt handler for OMAP-1510 Innovator FPGA
5
*
6
* Copyright (C) 2001 RidgeRun, Inc.
7
* Author: Greg Lonnon <[email protected]>
8
*
9
* Copyright (C) 2002 MontaVista Software, Inc.
10
*
11
* Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
12
* Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <[email protected]>
13
*
14
* This program is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License version 2 as
16
* published by the Free Software Foundation.
17
*/
18
19
#include <linux/types.h>
20
#include <linux/init.h>
21
#include <linux/kernel.h>
22
#include <linux/device.h>
23
#include <linux/errno.h>
24
#include <linux/io.h>
25
26
#include <mach/hardware.h>
27
#include <asm/irq.h>
28
#include <asm/mach/irq.h>
29
30
#include <plat/fpga.h>
31
#include <mach/gpio.h>
32
33
static void fpga_mask_irq(struct irq_data *d)
34
{
35
unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
36
37
if (irq < 8)
38
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
39
& ~(1 << irq)), OMAP1510_FPGA_IMR_LO);
40
else if (irq < 16)
41
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
42
& ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
43
else
44
__raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
45
& ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
46
}
47
48
49
static inline u32 get_fpga_unmasked_irqs(void)
50
{
51
return
52
((__raw_readb(OMAP1510_FPGA_ISR_LO) &
53
__raw_readb(OMAP1510_FPGA_IMR_LO))) |
54
((__raw_readb(OMAP1510_FPGA_ISR_HI) &
55
__raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) |
56
((__raw_readb(INNOVATOR_FPGA_ISR2) &
57
__raw_readb(INNOVATOR_FPGA_IMR2)) << 16);
58
}
59
60
61
static void fpga_ack_irq(struct irq_data *d)
62
{
63
/* Don't need to explicitly ACK FPGA interrupts */
64
}
65
66
static void fpga_unmask_irq(struct irq_data *d)
67
{
68
unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
69
70
if (irq < 8)
71
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
72
OMAP1510_FPGA_IMR_LO);
73
else if (irq < 16)
74
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
75
| (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
76
else
77
__raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
78
| (1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
79
}
80
81
static void fpga_mask_ack_irq(struct irq_data *d)
82
{
83
fpga_mask_irq(d);
84
fpga_ack_irq(d);
85
}
86
87
void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
88
{
89
u32 stat;
90
int fpga_irq;
91
92
stat = get_fpga_unmasked_irqs();
93
94
if (!stat)
95
return;
96
97
for (fpga_irq = OMAP_FPGA_IRQ_BASE;
98
(fpga_irq < OMAP_FPGA_IRQ_END) && stat;
99
fpga_irq++, stat >>= 1) {
100
if (stat & 1) {
101
generic_handle_irq(fpga_irq);
102
}
103
}
104
}
105
106
static struct irq_chip omap_fpga_irq_ack = {
107
.name = "FPGA-ack",
108
.irq_ack = fpga_mask_ack_irq,
109
.irq_mask = fpga_mask_irq,
110
.irq_unmask = fpga_unmask_irq,
111
};
112
113
114
static struct irq_chip omap_fpga_irq = {
115
.name = "FPGA",
116
.irq_ack = fpga_ack_irq,
117
.irq_mask = fpga_mask_irq,
118
.irq_unmask = fpga_unmask_irq,
119
};
120
121
/*
122
* All of the FPGA interrupt request inputs except for the touchscreen are
123
* edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive
124
* interrupts are acknowledged as a side-effect of reading the interrupt
125
* status register from the FPGA. The edge-sensitive interrupt inputs
126
* cause a problem with level interrupt requests, such as Ethernet. The
127
* problem occurs when a level interrupt request is asserted while its
128
* interrupt input is masked in the FPGA, which results in a missed
129
* interrupt.
130
*
131
* In an attempt to workaround the problem with missed interrupts, the
132
* mask_ack routine for all of the FPGA interrupts has been changed from
133
* fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt
134
* being serviced is left unmasked. We can do this because the FPGA cascade
135
* interrupt is installed with the IRQF_DISABLED flag, which leaves all
136
* interrupts masked at the CPU while an FPGA interrupt handler executes.
137
*
138
* Limited testing indicates that this workaround appears to be effective
139
* for the smc9194 Ethernet driver used on the Innovator. It should work
140
* on other FPGA interrupts as well, but any drivers that explicitly mask
141
* interrupts at the interrupt controller via disable_irq/enable_irq
142
* could pose a problem.
143
*/
144
void omap1510_fpga_init_irq(void)
145
{
146
int i, res;
147
148
__raw_writeb(0, OMAP1510_FPGA_IMR_LO);
149
__raw_writeb(0, OMAP1510_FPGA_IMR_HI);
150
__raw_writeb(0, INNOVATOR_FPGA_IMR2);
151
152
for (i = OMAP_FPGA_IRQ_BASE; i < OMAP_FPGA_IRQ_END; i++) {
153
154
if (i == OMAP1510_INT_FPGA_TS) {
155
/*
156
* The touchscreen interrupt is level-sensitive, so
157
* we'll use the regular mask_ack routine for it.
158
*/
159
irq_set_chip(i, &omap_fpga_irq_ack);
160
}
161
else {
162
/*
163
* All FPGA interrupts except the touchscreen are
164
* edge-sensitive, so we won't mask them.
165
*/
166
irq_set_chip(i, &omap_fpga_irq);
167
}
168
169
irq_set_handler(i, handle_edge_irq);
170
set_irq_flags(i, IRQF_VALID);
171
}
172
173
/*
174
* The FPGA interrupt line is connected to GPIO13. Claim this pin for
175
* the ARM.
176
*
177
* NOTE: For general GPIO/MPUIO access and interrupts, please see
178
* gpio.[ch]
179
*/
180
res = gpio_request(13, "FPGA irq");
181
if (res) {
182
pr_err("%s failed to get gpio\n", __func__);
183
return;
184
}
185
gpio_direction_input(13);
186
irq_set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
187
irq_set_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
188
}
189
190