Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-pxa/irq.c
10817 views
1
/*
2
* linux/arch/arm/mach-pxa/irq.c
3
*
4
* Generic PXA IRQ handling
5
*
6
* Author: Nicolas Pitre
7
* Created: Jun 15, 2001
8
* Copyright: MontaVista Software Inc.
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License version 2 as
12
* published by the Free Software Foundation.
13
*/
14
15
#include <linux/init.h>
16
#include <linux/module.h>
17
#include <linux/interrupt.h>
18
#include <linux/syscore_ops.h>
19
#include <linux/io.h>
20
#include <linux/irq.h>
21
22
#include <mach/hardware.h>
23
#include <mach/irqs.h>
24
#include <mach/gpio.h>
25
26
#include "generic.h"
27
28
#define IRQ_BASE (void __iomem *)io_p2v(0x40d00000)
29
30
#define ICIP (0x000)
31
#define ICMR (0x004)
32
#define ICLR (0x008)
33
#define ICFR (0x00c)
34
#define ICPR (0x010)
35
#define ICCR (0x014)
36
#define ICHP (0x018)
37
#define IPR(i) (((i) < 32) ? (0x01c + ((i) << 2)) : \
38
((i) < 64) ? (0x0b0 + (((i) - 32) << 2)) : \
39
(0x144 + (((i) - 64) << 2)))
40
#define IPR_VALID (1 << 31)
41
#define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f)
42
43
#define MAX_INTERNAL_IRQS 128
44
45
/*
46
* This is for peripheral IRQs internal to the PXA chip.
47
*/
48
49
static int pxa_internal_irq_nr;
50
51
static inline int cpu_has_ipr(void)
52
{
53
return !cpu_is_pxa25x();
54
}
55
56
static inline void __iomem *irq_base(int i)
57
{
58
static unsigned long phys_base[] = {
59
0x40d00000,
60
0x40d0009c,
61
0x40d00130,
62
};
63
64
return (void __iomem *)io_p2v(phys_base[i]);
65
}
66
67
static void pxa_mask_irq(struct irq_data *d)
68
{
69
void __iomem *base = irq_data_get_irq_chip_data(d);
70
uint32_t icmr = __raw_readl(base + ICMR);
71
72
icmr &= ~(1 << IRQ_BIT(d->irq));
73
__raw_writel(icmr, base + ICMR);
74
}
75
76
static void pxa_unmask_irq(struct irq_data *d)
77
{
78
void __iomem *base = irq_data_get_irq_chip_data(d);
79
uint32_t icmr = __raw_readl(base + ICMR);
80
81
icmr |= 1 << IRQ_BIT(d->irq);
82
__raw_writel(icmr, base + ICMR);
83
}
84
85
static struct irq_chip pxa_internal_irq_chip = {
86
.name = "SC",
87
.irq_ack = pxa_mask_irq,
88
.irq_mask = pxa_mask_irq,
89
.irq_unmask = pxa_unmask_irq,
90
};
91
92
/*
93
* GPIO IRQs for GPIO 0 and 1
94
*/
95
static int pxa_set_low_gpio_type(struct irq_data *d, unsigned int type)
96
{
97
int gpio = d->irq - IRQ_GPIO0;
98
99
if (__gpio_is_occupied(gpio)) {
100
pr_err("%s failed: GPIO is configured\n", __func__);
101
return -EINVAL;
102
}
103
104
if (type & IRQ_TYPE_EDGE_RISING)
105
GRER0 |= GPIO_bit(gpio);
106
else
107
GRER0 &= ~GPIO_bit(gpio);
108
109
if (type & IRQ_TYPE_EDGE_FALLING)
110
GFER0 |= GPIO_bit(gpio);
111
else
112
GFER0 &= ~GPIO_bit(gpio);
113
114
return 0;
115
}
116
117
static void pxa_ack_low_gpio(struct irq_data *d)
118
{
119
GEDR0 = (1 << (d->irq - IRQ_GPIO0));
120
}
121
122
static struct irq_chip pxa_low_gpio_chip = {
123
.name = "GPIO-l",
124
.irq_ack = pxa_ack_low_gpio,
125
.irq_mask = pxa_mask_irq,
126
.irq_unmask = pxa_unmask_irq,
127
.irq_set_type = pxa_set_low_gpio_type,
128
};
129
130
static void __init pxa_init_low_gpio_irq(set_wake_t fn)
131
{
132
int irq;
133
134
/* clear edge detection on GPIO 0 and 1 */
135
GFER0 &= ~0x3;
136
GRER0 &= ~0x3;
137
GEDR0 = 0x3;
138
139
for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
140
irq_set_chip_and_handler(irq, &pxa_low_gpio_chip,
141
handle_edge_irq);
142
irq_set_chip_data(irq, irq_base(0));
143
set_irq_flags(irq, IRQF_VALID);
144
}
145
146
pxa_low_gpio_chip.irq_set_wake = fn;
147
}
148
149
void __init pxa_init_irq(int irq_nr, set_wake_t fn)
150
{
151
int irq, i, n;
152
153
BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
154
155
pxa_internal_irq_nr = irq_nr;
156
157
for (n = 0; n < irq_nr; n += 32) {
158
void __iomem *base = irq_base(n >> 5);
159
160
__raw_writel(0, base + ICMR); /* disable all IRQs */
161
__raw_writel(0, base + ICLR); /* all IRQs are IRQ, not FIQ */
162
for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
163
/* initialize interrupt priority */
164
if (cpu_has_ipr())
165
__raw_writel(i | IPR_VALID, IRQ_BASE + IPR(i));
166
167
irq = PXA_IRQ(i);
168
irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
169
handle_level_irq);
170
irq_set_chip_data(irq, base);
171
set_irq_flags(irq, IRQF_VALID);
172
}
173
}
174
175
/* only unmasked interrupts kick us out of idle */
176
__raw_writel(1, irq_base(0) + ICCR);
177
178
pxa_internal_irq_chip.irq_set_wake = fn;
179
pxa_init_low_gpio_irq(fn);
180
}
181
182
#ifdef CONFIG_PM
183
static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
184
static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
185
186
static int pxa_irq_suspend(void)
187
{
188
int i;
189
190
for (i = 0; i < pxa_internal_irq_nr / 32; i++) {
191
void __iomem *base = irq_base(i);
192
193
saved_icmr[i] = __raw_readl(base + ICMR);
194
__raw_writel(0, base + ICMR);
195
}
196
197
if (cpu_has_ipr()) {
198
for (i = 0; i < pxa_internal_irq_nr; i++)
199
saved_ipr[i] = __raw_readl(IRQ_BASE + IPR(i));
200
}
201
202
return 0;
203
}
204
205
static void pxa_irq_resume(void)
206
{
207
int i;
208
209
for (i = 0; i < pxa_internal_irq_nr / 32; i++) {
210
void __iomem *base = irq_base(i);
211
212
__raw_writel(saved_icmr[i], base + ICMR);
213
__raw_writel(0, base + ICLR);
214
}
215
216
if (cpu_has_ipr())
217
for (i = 0; i < pxa_internal_irq_nr; i++)
218
__raw_writel(saved_ipr[i], IRQ_BASE + IPR(i));
219
220
__raw_writel(1, IRQ_BASE + ICCR);
221
}
222
#else
223
#define pxa_irq_suspend NULL
224
#define pxa_irq_resume NULL
225
#endif
226
227
struct syscore_ops pxa_irq_syscore_ops = {
228
.suspend = pxa_irq_suspend,
229
.resume = pxa_irq_resume,
230
};
231
232