aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common/vic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/common/vic.c')
-rw-r--r--arch/arm/common/vic.c265
1 files changed, 132 insertions, 133 deletions
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index f232941de8ab..1cf999ade4bc 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -18,6 +18,7 @@
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21
21#include <linux/init.h> 22#include <linux/init.h>
22#include <linux/list.h> 23#include <linux/list.h>
23#include <linux/io.h> 24#include <linux/io.h>
@@ -28,48 +29,6 @@
28#include <asm/mach/irq.h> 29#include <asm/mach/irq.h>
29#include <asm/hardware/vic.h> 30#include <asm/hardware/vic.h>
30 31
31static void vic_ack_irq(unsigned int irq)
32{
33 void __iomem *base = get_irq_chip_data(irq);
34 irq &= 31;
35 writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
36 /* moreover, clear the soft-triggered, in case it was the reason */
37 writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
38}
39
40static void vic_mask_irq(unsigned int irq)
41{
42 void __iomem *base = get_irq_chip_data(irq);
43 irq &= 31;
44 writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
45}
46
47static void vic_unmask_irq(unsigned int irq)
48{
49 void __iomem *base = get_irq_chip_data(irq);
50 irq &= 31;
51 writel(1 << irq, base + VIC_INT_ENABLE);
52}
53
54/**
55 * vic_init2 - common initialisation code
56 * @base: Base of the VIC.
57 *
58 * Common initialisation code for registeration
59 * and resume.
60*/
61static void vic_init2(void __iomem *base)
62{
63 int i;
64
65 for (i = 0; i < 16; i++) {
66 void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
67 writel(VIC_VECT_CNTL_ENABLE | i, reg);
68 }
69
70 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
71}
72
73#if defined(CONFIG_PM) 32#if defined(CONFIG_PM)
74/** 33/**
75 * struct vic_device - VIC PM device 34 * struct vic_device - VIC PM device
@@ -99,13 +58,34 @@ struct vic_device {
99/* we cannot allocate memory when VICs are initially registered */ 58/* we cannot allocate memory when VICs are initially registered */
100static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; 59static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
101 60
61static int vic_id;
62
102static inline struct vic_device *to_vic(struct sys_device *sys) 63static inline struct vic_device *to_vic(struct sys_device *sys)
103{ 64{
104 return container_of(sys, struct vic_device, sysdev); 65 return container_of(sys, struct vic_device, sysdev);
105} 66}
67#endif /* CONFIG_PM */
106 68
107static int vic_id; 69/**
70 * vic_init2 - common initialisation code
71 * @base: Base of the VIC.
72 *
73 * Common initialisation code for registeration
74 * and resume.
75*/
76static void vic_init2(void __iomem *base)
77{
78 int i;
79
80 for (i = 0; i < 16; i++) {
81 void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
82 writel(VIC_VECT_CNTL_ENABLE | i, reg);
83 }
84
85 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
86}
108 87
88#if defined(CONFIG_PM)
109static int vic_class_resume(struct sys_device *dev) 89static int vic_class_resume(struct sys_device *dev)
110{ 90{
111 struct vic_device *vic = to_vic(dev); 91 struct vic_device *vic = to_vic(dev);
@@ -159,31 +139,6 @@ struct sysdev_class vic_class = {
159}; 139};
160 140
161/** 141/**
162 * vic_pm_register - Register a VIC for later power management control
163 * @base: The base address of the VIC.
164 * @irq: The base IRQ for the VIC.
165 * @resume_sources: bitmask of interrupts allowed for resume sources.
166 *
167 * Register the VIC with the system device tree so that it can be notified
168 * of suspend and resume requests and ensure that the correct actions are
169 * taken to re-instate the settings on resume.
170 */
171static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
172{
173 struct vic_device *v;
174
175 if (vic_id >= ARRAY_SIZE(vic_devices))
176 printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
177 else {
178 v = &vic_devices[vic_id];
179 v->base = base;
180 v->resume_sources = resume_sources;
181 v->irq = irq;
182 vic_id++;
183 }
184}
185
186/**
187 * vic_pm_init - initicall to register VIC pm 142 * vic_pm_init - initicall to register VIC pm
188 * 143 *
189 * This is called via late_initcall() to register 144 * This is called via late_initcall() to register
@@ -219,9 +174,60 @@ static int __init vic_pm_init(void)
219 174
220 return 0; 175 return 0;
221} 176}
222
223late_initcall(vic_pm_init); 177late_initcall(vic_pm_init);
224 178
179/**
180 * vic_pm_register - Register a VIC for later power management control
181 * @base: The base address of the VIC.
182 * @irq: The base IRQ for the VIC.
183 * @resume_sources: bitmask of interrupts allowed for resume sources.
184 *
185 * Register the VIC with the system device tree so that it can be notified
186 * of suspend and resume requests and ensure that the correct actions are
187 * taken to re-instate the settings on resume.
188 */
189static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
190{
191 struct vic_device *v;
192
193 if (vic_id >= ARRAY_SIZE(vic_devices))
194 printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
195 else {
196 v = &vic_devices[vic_id];
197 v->base = base;
198 v->resume_sources = resume_sources;
199 v->irq = irq;
200 vic_id++;
201 }
202}
203#else
204static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
205#endif /* CONFIG_PM */
206
207static void vic_ack_irq(unsigned int irq)
208{
209 void __iomem *base = get_irq_chip_data(irq);
210 irq &= 31;
211 writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
212 /* moreover, clear the soft-triggered, in case it was the reason */
213 writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
214}
215
216static void vic_mask_irq(unsigned int irq)
217{
218 void __iomem *base = get_irq_chip_data(irq);
219 irq &= 31;
220 writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
221}
222
223static void vic_unmask_irq(unsigned int irq)
224{
225 void __iomem *base = get_irq_chip_data(irq);
226 irq &= 31;
227 writel(1 << irq, base + VIC_INT_ENABLE);
228}
229
230#if defined(CONFIG_PM)
225static struct vic_device *vic_from_irq(unsigned int irq) 231static struct vic_device *vic_from_irq(unsigned int irq)
226{ 232{
227 struct vic_device *v = vic_devices; 233 struct vic_device *v = vic_devices;
@@ -255,10 +261,7 @@ static int vic_set_wake(unsigned int irq, unsigned int on)
255 261
256 return 0; 262 return 0;
257} 263}
258
259#else 264#else
260static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
261
262#define vic_set_wake NULL 265#define vic_set_wake NULL
263#endif /* CONFIG_PM */ 266#endif /* CONFIG_PM */
264 267
@@ -270,9 +273,62 @@ static struct irq_chip vic_chip = {
270 .set_wake = vic_set_wake, 273 .set_wake = vic_set_wake,
271}; 274};
272 275
273/* The PL190 cell from ARM has been modified by ST, so handle both here */ 276/*
274static void vik_init_st(void __iomem *base, unsigned int irq_start, 277 * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
275 u32 vic_sources); 278 * The original cell has 32 interrupts, while the modified one has 64,
279 * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
280 * the probe function is called twice, with base set to offset 000
281 * and 020 within the page. We call this "second block".
282 */
283static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
284 u32 vic_sources)
285{
286 unsigned int i;
287 int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
288
289 /* Disable all interrupts initially. */
290
291 writel(0, base + VIC_INT_SELECT);
292 writel(0, base + VIC_INT_ENABLE);
293 writel(~0, base + VIC_INT_ENABLE_CLEAR);
294 writel(0, base + VIC_IRQ_STATUS);
295 writel(0, base + VIC_ITCR);
296 writel(~0, base + VIC_INT_SOFT_CLEAR);
297
298 /*
299 * Make sure we clear all existing interrupts. The vector registers
300 * in this cell are after the second block of general registers,
301 * so we can address them using standard offsets, but only from
302 * the second base address, which is 0x20 in the page
303 */
304 if (vic_2nd_block) {
305 writel(0, base + VIC_PL190_VECT_ADDR);
306 for (i = 0; i < 19; i++) {
307 unsigned int value;
308
309 value = readl(base + VIC_PL190_VECT_ADDR);
310 writel(value, base + VIC_PL190_VECT_ADDR);
311 }
312 /* ST has 16 vectors as well, but we don't enable them by now */
313 for (i = 0; i < 16; i++) {
314 void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
315 writel(0, reg);
316 }
317
318 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
319 }
320
321 for (i = 0; i < 32; i++) {
322 if (vic_sources & (1 << i)) {
323 unsigned int irq = irq_start + i;
324
325 set_irq_chip(irq, &vic_chip);
326 set_irq_chip_data(irq, base);
327 set_irq_handler(irq, handle_level_irq);
328 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
329 }
330 }
331}
276 332
277/** 333/**
278 * vic_init - initialise a vectored interrupt controller 334 * vic_init - initialise a vectored interrupt controller
@@ -299,7 +355,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
299 355
300 switch(vendor) { 356 switch(vendor) {
301 case AMBA_VENDOR_ST: 357 case AMBA_VENDOR_ST:
302 vik_init_st(base, irq_start, vic_sources); 358 vic_init_st(base, irq_start, vic_sources);
303 return; 359 return;
304 default: 360 default:
305 printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n"); 361 printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -343,60 +399,3 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
343 399
344 vic_pm_register(base, irq_start, resume_sources); 400 vic_pm_register(base, irq_start, resume_sources);
345} 401}
346
347/*
348 * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
349 * The original cell has 32 interrupts, while the modified one has 64,
350 * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
351 * the probe function is called twice, with base set to offset 000
352 * and 020 within the page. We call this "second block".
353 */
354static void __init vik_init_st(void __iomem *base, unsigned int irq_start,
355 u32 vic_sources)
356{
357 unsigned int i;
358 int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
359
360 /* Disable all interrupts initially. */
361
362 writel(0, base + VIC_INT_SELECT);
363 writel(0, base + VIC_INT_ENABLE);
364 writel(~0, base + VIC_INT_ENABLE_CLEAR);
365 writel(0, base + VIC_IRQ_STATUS);
366 writel(0, base + VIC_ITCR);
367 writel(~0, base + VIC_INT_SOFT_CLEAR);
368
369 /*
370 * Make sure we clear all existing interrupts. The vector registers
371 * in this cell are after the second block of general registers,
372 * so we can address them using standard offsets, but only from
373 * the second base address, which is 0x20 in the page
374 */
375 if (vic_2nd_block) {
376 writel(0, base + VIC_PL190_VECT_ADDR);
377 for (i = 0; i < 19; i++) {
378 unsigned int value;
379
380 value = readl(base + VIC_PL190_VECT_ADDR);
381 writel(value, base + VIC_PL190_VECT_ADDR);
382 }
383 /* ST has 16 vectors as well, but we don't enable them by now */
384 for (i = 0; i < 16; i++) {
385 void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
386 writel(0, reg);
387 }
388
389 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
390 }
391
392 for (i = 0; i < 32; i++) {
393 if (vic_sources & (1 << i)) {
394 unsigned int irq = irq_start + i;
395
396 set_irq_chip(irq, &vic_chip);
397 set_irq_chip_data(irq, base);
398 set_irq_handler(irq, handle_level_irq);
399 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
400 }
401 }
402}