Blame view
drivers/irqchip/irq-vic.c
14.4 KB
fa0fe48fc [ARM] Separate VI... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * linux/arch/arm/common/vic.c * * Copyright (C) 1999 - 2003 ARM Limited * Copyright (C) 2000 Deep Blue Solutions Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
bb06b7371 ARM: 5881/1: vic.... |
21 |
|
f9b28ccbc ARM: vic: device ... |
22 |
#include <linux/export.h> |
fa0fe48fc [ARM] Separate VI... |
23 24 |
#include <linux/init.h> #include <linux/list.h> |
fced80c73 [ARM] Convert asm... |
25 |
#include <linux/io.h> |
bc895b598 irqchip: vic: add... |
26 |
#include <linux/irq.h> |
41a83e06e irqchip: Prepare ... |
27 |
#include <linux/irqchip.h> |
f6da9fe45 irqchip: vic: Pro... |
28 |
#include <linux/irqchip/chained_irq.h> |
f9b28ccbc ARM: vic: device ... |
29 30 31 32 |
#include <linux/irqdomain.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> |
328f5cc30 ARM: Use struct s... |
33 |
#include <linux/syscore_ops.h> |
59fcf48fd ARM: 5696/1: Incl... |
34 |
#include <linux/device.h> |
f17a1f06d ARM: 5636/1: Move... |
35 |
#include <linux/amba/bus.h> |
9e47b8bf9 irqchip: Move ARM... |
36 |
#include <linux/irqchip/arm-vic.h> |
fa0fe48fc [ARM] Separate VI... |
37 |
|
1558368eb ARM: vic: MULTI_I... |
38 |
#include <asm/exception.h> |
f36a3bb1a arm: Move the set... |
39 |
#include <asm/irq.h> |
fa0fe48fc [ARM] Separate VI... |
40 |
|
cf21af545 ARM: VIC: shrink ... |
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#define VIC_IRQ_STATUS 0x00 #define VIC_FIQ_STATUS 0x04 #define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */ #define VIC_INT_SOFT 0x18 #define VIC_INT_SOFT_CLEAR 0x1c #define VIC_PROTECT 0x20 #define VIC_PL190_VECT_ADDR 0x30 /* PL190 only */ #define VIC_PL190_DEF_VECT_ADDR 0x34 /* PL190 only */ #define VIC_VECT_ADDR0 0x100 /* 0 to 15 (0..31 PL192) */ #define VIC_VECT_CNTL0 0x200 /* 0 to 15 (0..31 PL192) */ #define VIC_ITCR 0x300 /* VIC test control register */ #define VIC_VECT_CNTL_ENABLE (1 << 5) #define VIC_PL192_VECT_ADDR 0xF00 |
c07f87f22 [ARM] VIC: Add po... |
57 58 |
/** * struct vic_device - VIC PM device |
e641b987c irqchip: support ... |
59 |
* @parent_irq: The parent IRQ number of the VIC if cascaded, or 0. |
c07f87f22 [ARM] VIC: Add po... |
60 61 |
* @irq: The IRQ number for the base of the VIC. * @base: The register base for the VIC. |
ce94df9c0 ARM: 7395/1: VIC:... |
62 |
* @valid_sources: A bitmask of valid interrupts |
c07f87f22 [ARM] VIC: Add po... |
63 64 65 66 67 68 |
* @resume_sources: A bitmask of interrupts for resume. * @resume_irqs: The IRQs enabled for resume. * @int_select: Save for VIC_INT_SELECT. * @int_enable: Save for VIC_INT_ENABLE. * @soft_int: Save for VIC_INT_SOFT. * @protect: Save for VIC_PROTECT. |
f9b28ccbc ARM: vic: device ... |
69 |
* @domain: The IRQ domain for the VIC. |
c07f87f22 [ARM] VIC: Add po... |
70 71 |
*/ struct vic_device { |
c07f87f22 [ARM] VIC: Add po... |
72 73 |
void __iomem *base; int irq; |
ce94df9c0 ARM: 7395/1: VIC:... |
74 |
u32 valid_sources; |
c07f87f22 [ARM] VIC: Add po... |
75 76 77 78 79 80 |
u32 resume_sources; u32 resume_irqs; u32 int_select; u32 int_enable; u32 soft_int; u32 protect; |
75294957b irq_domain: Remov... |
81 |
struct irq_domain *domain; |
c07f87f22 [ARM] VIC: Add po... |
82 83 84 85 |
}; /* we cannot allocate memory when VICs are initially registered */ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; |
bb06b7371 ARM: 5881/1: vic.... |
86 |
static int vic_id; |
c07f87f22 [ARM] VIC: Add po... |
87 |
|
a03680291 ARM: remove mach ... |
88 |
static void vic_handle_irq(struct pt_regs *regs); |
bb06b7371 ARM: 5881/1: vic.... |
89 90 91 92 |
/** * vic_init2 - common initialisation code * @base: Base of the VIC. * |
b595076a1 tree-wide: fix co... |
93 |
* Common initialisation code for registration |
bb06b7371 ARM: 5881/1: vic.... |
94 95 96 97 98 99 100 101 102 103 104 105 106 |
* and resume. */ static void vic_init2(void __iomem *base) { int i; for (i = 0; i < 16; i++) { void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); writel(VIC_VECT_CNTL_ENABLE | i, reg); } writel(32, base + VIC_PL190_DEF_VECT_ADDR); } |
c07f87f22 [ARM] VIC: Add po... |
107 |
|
328f5cc30 ARM: Use struct s... |
108 109 |
#ifdef CONFIG_PM static void resume_one_vic(struct vic_device *vic) |
c07f87f22 [ARM] VIC: Add po... |
110 |
{ |
c07f87f22 [ARM] VIC: Add po... |
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
void __iomem *base = vic->base; printk(KERN_DEBUG "%s: resuming vic at %p ", __func__, base); /* re-initialise static settings */ vic_init2(base); writel(vic->int_select, base + VIC_INT_SELECT); writel(vic->protect, base + VIC_PROTECT); /* set the enabled ints and then clear the non-enabled */ writel(vic->int_enable, base + VIC_INT_ENABLE); writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR); /* and the same for the soft-int register */ writel(vic->soft_int, base + VIC_INT_SOFT); writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR); |
328f5cc30 ARM: Use struct s... |
130 |
} |
c07f87f22 [ARM] VIC: Add po... |
131 |
|
328f5cc30 ARM: Use struct s... |
132 133 134 135 136 137 |
static void vic_resume(void) { int id; for (id = vic_id - 1; id >= 0; id--) resume_one_vic(vic_devices + id); |
c07f87f22 [ARM] VIC: Add po... |
138 |
} |
328f5cc30 ARM: Use struct s... |
139 |
static void suspend_one_vic(struct vic_device *vic) |
c07f87f22 [ARM] VIC: Add po... |
140 |
{ |
c07f87f22 [ARM] VIC: Add po... |
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
void __iomem *base = vic->base; printk(KERN_DEBUG "%s: suspending vic at %p ", __func__, base); vic->int_select = readl(base + VIC_INT_SELECT); vic->int_enable = readl(base + VIC_INT_ENABLE); vic->soft_int = readl(base + VIC_INT_SOFT); vic->protect = readl(base + VIC_PROTECT); /* set the interrupts (if any) that are used for * resuming the system */ writel(vic->resume_irqs, base + VIC_INT_ENABLE); writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR); |
328f5cc30 ARM: Use struct s... |
156 157 158 159 160 161 162 163 |
} static int vic_suspend(void) { int id; for (id = 0; id < vic_id; id++) suspend_one_vic(vic_devices + id); |
c07f87f22 [ARM] VIC: Add po... |
164 165 166 |
return 0; } |
df042a5f4 irqchip/vic: Make... |
167 |
static struct syscore_ops vic_syscore_ops = { |
328f5cc30 ARM: Use struct s... |
168 169 |
.suspend = vic_suspend, .resume = vic_resume, |
c07f87f22 [ARM] VIC: Add po... |
170 171 172 |
}; /** |
c07f87f22 [ARM] VIC: Add po... |
173 174 175 176 177 178 179 180 |
* vic_pm_init - initicall to register VIC pm * * This is called via late_initcall() to register * the resources for the VICs due to the early * nature of the VIC's registration. */ static int __init vic_pm_init(void) { |
328f5cc30 ARM: Use struct s... |
181 182 |
if (vic_id > 0) register_syscore_ops(&vic_syscore_ops); |
c07f87f22 [ARM] VIC: Add po... |
183 184 185 |
return 0; } |
c07f87f22 [ARM] VIC: Add po... |
186 |
late_initcall(vic_pm_init); |
f9b28ccbc ARM: vic: device ... |
187 |
#endif /* CONFIG_PM */ |
c07f87f22 [ARM] VIC: Add po... |
188 |
|
ce94df9c0 ARM: 7395/1: VIC:... |
189 190 191 192 193 194 195 196 197 |
static struct irq_chip vic_chip; static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct vic_device *v = d->host_data; /* Skip invalid IRQs, only register handlers for the real ones */ if (!(v->valid_sources & (1 << hwirq))) |
d94ea3f6d irqchip: Return -... |
198 |
return -EPERM; |
ce94df9c0 ARM: 7395/1: VIC:... |
199 200 |
irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq); irq_set_chip_data(irq, v->base); |
d17cab445 irqchip: Kill off... |
201 |
irq_set_probe(irq); |
ce94df9c0 ARM: 7395/1: VIC:... |
202 203 |
return 0; } |
a03680291 ARM: remove mach ... |
204 205 206 207 208 209 210 211 212 213 214 215 216 |
/* * Handle each interrupt in a single VIC. Returns non-zero if we've * handled at least one interrupt. This reads the status register * before handling each interrupt, which is necessary given that * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. */ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) { u32 stat, irq; int handled = 0; while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { irq = ffs(stat) - 1; |
0af83b3b0 irqchip: vic: Con... |
217 |
handle_domain_irq(vic->domain, irq, regs); |
a03680291 ARM: remove mach ... |
218 219 220 221 222 |
handled = 1; } return handled; } |
bd0b9ac40 genirq: Remove ir... |
223 |
static void vic_handle_irq_cascaded(struct irq_desc *desc) |
e641b987c irqchip: support ... |
224 225 |
{ u32 stat, hwirq; |
f6da9fe45 irqchip: vic: Pro... |
226 |
struct irq_chip *host_chip = irq_desc_get_chip(desc); |
e641b987c irqchip: support ... |
227 |
struct vic_device *vic = irq_desc_get_handler_data(desc); |
f6da9fe45 irqchip: vic: Pro... |
228 |
chained_irq_enter(host_chip, desc); |
e641b987c irqchip: support ... |
229 230 231 232 |
while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { hwirq = ffs(stat) - 1; generic_handle_irq(irq_find_mapping(vic->domain, hwirq)); } |
f6da9fe45 irqchip: vic: Pro... |
233 234 |
chained_irq_exit(host_chip, desc); |
e641b987c irqchip: support ... |
235 |
} |
a03680291 ARM: remove mach ... |
236 237 238 239 |
/* * Keep iterating over all registered VIC's until there are no pending * interrupts. */ |
8783dd3a3 irqchip: Remove a... |
240 |
static void __exception_irq_entry vic_handle_irq(struct pt_regs *regs) |
a03680291 ARM: remove mach ... |
241 242 243 244 245 246 247 248 |
{ int i, handled; do { for (i = 0, handled = 0; i < vic_id; ++i) handled |= handle_one_vic(&vic_devices[i], regs); } while (handled); } |
960097365 irqchip: Constify... |
249 |
static const struct irq_domain_ops vic_irqdomain_ops = { |
ce94df9c0 ARM: 7395/1: VIC:... |
250 251 252 |
.map = vic_irqdomain_map, .xlate = irq_domain_xlate_onetwocell, }; |
bb06b7371 ARM: 5881/1: vic.... |
253 |
/** |
f9b28ccbc ARM: vic: device ... |
254 |
* vic_register() - Register a VIC. |
bb06b7371 ARM: 5881/1: vic.... |
255 |
* @base: The base address of the VIC. |
e641b987c irqchip: support ... |
256 |
* @parent_irq: The parent IRQ if cascaded, else 0. |
bb06b7371 ARM: 5881/1: vic.... |
257 |
* @irq: The base IRQ for the VIC. |
fa943bed6 ARM: 7394/1: VIC:... |
258 |
* @valid_sources: bitmask of valid interrupts |
bb06b7371 ARM: 5881/1: vic.... |
259 |
* @resume_sources: bitmask of interrupts allowed for resume sources. |
f9b28ccbc ARM: vic: device ... |
260 |
* @node: The device tree node associated with the VIC. |
bb06b7371 ARM: 5881/1: vic.... |
261 262 263 264 |
* * Register the VIC with the system device tree so that it can be notified * of suspend and resume requests and ensure that the correct actions are * taken to re-instate the settings on resume. |
f9b28ccbc ARM: vic: device ... |
265 266 |
* * This also configures the IRQ domain for the VIC. |
bb06b7371 ARM: 5881/1: vic.... |
267 |
*/ |
e641b987c irqchip: support ... |
268 269 |
static void __init vic_register(void __iomem *base, unsigned int parent_irq, unsigned int irq, |
fa943bed6 ARM: 7394/1: VIC:... |
270 271 |
u32 valid_sources, u32 resume_sources, struct device_node *node) |
bb06b7371 ARM: 5881/1: vic.... |
272 273 |
{ struct vic_device *v; |
5ced33bc0 ARM: 7611/1: VIC:... |
274 |
int i; |
bb06b7371 ARM: 5881/1: vic.... |
275 |
|
f9b28ccbc ARM: vic: device ... |
276 |
if (vic_id >= ARRAY_SIZE(vic_devices)) { |
bb06b7371 ARM: 5881/1: vic.... |
277 278 |
printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR ", __func__); |
f9b28ccbc ARM: vic: device ... |
279 |
return; |
bb06b7371 ARM: 5881/1: vic.... |
280 |
} |
f9b28ccbc ARM: vic: device ... |
281 282 283 |
v = &vic_devices[vic_id]; v->base = base; |
ce94df9c0 ARM: 7395/1: VIC:... |
284 |
v->valid_sources = valid_sources; |
f9b28ccbc ARM: vic: device ... |
285 |
v->resume_sources = resume_sources; |
7fb7d8ae1 ARM: VIC: set han... |
286 |
set_handle_irq(vic_handle_irq); |
f9b28ccbc ARM: vic: device ... |
287 |
vic_id++; |
e641b987c irqchip: support ... |
288 289 |
if (parent_irq) { |
9f2135419 irqchip/vic: Cons... |
290 291 |
irq_set_chained_handler_and_data(parent_irq, vic_handle_irq_cascaded, v); |
e641b987c irqchip: support ... |
292 |
} |
07c9249f1 ARM: 7554/1: VIC:... |
293 |
v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, |
fa943bed6 ARM: 7394/1: VIC:... |
294 |
&vic_irqdomain_ops, v); |
5ced33bc0 ARM: 7611/1: VIC:... |
295 296 297 298 |
/* create an IRQ mapping for each valid IRQ */ for (i = 0; i < fls(valid_sources); i++) if (valid_sources & (1 << i)) irq_create_mapping(v->domain, i); |
3b4df9dbd irqchip: vic: upd... |
299 300 301 302 303 |
/* If no base IRQ was passed, figure out our allocated base */ if (irq) v->irq = irq; else v->irq = irq_find_mapping(v->domain, 0); |
bb06b7371 ARM: 5881/1: vic.... |
304 |
} |
bb06b7371 ARM: 5881/1: vic.... |
305 |
|
f013c98dd ARM: vic: irq_dat... |
306 |
static void vic_ack_irq(struct irq_data *d) |
bb06b7371 ARM: 5881/1: vic.... |
307 |
{ |
f013c98dd ARM: vic: irq_dat... |
308 |
void __iomem *base = irq_data_get_irq_chip_data(d); |
f9b28ccbc ARM: vic: device ... |
309 |
unsigned int irq = d->hwirq; |
bb06b7371 ARM: 5881/1: vic.... |
310 311 312 313 |
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); /* moreover, clear the soft-triggered, in case it was the reason */ writel(1 << irq, base + VIC_INT_SOFT_CLEAR); } |
f013c98dd ARM: vic: irq_dat... |
314 |
static void vic_mask_irq(struct irq_data *d) |
bb06b7371 ARM: 5881/1: vic.... |
315 |
{ |
f013c98dd ARM: vic: irq_dat... |
316 |
void __iomem *base = irq_data_get_irq_chip_data(d); |
f9b28ccbc ARM: vic: device ... |
317 |
unsigned int irq = d->hwirq; |
bb06b7371 ARM: 5881/1: vic.... |
318 319 |
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); } |
f013c98dd ARM: vic: irq_dat... |
320 |
static void vic_unmask_irq(struct irq_data *d) |
bb06b7371 ARM: 5881/1: vic.... |
321 |
{ |
f013c98dd ARM: vic: irq_dat... |
322 |
void __iomem *base = irq_data_get_irq_chip_data(d); |
f9b28ccbc ARM: vic: device ... |
323 |
unsigned int irq = d->hwirq; |
bb06b7371 ARM: 5881/1: vic.... |
324 325 326 327 |
writel(1 << irq, base + VIC_INT_ENABLE); } #if defined(CONFIG_PM) |
c07f87f22 [ARM] VIC: Add po... |
328 329 330 331 332 333 334 335 336 337 338 339 340 |
static struct vic_device *vic_from_irq(unsigned int irq) { struct vic_device *v = vic_devices; unsigned int base_irq = irq & ~31; int id; for (id = 0; id < vic_id; id++, v++) { if (v->irq == base_irq) return v; } return NULL; } |
f013c98dd ARM: vic: irq_dat... |
341 |
static int vic_set_wake(struct irq_data *d, unsigned int on) |
c07f87f22 [ARM] VIC: Add po... |
342 |
{ |
f013c98dd ARM: vic: irq_dat... |
343 |
struct vic_device *v = vic_from_irq(d->irq); |
f9b28ccbc ARM: vic: device ... |
344 |
unsigned int off = d->hwirq; |
3f1a567d8 [ARM] VIC: Fix re... |
345 |
u32 bit = 1 << off; |
c07f87f22 [ARM] VIC: Add po... |
346 347 348 |
if (!v) return -EINVAL; |
3f1a567d8 [ARM] VIC: Fix re... |
349 350 |
if (!(bit & v->resume_sources)) return -EINVAL; |
c07f87f22 [ARM] VIC: Add po... |
351 |
if (on) |
3f1a567d8 [ARM] VIC: Fix re... |
352 |
v->resume_irqs |= bit; |
c07f87f22 [ARM] VIC: Add po... |
353 |
else |
3f1a567d8 [ARM] VIC: Fix re... |
354 |
v->resume_irqs &= ~bit; |
c07f87f22 [ARM] VIC: Add po... |
355 356 357 |
return 0; } |
c07f87f22 [ARM] VIC: Add po... |
358 |
#else |
c07f87f22 [ARM] VIC: Add po... |
359 360 |
#define vic_set_wake NULL #endif /* CONFIG_PM */ |
38c677cb9 [ARM] 3739/1: gen... |
361 |
static struct irq_chip vic_chip = { |
b0c4c8988 ARM: 6025/1: vic:... |
362 |
.name = "VIC", |
f013c98dd ARM: vic: irq_dat... |
363 364 365 366 |
.irq_ack = vic_ack_irq, .irq_mask = vic_mask_irq, .irq_unmask = vic_unmask_irq, .irq_set_wake = vic_set_wake, |
fa0fe48fc [ARM] Separate VI... |
367 |
}; |
b0c4c8988 ARM: 6025/1: vic:... |
368 369 370 371 372 |
static void __init vic_disable(void __iomem *base) { writel(0, base + VIC_INT_SELECT); writel(0, base + VIC_INT_ENABLE); writel(~0, base + VIC_INT_ENABLE_CLEAR); |
b0c4c8988 ARM: 6025/1: vic:... |
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
writel(0, base + VIC_ITCR); writel(~0, base + VIC_INT_SOFT_CLEAR); } static void __init vic_clear_interrupts(void __iomem *base) { unsigned int i; writel(0, base + VIC_PL190_VECT_ADDR); for (i = 0; i < 19; i++) { unsigned int value; value = readl(base + VIC_PL190_VECT_ADDR); writel(value, base + VIC_PL190_VECT_ADDR); } } |
bb06b7371 ARM: 5881/1: vic.... |
389 390 391 392 393 394 395 396 |
/* * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. * The original cell has 32 interrupts, while the modified one has 64, * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case * the probe function is called twice, with base set to offset 000 * and 020 within the page. We call this "second block". */ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, |
ad622671a ARM: 7183/1: vic:... |
397 |
u32 vic_sources, struct device_node *node) |
bb06b7371 ARM: 5881/1: vic.... |
398 399 400 401 402 |
{ unsigned int i; int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0; /* Disable all interrupts initially. */ |
b0c4c8988 ARM: 6025/1: vic:... |
403 |
vic_disable(base); |
bb06b7371 ARM: 5881/1: vic.... |
404 405 406 407 408 409 410 411 |
/* * Make sure we clear all existing interrupts. The vector registers * in this cell are after the second block of general registers, * so we can address them using standard offsets, but only from * the second base address, which is 0x20 in the page */ if (vic_2nd_block) { |
b0c4c8988 ARM: 6025/1: vic:... |
412 |
vic_clear_interrupts(base); |
bb06b7371 ARM: 5881/1: vic.... |
413 |
|
bb06b7371 ARM: 5881/1: vic.... |
414 415 416 417 418 419 420 421 |
/* ST has 16 vectors as well, but we don't enable them by now */ for (i = 0; i < 16; i++) { void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); writel(0, reg); } writel(32, base + VIC_PL190_DEF_VECT_ADDR); } |
e641b987c irqchip: support ... |
422 |
vic_register(base, 0, irq_start, vic_sources, 0, node); |
bb06b7371 ARM: 5881/1: vic.... |
423 |
} |
87e8824b4 [ARM] 5582/1: VIC... |
424 |
|
e641b987c irqchip: support ... |
425 |
void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, |
f9b28ccbc ARM: vic: device ... |
426 427 |
u32 vic_sources, u32 resume_sources, struct device_node *node) |
fa0fe48fc [ARM] Separate VI... |
428 429 |
{ unsigned int i; |
87e8824b4 [ARM] 5582/1: VIC... |
430 |
u32 cellid = 0; |
f17a1f06d ARM: 5636/1: Move... |
431 |
enum amba_vendor vendor; |
87e8824b4 [ARM] 5582/1: VIC... |
432 433 434 |
/* Identify which VIC cell this one is, by reading the ID */ for (i = 0; i < 4; i++) { |
d4f3add28 ARM: common/vic: ... |
435 436 |
void __iomem *addr; addr = (void __iomem *)((u32)base & PAGE_MASK) + 0xfe0 + (i * 4); |
87e8824b4 [ARM] 5582/1: VIC... |
437 438 439 440 441 442 443 444 |
cellid |= (readl(addr) & 0xff) << (8 * i); } vendor = (cellid >> 12) & 0xff; printk(KERN_INFO "VIC @%p: id 0x%08x, vendor 0x%02x ", base, cellid, vendor); switch(vendor) { |
f17a1f06d ARM: 5636/1: Move... |
445 |
case AMBA_VENDOR_ST: |
ad622671a ARM: 7183/1: vic:... |
446 |
vic_init_st(base, irq_start, vic_sources, node); |
87e8824b4 [ARM] 5582/1: VIC... |
447 448 449 450 451 |
return; default: printk(KERN_WARNING "VIC: unknown vendor, continuing anyways "); /* fall through */ |
f17a1f06d ARM: 5636/1: Move... |
452 |
case AMBA_VENDOR_ARM: |
87e8824b4 [ARM] 5582/1: VIC... |
453 454 |
break; } |
fa0fe48fc [ARM] Separate VI... |
455 |
|
fa0fe48fc [ARM] Separate VI... |
456 |
/* Disable all interrupts initially. */ |
b0c4c8988 ARM: 6025/1: vic:... |
457 |
vic_disable(base); |
fa0fe48fc [ARM] Separate VI... |
458 |
|
b0c4c8988 ARM: 6025/1: vic:... |
459 460 |
/* Make sure we clear all existing interrupts */ vic_clear_interrupts(base); |
fa0fe48fc [ARM] Separate VI... |
461 |
|
c07f87f22 [ARM] VIC: Add po... |
462 |
vic_init2(base); |
fa0fe48fc [ARM] Separate VI... |
463 |
|
e641b987c irqchip: support ... |
464 |
vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node); |
f9b28ccbc ARM: vic: device ... |
465 466 467 468 469 470 471 472 473 474 475 476 |
} /** * vic_init() - initialise a vectored interrupt controller * @base: iomem base address * @irq_start: starting interrupt number, must be muliple of 32 * @vic_sources: bitmask of interrupt sources to allow * @resume_sources: bitmask of interrupt sources to allow for resume */ void __init vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources) { |
e641b987c irqchip: support ... |
477 478 479 480 481 482 483 |
__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL); } /** * vic_init_cascaded() - initialise a cascaded vectored interrupt controller * @base: iomem base address * @parent_irq: the parent IRQ we're cascaded off |
e641b987c irqchip: support ... |
484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
* @vic_sources: bitmask of interrupt sources to allow * @resume_sources: bitmask of interrupt sources to allow for resume * * This returns the base for the new interrupts or negative on error. */ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq, u32 vic_sources, u32 resume_sources) { struct vic_device *v; v = &vic_devices[vic_id]; __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL); /* Return out acquired base */ return v->irq; |
f9b28ccbc ARM: vic: device ... |
498 |
} |
a3f4fdf21 irqchip: VIC: exp... |
499 |
EXPORT_SYMBOL_GPL(vic_init_cascaded); |
f9b28ccbc ARM: vic: device ... |
500 501 |
#ifdef CONFIG_OF |
df042a5f4 irqchip/vic: Make... |
502 503 |
static int __init vic_of_init(struct device_node *node, struct device_node *parent) |
f9b28ccbc ARM: vic: device ... |
504 505 |
{ void __iomem *regs; |
81e9c1794 irqchip: vic: Par... |
506 507 |
u32 interrupt_mask = ~0; u32 wakeup_mask = ~0; |
f9b28ccbc ARM: vic: device ... |
508 509 510 511 512 513 514 |
if (WARN(parent, "non-root VICs are not supported")) return -EINVAL; regs = of_iomap(node, 0); if (WARN_ON(!regs)) return -EIO; |
81e9c1794 irqchip: vic: Par... |
515 516 |
of_property_read_u32(node, "valid-mask", &interrupt_mask); of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask); |
07c9249f1 ARM: 7554/1: VIC:... |
517 |
/* |
5ced33bc0 ARM: 7611/1: VIC:... |
518 |
* Passing 0 as first IRQ makes the simple domain allocate descriptors |
07c9249f1 ARM: 7554/1: VIC:... |
519 |
*/ |
e641b987c irqchip: support ... |
520 |
__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node); |
f9b28ccbc ARM: vic: device ... |
521 522 |
return 0; |
fa0fe48fc [ARM] Separate VI... |
523 |
} |
44430ec06 irqchip: Move ARM... |
524 525 526 |
IRQCHIP_DECLARE(arm_pl190_vic, "arm,pl190-vic", vic_of_init); IRQCHIP_DECLARE(arm_pl192_vic, "arm,pl192-vic", vic_of_init); IRQCHIP_DECLARE(arm_versatile_vic, "arm,versatile-vic", vic_of_init); |
f9b28ccbc ARM: vic: device ... |
527 |
#endif /* CONFIG OF */ |