Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/dma/ipu/ipu_irq.c
15111 views
1
/*
2
* Copyright (C) 2008
3
* Guennadi Liakhovetski, DENX Software Engineering, <[email protected]>
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
#include <linux/init.h>
11
#include <linux/err.h>
12
#include <linux/spinlock.h>
13
#include <linux/delay.h>
14
#include <linux/clk.h>
15
#include <linux/irq.h>
16
#include <linux/io.h>
17
18
#include <mach/ipu.h>
19
20
#include "ipu_intern.h"
21
22
/*
23
* Register read / write - shall be inlined by the compiler
24
*/
25
static u32 ipu_read_reg(struct ipu *ipu, unsigned long reg)
26
{
27
return __raw_readl(ipu->reg_ipu + reg);
28
}
29
30
static void ipu_write_reg(struct ipu *ipu, u32 value, unsigned long reg)
31
{
32
__raw_writel(value, ipu->reg_ipu + reg);
33
}
34
35
36
/*
37
* IPU IRQ chip driver
38
*/
39
40
#define IPU_IRQ_NR_FN_BANKS 3
41
#define IPU_IRQ_NR_ERR_BANKS 2
42
#define IPU_IRQ_NR_BANKS (IPU_IRQ_NR_FN_BANKS + IPU_IRQ_NR_ERR_BANKS)
43
44
struct ipu_irq_bank {
45
unsigned int control;
46
unsigned int status;
47
spinlock_t lock;
48
struct ipu *ipu;
49
};
50
51
static struct ipu_irq_bank irq_bank[IPU_IRQ_NR_BANKS] = {
52
/* 3 groups of functional interrupts */
53
{
54
.control = IPU_INT_CTRL_1,
55
.status = IPU_INT_STAT_1,
56
}, {
57
.control = IPU_INT_CTRL_2,
58
.status = IPU_INT_STAT_2,
59
}, {
60
.control = IPU_INT_CTRL_3,
61
.status = IPU_INT_STAT_3,
62
},
63
/* 2 groups of error interrupts */
64
{
65
.control = IPU_INT_CTRL_4,
66
.status = IPU_INT_STAT_4,
67
}, {
68
.control = IPU_INT_CTRL_5,
69
.status = IPU_INT_STAT_5,
70
},
71
};
72
73
struct ipu_irq_map {
74
unsigned int irq;
75
int source;
76
struct ipu_irq_bank *bank;
77
struct ipu *ipu;
78
};
79
80
static struct ipu_irq_map irq_map[CONFIG_MX3_IPU_IRQS];
81
/* Protects allocations from the above array of maps */
82
static DEFINE_MUTEX(map_lock);
83
/* Protects register accesses and individual mappings */
84
static DEFINE_SPINLOCK(bank_lock);
85
86
static struct ipu_irq_map *src2map(unsigned int src)
87
{
88
int i;
89
90
for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++)
91
if (irq_map[i].source == src)
92
return irq_map + i;
93
94
return NULL;
95
}
96
97
static void ipu_irq_unmask(struct irq_data *d)
98
{
99
struct ipu_irq_map *map = irq_data_get_irq_chip_data(d);
100
struct ipu_irq_bank *bank;
101
uint32_t reg;
102
unsigned long lock_flags;
103
104
spin_lock_irqsave(&bank_lock, lock_flags);
105
106
bank = map->bank;
107
if (!bank) {
108
spin_unlock_irqrestore(&bank_lock, lock_flags);
109
pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq);
110
return;
111
}
112
113
reg = ipu_read_reg(bank->ipu, bank->control);
114
reg |= (1UL << (map->source & 31));
115
ipu_write_reg(bank->ipu, reg, bank->control);
116
117
spin_unlock_irqrestore(&bank_lock, lock_flags);
118
}
119
120
static void ipu_irq_mask(struct irq_data *d)
121
{
122
struct ipu_irq_map *map = irq_data_get_irq_chip_data(d);
123
struct ipu_irq_bank *bank;
124
uint32_t reg;
125
unsigned long lock_flags;
126
127
spin_lock_irqsave(&bank_lock, lock_flags);
128
129
bank = map->bank;
130
if (!bank) {
131
spin_unlock_irqrestore(&bank_lock, lock_flags);
132
pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq);
133
return;
134
}
135
136
reg = ipu_read_reg(bank->ipu, bank->control);
137
reg &= ~(1UL << (map->source & 31));
138
ipu_write_reg(bank->ipu, reg, bank->control);
139
140
spin_unlock_irqrestore(&bank_lock, lock_flags);
141
}
142
143
static void ipu_irq_ack(struct irq_data *d)
144
{
145
struct ipu_irq_map *map = irq_data_get_irq_chip_data(d);
146
struct ipu_irq_bank *bank;
147
unsigned long lock_flags;
148
149
spin_lock_irqsave(&bank_lock, lock_flags);
150
151
bank = map->bank;
152
if (!bank) {
153
spin_unlock_irqrestore(&bank_lock, lock_flags);
154
pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq);
155
return;
156
}
157
158
ipu_write_reg(bank->ipu, 1UL << (map->source & 31), bank->status);
159
spin_unlock_irqrestore(&bank_lock, lock_flags);
160
}
161
162
/**
163
* ipu_irq_status() - returns the current interrupt status of the specified IRQ.
164
* @irq: interrupt line to get status for.
165
* @return: true if the interrupt is pending/asserted or false if the
166
* interrupt is not pending.
167
*/
168
bool ipu_irq_status(unsigned int irq)
169
{
170
struct ipu_irq_map *map = irq_get_chip_data(irq);
171
struct ipu_irq_bank *bank;
172
unsigned long lock_flags;
173
bool ret;
174
175
spin_lock_irqsave(&bank_lock, lock_flags);
176
bank = map->bank;
177
ret = bank && ipu_read_reg(bank->ipu, bank->status) &
178
(1UL << (map->source & 31));
179
spin_unlock_irqrestore(&bank_lock, lock_flags);
180
181
return ret;
182
}
183
184
/**
185
* ipu_irq_map() - map an IPU interrupt source to an IRQ number
186
* @source: interrupt source bit position (see below)
187
* @return: mapped IRQ number or negative error code
188
*
189
* The source parameter has to be explained further. On i.MX31 IPU has 137 IRQ
190
* sources, they are broken down in 5 32-bit registers, like 32, 32, 24, 32, 17.
191
* However, the source argument of this function is not the sequence number of
192
* the possible IRQ, but rather its bit position. So, first interrupt in fourth
193
* register has source number 96, and not 88. This makes calculations easier,
194
* and also provides forward compatibility with any future IPU implementations
195
* with any interrupt bit assignments.
196
*/
197
int ipu_irq_map(unsigned int source)
198
{
199
int i, ret = -ENOMEM;
200
struct ipu_irq_map *map;
201
202
might_sleep();
203
204
mutex_lock(&map_lock);
205
map = src2map(source);
206
if (map) {
207
pr_err("IPU: Source %u already mapped to IRQ %u\n", source, map->irq);
208
ret = -EBUSY;
209
goto out;
210
}
211
212
for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
213
if (irq_map[i].source < 0) {
214
unsigned long lock_flags;
215
216
spin_lock_irqsave(&bank_lock, lock_flags);
217
irq_map[i].source = source;
218
irq_map[i].bank = irq_bank + source / 32;
219
spin_unlock_irqrestore(&bank_lock, lock_flags);
220
221
ret = irq_map[i].irq;
222
pr_debug("IPU: mapped source %u to IRQ %u\n",
223
source, ret);
224
break;
225
}
226
}
227
out:
228
mutex_unlock(&map_lock);
229
230
if (ret < 0)
231
pr_err("IPU: couldn't map source %u: %d\n", source, ret);
232
233
return ret;
234
}
235
236
/**
237
* ipu_irq_map() - map an IPU interrupt source to an IRQ number
238
* @source: interrupt source bit position (see ipu_irq_map())
239
* @return: 0 or negative error code
240
*/
241
int ipu_irq_unmap(unsigned int source)
242
{
243
int i, ret = -EINVAL;
244
245
might_sleep();
246
247
mutex_lock(&map_lock);
248
for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
249
if (irq_map[i].source == source) {
250
unsigned long lock_flags;
251
252
pr_debug("IPU: unmapped source %u from IRQ %u\n",
253
source, irq_map[i].irq);
254
255
spin_lock_irqsave(&bank_lock, lock_flags);
256
irq_map[i].source = -EINVAL;
257
irq_map[i].bank = NULL;
258
spin_unlock_irqrestore(&bank_lock, lock_flags);
259
260
ret = 0;
261
break;
262
}
263
}
264
mutex_unlock(&map_lock);
265
266
return ret;
267
}
268
269
/* Chained IRQ handler for IPU error interrupt */
270
static void ipu_irq_err(unsigned int irq, struct irq_desc *desc)
271
{
272
struct ipu *ipu = irq_get_handler_data(irq);
273
u32 status;
274
int i, line;
275
276
for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) {
277
struct ipu_irq_bank *bank = irq_bank + i;
278
279
spin_lock(&bank_lock);
280
status = ipu_read_reg(ipu, bank->status);
281
/*
282
* Don't think we have to clear all interrupts here, they will
283
* be acked by ->handle_irq() (handle_level_irq). However, we
284
* might want to clear unhandled interrupts after the loop...
285
*/
286
status &= ipu_read_reg(ipu, bank->control);
287
spin_unlock(&bank_lock);
288
while ((line = ffs(status))) {
289
struct ipu_irq_map *map;
290
291
line--;
292
status &= ~(1UL << line);
293
294
spin_lock(&bank_lock);
295
map = src2map(32 * i + line);
296
if (map)
297
irq = map->irq;
298
spin_unlock(&bank_lock);
299
300
if (!map) {
301
pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
302
line, i);
303
continue;
304
}
305
generic_handle_irq(irq);
306
}
307
}
308
}
309
310
/* Chained IRQ handler for IPU function interrupt */
311
static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc)
312
{
313
struct ipu *ipu = irq_desc_get_handler_data(desc);
314
u32 status;
315
int i, line;
316
317
for (i = 0; i < IPU_IRQ_NR_FN_BANKS; i++) {
318
struct ipu_irq_bank *bank = irq_bank + i;
319
320
spin_lock(&bank_lock);
321
status = ipu_read_reg(ipu, bank->status);
322
/* Not clearing all interrupts, see above */
323
status &= ipu_read_reg(ipu, bank->control);
324
spin_unlock(&bank_lock);
325
while ((line = ffs(status))) {
326
struct ipu_irq_map *map;
327
328
line--;
329
status &= ~(1UL << line);
330
331
spin_lock(&bank_lock);
332
map = src2map(32 * i + line);
333
if (map)
334
irq = map->irq;
335
spin_unlock(&bank_lock);
336
337
if (!map) {
338
pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
339
line, i);
340
continue;
341
}
342
generic_handle_irq(irq);
343
}
344
}
345
}
346
347
static struct irq_chip ipu_irq_chip = {
348
.name = "ipu_irq",
349
.irq_ack = ipu_irq_ack,
350
.irq_mask = ipu_irq_mask,
351
.irq_unmask = ipu_irq_unmask,
352
};
353
354
/* Install the IRQ handler */
355
int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev)
356
{
357
struct ipu_platform_data *pdata = dev->dev.platform_data;
358
unsigned int irq, irq_base, i;
359
360
irq_base = pdata->irq_base;
361
362
for (i = 0; i < IPU_IRQ_NR_BANKS; i++)
363
irq_bank[i].ipu = ipu;
364
365
for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
366
int ret;
367
368
irq = irq_base + i;
369
ret = irq_set_chip(irq, &ipu_irq_chip);
370
if (ret < 0)
371
return ret;
372
ret = irq_set_chip_data(irq, irq_map + i);
373
if (ret < 0)
374
return ret;
375
irq_map[i].ipu = ipu;
376
irq_map[i].irq = irq;
377
irq_map[i].source = -EINVAL;
378
irq_set_handler(irq, handle_level_irq);
379
#ifdef CONFIG_ARM
380
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
381
#endif
382
}
383
384
irq_set_handler_data(ipu->irq_fn, ipu);
385
irq_set_chained_handler(ipu->irq_fn, ipu_irq_fn);
386
387
irq_set_handler_data(ipu->irq_err, ipu);
388
irq_set_chained_handler(ipu->irq_err, ipu_irq_err);
389
390
return 0;
391
}
392
393
void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev)
394
{
395
struct ipu_platform_data *pdata = dev->dev.platform_data;
396
unsigned int irq, irq_base;
397
398
irq_base = pdata->irq_base;
399
400
irq_set_chained_handler(ipu->irq_fn, NULL);
401
irq_set_handler_data(ipu->irq_fn, NULL);
402
403
irq_set_chained_handler(ipu->irq_err, NULL);
404
irq_set_handler_data(ipu->irq_err, NULL);
405
406
for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) {
407
#ifdef CONFIG_ARM
408
set_irq_flags(irq, 0);
409
#endif
410
irq_set_chip(irq, NULL);
411
irq_set_chip_data(irq, NULL);
412
}
413
}
414
415