Merge branch 'agp-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / arch / arm / common / vic.c
1 /*
2  *  linux/arch/arm/common/vic.c
3  *
4  *  Copyright (C) 1999 - 2003 ARM Limited
5  *  Copyright (C) 2000 Deep Blue Solutions Ltd
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
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
20  */
21 #include <linux/init.h>
22 #include <linux/list.h>
23 #include <linux/io.h>
24 #include <linux/sysdev.h>
25 #include <linux/amba/bus.h>
26
27 #include <asm/mach/irq.h>
28 #include <asm/hardware/vic.h>
29
30 static void vic_ack_irq(unsigned int irq)
31 {
32         void __iomem *base = get_irq_chip_data(irq);
33         irq &= 31;
34         writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
35         /* moreover, clear the soft-triggered, in case it was the reason */
36         writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
37 }
38
39 static void vic_mask_irq(unsigned int irq)
40 {
41         void __iomem *base = get_irq_chip_data(irq);
42         irq &= 31;
43         writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
44 }
45
46 static void vic_unmask_irq(unsigned int irq)
47 {
48         void __iomem *base = get_irq_chip_data(irq);
49         irq &= 31;
50         writel(1 << irq, base + VIC_INT_ENABLE);
51 }
52
53 /**
54  * vic_init2 - common initialisation code
55  * @base: Base of the VIC.
56  *
57  * Common initialisation code for registeration
58  * and resume.
59 */
60 static void vic_init2(void __iomem *base)
61 {
62         int i;
63
64         for (i = 0; i < 16; i++) {
65                 void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
66                 writel(VIC_VECT_CNTL_ENABLE | i, reg);
67         }
68
69         writel(32, base + VIC_PL190_DEF_VECT_ADDR);
70 }
71
72 #if defined(CONFIG_PM)
73 /**
74  * struct vic_device - VIC PM device
75  * @sysdev: The system device which is registered.
76  * @irq: The IRQ number for the base of the VIC.
77  * @base: The register base for the VIC.
78  * @resume_sources: A bitmask of interrupts for resume.
79  * @resume_irqs: The IRQs enabled for resume.
80  * @int_select: Save for VIC_INT_SELECT.
81  * @int_enable: Save for VIC_INT_ENABLE.
82  * @soft_int: Save for VIC_INT_SOFT.
83  * @protect: Save for VIC_PROTECT.
84  */
85 struct vic_device {
86         struct sys_device sysdev;
87
88         void __iomem    *base;
89         int             irq;
90         u32             resume_sources;
91         u32             resume_irqs;
92         u32             int_select;
93         u32             int_enable;
94         u32             soft_int;
95         u32             protect;
96 };
97
98 /* we cannot allocate memory when VICs are initially registered */
99 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
100
101 static inline struct vic_device *to_vic(struct sys_device *sys)
102 {
103         return container_of(sys, struct vic_device, sysdev);
104 }
105
106 static int vic_id;
107
108 static int vic_class_resume(struct sys_device *dev)
109 {
110         struct vic_device *vic = to_vic(dev);
111         void __iomem *base = vic->base;
112
113         printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
114
115         /* re-initialise static settings */
116         vic_init2(base);
117
118         writel(vic->int_select, base + VIC_INT_SELECT);
119         writel(vic->protect, base + VIC_PROTECT);
120
121         /* set the enabled ints and then clear the non-enabled */
122         writel(vic->int_enable, base + VIC_INT_ENABLE);
123         writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR);
124
125         /* and the same for the soft-int register */
126
127         writel(vic->soft_int, base + VIC_INT_SOFT);
128         writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
129
130         return 0;
131 }
132
133 static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
134 {
135         struct vic_device *vic = to_vic(dev);
136         void __iomem *base = vic->base;
137
138         printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
139
140         vic->int_select = readl(base + VIC_INT_SELECT);
141         vic->int_enable = readl(base + VIC_INT_ENABLE);
142         vic->soft_int = readl(base + VIC_INT_SOFT);
143         vic->protect = readl(base + VIC_PROTECT);
144
145         /* set the interrupts (if any) that are used for
146          * resuming the system */
147
148         writel(vic->resume_irqs, base + VIC_INT_ENABLE);
149         writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
150
151         return 0;
152 }
153
154 struct sysdev_class vic_class = {
155         .name           = "vic",
156         .suspend        = vic_class_suspend,
157         .resume         = vic_class_resume,
158 };
159
160 /**
161  * vic_pm_register - Register a VIC for later power management control
162  * @base: The base address of the VIC.
163  * @irq: The base IRQ for the VIC.
164  * @resume_sources: bitmask of interrupts allowed for resume sources.
165  *
166  * Register the VIC with the system device tree so that it can be notified
167  * of suspend and resume requests and ensure that the correct actions are
168  * taken to re-instate the settings on resume.
169  */
170 static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
171 {
172         struct vic_device *v;
173
174         if (vic_id >= ARRAY_SIZE(vic_devices))
175                 printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
176         else {
177                 v = &vic_devices[vic_id];
178                 v->base = base;
179                 v->resume_sources = resume_sources;
180                 v->irq = irq;
181                 vic_id++;
182         }
183 }
184
185 /**
186  * vic_pm_init - initicall to register VIC pm
187  *
188  * This is called via late_initcall() to register
189  * the resources for the VICs due to the early
190  * nature of the VIC's registration.
191 */
192 static int __init vic_pm_init(void)
193 {
194         struct vic_device *dev = vic_devices;
195         int err;
196         int id;
197
198         if (vic_id == 0)
199                 return 0;
200
201         err = sysdev_class_register(&vic_class);
202         if (err) {
203                 printk(KERN_ERR "%s: cannot register class\n", __func__);
204                 return err;
205         }
206
207         for (id = 0; id < vic_id; id++, dev++) {
208                 dev->sysdev.id = id;
209                 dev->sysdev.cls = &vic_class;
210
211                 err = sysdev_register(&dev->sysdev);
212                 if (err) {
213                         printk(KERN_ERR "%s: failed to register device\n",
214                                __func__);
215                         return err;
216                 }
217         }
218
219         return 0;
220 }
221
222 late_initcall(vic_pm_init);
223
224 static struct vic_device *vic_from_irq(unsigned int irq)
225 {
226         struct vic_device *v = vic_devices;
227         unsigned int base_irq = irq & ~31;
228         int id;
229
230         for (id = 0; id < vic_id; id++, v++) {
231                 if (v->irq == base_irq)
232                         return v;
233         }
234
235         return NULL;
236 }
237
238 static int vic_set_wake(unsigned int irq, unsigned int on)
239 {
240         struct vic_device *v = vic_from_irq(irq);
241         unsigned int off = irq & 31;
242         u32 bit = 1 << off;
243
244         if (!v)
245                 return -EINVAL;
246
247         if (!(bit & v->resume_sources))
248                 return -EINVAL;
249
250         if (on)
251                 v->resume_irqs |= bit;
252         else
253                 v->resume_irqs &= ~bit;
254
255         return 0;
256 }
257
258 #else
259 static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
260
261 #define vic_set_wake NULL
262 #endif /* CONFIG_PM */
263
264 static struct irq_chip vic_chip = {
265         .name   = "VIC",
266         .ack    = vic_ack_irq,
267         .mask   = vic_mask_irq,
268         .unmask = vic_unmask_irq,
269         .set_wake = vic_set_wake,
270 };
271
272 /* The PL190 cell from ARM has been modified by ST, so handle both here */
273 static void vik_init_st(void __iomem *base, unsigned int irq_start,
274                          u32 vic_sources);
275
276 /**
277  * vic_init - initialise a vectored interrupt controller
278  * @base: iomem base address
279  * @irq_start: starting interrupt number, must be muliple of 32
280  * @vic_sources: bitmask of interrupt sources to allow
281  * @resume_sources: bitmask of interrupt sources to allow for resume
282  */
283 void __init vic_init(void __iomem *base, unsigned int irq_start,
284                      u32 vic_sources, u32 resume_sources)
285 {
286         unsigned int i;
287         u32 cellid = 0;
288         enum amba_vendor vendor;
289
290         /* Identify which VIC cell this one is, by reading the ID */
291         for (i = 0; i < 4; i++) {
292                 u32 addr = ((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
293                 cellid |= (readl(addr) & 0xff) << (8 * i);
294         }
295         vendor = (cellid >> 12) & 0xff;
296         printk(KERN_INFO "VIC @%p: id 0x%08x, vendor 0x%02x\n",
297                base, cellid, vendor);
298
299         switch(vendor) {
300         case AMBA_VENDOR_ST:
301                 vik_init_st(base, irq_start, vic_sources);
302                 return;
303         default:
304                 printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
305                 /* fall through */
306         case AMBA_VENDOR_ARM:
307                 break;
308         }
309
310         /* Disable all interrupts initially. */
311
312         writel(0, base + VIC_INT_SELECT);
313         writel(0, base + VIC_INT_ENABLE);
314         writel(~0, base + VIC_INT_ENABLE_CLEAR);
315         writel(0, base + VIC_IRQ_STATUS);
316         writel(0, base + VIC_ITCR);
317         writel(~0, base + VIC_INT_SOFT_CLEAR);
318
319         /*
320          * Make sure we clear all existing interrupts
321          */
322         writel(0, base + VIC_PL190_VECT_ADDR);
323         for (i = 0; i < 19; i++) {
324                 unsigned int value;
325
326                 value = readl(base + VIC_PL190_VECT_ADDR);
327                 writel(value, base + VIC_PL190_VECT_ADDR);
328         }
329
330         vic_init2(base);
331
332         for (i = 0; i < 32; i++) {
333                 if (vic_sources & (1 << i)) {
334                         unsigned int irq = irq_start + i;
335
336                         set_irq_chip(irq, &vic_chip);
337                         set_irq_chip_data(irq, base);
338                         set_irq_handler(irq, handle_level_irq);
339                         set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
340                 }
341         }
342
343         vic_pm_register(base, irq_start, resume_sources);
344 }
345
346 /*
347  * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
348  * The original cell has 32 interrupts, while the modified one has 64,
349  * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
350  * the probe function is called twice, with base set to offset 000
351  *  and 020 within the page. We call this "second block".
352  */
353 static void __init vik_init_st(void __iomem *base, unsigned int irq_start,
354                                 u32 vic_sources)
355 {
356         unsigned int i;
357         int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
358
359         /* Disable all interrupts initially. */
360
361         writel(0, base + VIC_INT_SELECT);
362         writel(0, base + VIC_INT_ENABLE);
363         writel(~0, base + VIC_INT_ENABLE_CLEAR);
364         writel(0, base + VIC_IRQ_STATUS);
365         writel(0, base + VIC_ITCR);
366         writel(~0, base + VIC_INT_SOFT_CLEAR);
367
368         /*
369          * Make sure we clear all existing interrupts. The vector registers
370          * in this cell are after the second block of general registers,
371          * so we can address them using standard offsets, but only from
372          * the second base address, which is 0x20 in the page
373          */
374         if (vic_2nd_block) {
375                 writel(0, base + VIC_PL190_VECT_ADDR);
376                 for (i = 0; i < 19; i++) {
377                         unsigned int value;
378
379                         value = readl(base + VIC_PL190_VECT_ADDR);
380                         writel(value, base + VIC_PL190_VECT_ADDR);
381                 }
382                 /* ST has 16 vectors as well, but we don't enable them by now */
383                 for (i = 0; i < 16; i++) {
384                         void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
385                         writel(0, reg);
386                 }
387
388                 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
389         }
390
391         for (i = 0; i < 32; i++) {
392                 if (vic_sources & (1 << i)) {
393                         unsigned int irq = irq_start + i;
394
395                         set_irq_chip(irq, &vic_chip);
396                         set_irq_chip_data(irq, base);
397                         set_irq_handler(irq, handle_level_irq);
398                         set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
399                 }
400         }
401 }