Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
10820 views
1
/*
2
* Copyright (C) 2008 Ilya Yanok, Emcraft Systems
3
*
4
*
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
8
*
9
*/
10
11
#include <linux/irq.h>
12
#include <linux/of_platform.h>
13
#include <linux/io.h>
14
15
/*
16
* The FPGA supports 9 interrupt sources, which can be routed to 3
17
* interrupt request lines of the MPIC. The line to be used can be
18
* specified through the third cell of FDT property "interrupts".
19
*/
20
21
#define SOCRATES_FPGA_NUM_IRQS 9
22
23
#define FPGA_PIC_IRQCFG (0x0)
24
#define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
25
26
#define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
27
28
struct socrates_fpga_irq_info {
29
unsigned int irq_line;
30
int type;
31
};
32
33
/*
34
* Interrupt routing and type table
35
*
36
* IRQ_TYPE_NONE means the interrupt type is configurable,
37
* otherwise it's fixed to the specified value.
38
*/
39
static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
40
[0] = {0, IRQ_TYPE_NONE},
41
[1] = {0, IRQ_TYPE_LEVEL_HIGH},
42
[2] = {0, IRQ_TYPE_LEVEL_LOW},
43
[3] = {0, IRQ_TYPE_NONE},
44
[4] = {0, IRQ_TYPE_NONE},
45
[5] = {0, IRQ_TYPE_NONE},
46
[6] = {0, IRQ_TYPE_NONE},
47
[7] = {0, IRQ_TYPE_NONE},
48
[8] = {0, IRQ_TYPE_LEVEL_HIGH},
49
};
50
51
static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
52
53
static void __iomem *socrates_fpga_pic_iobase;
54
static struct irq_host *socrates_fpga_pic_irq_host;
55
static unsigned int socrates_fpga_irqs[3];
56
57
static inline uint32_t socrates_fpga_pic_read(int reg)
58
{
59
return in_be32(socrates_fpga_pic_iobase + reg);
60
}
61
62
static inline void socrates_fpga_pic_write(int reg, uint32_t val)
63
{
64
out_be32(socrates_fpga_pic_iobase + reg, val);
65
}
66
67
static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
68
{
69
uint32_t cause;
70
unsigned long flags;
71
int i;
72
73
/* Check irq line routed to the MPIC */
74
for (i = 0; i < 3; i++) {
75
if (irq == socrates_fpga_irqs[i])
76
break;
77
}
78
if (i == 3)
79
return NO_IRQ;
80
81
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
82
cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
83
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
84
for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
85
if (cause >> (i + 16))
86
break;
87
}
88
return irq_linear_revmap(socrates_fpga_pic_irq_host,
89
(irq_hw_number_t)i);
90
}
91
92
void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
93
{
94
struct irq_chip *chip = irq_desc_get_chip(desc);
95
unsigned int cascade_irq;
96
97
/*
98
* See if we actually have an interrupt, call generic handling code if
99
* we do.
100
*/
101
cascade_irq = socrates_fpga_pic_get_irq(irq);
102
103
if (cascade_irq != NO_IRQ)
104
generic_handle_irq(cascade_irq);
105
chip->irq_eoi(&desc->irq_data);
106
}
107
108
static void socrates_fpga_pic_ack(struct irq_data *d)
109
{
110
unsigned long flags;
111
unsigned int irq_line, hwirq = irqd_to_hwirq(d);
112
uint32_t mask;
113
114
irq_line = fpga_irqs[hwirq].irq_line;
115
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
116
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
117
& SOCRATES_FPGA_IRQ_MASK;
118
mask |= (1 << (hwirq + 16));
119
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
120
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
121
}
122
123
static void socrates_fpga_pic_mask(struct irq_data *d)
124
{
125
unsigned long flags;
126
unsigned int hwirq = irqd_to_hwirq(d);
127
int irq_line;
128
u32 mask;
129
130
irq_line = fpga_irqs[hwirq].irq_line;
131
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
132
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
133
& SOCRATES_FPGA_IRQ_MASK;
134
mask &= ~(1 << hwirq);
135
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
136
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
137
}
138
139
static void socrates_fpga_pic_mask_ack(struct irq_data *d)
140
{
141
unsigned long flags;
142
unsigned int hwirq = irqd_to_hwirq(d);
143
int irq_line;
144
u32 mask;
145
146
irq_line = fpga_irqs[hwirq].irq_line;
147
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
148
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
149
& SOCRATES_FPGA_IRQ_MASK;
150
mask &= ~(1 << hwirq);
151
mask |= (1 << (hwirq + 16));
152
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
153
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
154
}
155
156
static void socrates_fpga_pic_unmask(struct irq_data *d)
157
{
158
unsigned long flags;
159
unsigned int hwirq = irqd_to_hwirq(d);
160
int irq_line;
161
u32 mask;
162
163
irq_line = fpga_irqs[hwirq].irq_line;
164
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
165
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
166
& SOCRATES_FPGA_IRQ_MASK;
167
mask |= (1 << hwirq);
168
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
169
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
170
}
171
172
static void socrates_fpga_pic_eoi(struct irq_data *d)
173
{
174
unsigned long flags;
175
unsigned int hwirq = irqd_to_hwirq(d);
176
int irq_line;
177
u32 mask;
178
179
irq_line = fpga_irqs[hwirq].irq_line;
180
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
181
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
182
& SOCRATES_FPGA_IRQ_MASK;
183
mask |= (1 << (hwirq + 16));
184
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
185
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
186
}
187
188
static int socrates_fpga_pic_set_type(struct irq_data *d,
189
unsigned int flow_type)
190
{
191
unsigned long flags;
192
unsigned int hwirq = irqd_to_hwirq(d);
193
int polarity;
194
u32 mask;
195
196
if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
197
return -EINVAL;
198
199
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
200
case IRQ_TYPE_LEVEL_HIGH:
201
polarity = 1;
202
break;
203
case IRQ_TYPE_LEVEL_LOW:
204
polarity = 0;
205
break;
206
default:
207
return -EINVAL;
208
}
209
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
210
mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
211
if (polarity)
212
mask |= (1 << hwirq);
213
else
214
mask &= ~(1 << hwirq);
215
socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
216
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
217
return 0;
218
}
219
220
static struct irq_chip socrates_fpga_pic_chip = {
221
.name = "FPGA-PIC",
222
.irq_ack = socrates_fpga_pic_ack,
223
.irq_mask = socrates_fpga_pic_mask,
224
.irq_mask_ack = socrates_fpga_pic_mask_ack,
225
.irq_unmask = socrates_fpga_pic_unmask,
226
.irq_eoi = socrates_fpga_pic_eoi,
227
.irq_set_type = socrates_fpga_pic_set_type,
228
};
229
230
static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
231
irq_hw_number_t hwirq)
232
{
233
/* All interrupts are LEVEL sensitive */
234
irq_set_status_flags(virq, IRQ_LEVEL);
235
irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
236
handle_fasteoi_irq);
237
238
return 0;
239
}
240
241
static int socrates_fpga_pic_host_xlate(struct irq_host *h,
242
struct device_node *ct, const u32 *intspec, unsigned int intsize,
243
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
244
{
245
struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
246
247
*out_hwirq = intspec[0];
248
if (fpga_irq->type == IRQ_TYPE_NONE) {
249
/* type is configurable */
250
if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
251
intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
252
pr_warning("FPGA PIC: invalid irq type, "
253
"setting default active low\n");
254
*out_flags = IRQ_TYPE_LEVEL_LOW;
255
} else {
256
*out_flags = intspec[1];
257
}
258
} else {
259
/* type is fixed */
260
*out_flags = fpga_irq->type;
261
}
262
263
/* Use specified interrupt routing */
264
if (intspec[2] <= 2)
265
fpga_irq->irq_line = intspec[2];
266
else
267
pr_warning("FPGA PIC: invalid irq routing\n");
268
269
return 0;
270
}
271
272
static struct irq_host_ops socrates_fpga_pic_host_ops = {
273
.map = socrates_fpga_pic_host_map,
274
.xlate = socrates_fpga_pic_host_xlate,
275
};
276
277
void socrates_fpga_pic_init(struct device_node *pic)
278
{
279
unsigned long flags;
280
int i;
281
282
/* Setup an irq_host structure */
283
socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
284
SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
285
SOCRATES_FPGA_NUM_IRQS);
286
if (socrates_fpga_pic_irq_host == NULL) {
287
pr_err("FPGA PIC: Unable to allocate host\n");
288
return;
289
}
290
291
for (i = 0; i < 3; i++) {
292
socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
293
if (socrates_fpga_irqs[i] == NO_IRQ) {
294
pr_warning("FPGA PIC: can't get irq%d.\n", i);
295
continue;
296
}
297
irq_set_chained_handler(socrates_fpga_irqs[i],
298
socrates_fpga_pic_cascade);
299
}
300
301
socrates_fpga_pic_iobase = of_iomap(pic, 0);
302
303
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
304
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
305
SOCRATES_FPGA_IRQ_MASK << 16);
306
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
307
SOCRATES_FPGA_IRQ_MASK << 16);
308
socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
309
SOCRATES_FPGA_IRQ_MASK << 16);
310
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
311
312
pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
313
}
314
315