sparc32: Add more extensive documentation of sun4m interrupts.
[linux-2.6] / arch / sparc / kernel / sun4m_irq.c
1 /*  sun4m_irq.c
2  *  arch/sparc/kernel/sun4m_irq.c:
3  *
4  *  djhr: Hacked out of irq.c into a CPU dependent version.
5  *
6  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
7  *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
8  *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com)
9  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
10  */
11
12 #include <linux/errno.h>
13 #include <linux/linkage.h>
14 #include <linux/kernel_stat.h>
15 #include <linux/signal.h>
16 #include <linux/sched.h>
17 #include <linux/ptrace.h>
18 #include <linux/smp.h>
19 #include <linux/interrupt.h>
20 #include <linux/slab.h>
21 #include <linux/init.h>
22 #include <linux/ioport.h>
23 #include <linux/of.h>
24 #include <linux/of_device.h>
25
26 #include <asm/ptrace.h>
27 #include <asm/processor.h>
28 #include <asm/system.h>
29 #include <asm/psr.h>
30 #include <asm/vaddrs.h>
31 #include <asm/timer.h>
32 #include <asm/openprom.h>
33 #include <asm/oplib.h>
34 #include <asm/traps.h>
35 #include <asm/pgalloc.h>
36 #include <asm/pgtable.h>
37 #include <asm/smp.h>
38 #include <asm/irq.h>
39 #include <asm/io.h>
40 #include <asm/cacheflush.h>
41
42 #include "irq.h"
43
44 struct sun4m_irq_percpu {
45         u32             pending;
46         u32             clear;
47         u32             set;
48 };
49
50 struct sun4m_irq_global {
51         u32             pending;
52         u32             mask;
53         u32             mask_clear;
54         u32             mask_set;
55         u32             interrupt_target;
56 };
57
58 /* Code in entry.S needs to get at these register mappings.  */
59 struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
60 struct sun4m_irq_global __iomem *sun4m_irq_global;
61
62 /* Dave Redman (djhr@tadpole.co.uk)
63  * The sun4m interrupt registers.
64  */
65 #define SUN4M_INT_ENABLE        0x80000000
66 #define SUN4M_INT_E14           0x00000080
67 #define SUN4M_INT_E10           0x00080000
68
69 #define SUN4M_HARD_INT(x)       (0x000000001 << (x))
70 #define SUN4M_SOFT_INT(x)       (0x000010000 << (x))
71
72 #define SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
73 #define SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
74 #define SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
75 #define SUN4M_INT_ECC           0x10000000        /* ecc memory error */
76 #define SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
77 #define SUN4M_INT_MODULE        0x00200000        /* module interrupt */
78 #define SUN4M_INT_VIDEO         0x00100000        /* onboard video */
79 #define SUN4M_INT_REALTIME      0x00080000        /* system timer */
80 #define SUN4M_INT_SCSI          0x00040000        /* onboard scsi */
81 #define SUN4M_INT_AUDIO         0x00020000        /* audio/isdn */
82 #define SUN4M_INT_ETHERNET      0x00010000        /* onboard ethernet */
83 #define SUN4M_INT_SERIAL        0x00008000        /* serial ports */
84 #define SUN4M_INT_KBDMS         0x00004000        /* keyboard/mouse */
85 #define SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
86
87 #define SUN4M_INT_SBUS(x)       (1 << (x+7))
88 #define SUN4M_INT_VME(x)        (1 << (x))
89
90 /* Interrupt level assignment on sun4m:
91  *
92  *      level           source
93  * ------------------------------------------------------------
94  *        1             softint-1
95  *        2             softint-2, VME/SBUS level 1
96  *        3             softint-3, VME/SBUS level 2
97  *        4             softint-4, onboard SCSI
98  *        5             softint-5, VME/SBUS level 3
99  *        6             softint-6, onboard ETHERNET
100  *        7             softint-7, VME/SBUS level 4
101  *        8             softint-8, onboard VIDEO
102  *        9             softint-9, VME/SBUS level 5, Module Interrupt
103  *       10             softint-10, system counter/timer
104  *       11             softint-11, VME/SBUS level 6, Floppy
105  *       12             softint-12, Keyboard/Mouse, Serial
106  *       13             softint-13, VME/SBUS level 7, ISDN Audio
107  *       14             softint-14, per-processor counter/timer
108  *       15             softint-15, Asynchronous Errors (broadcast)
109  *
110  * Each interrupt source is masked distinctly in the sun4m interrupt
111  * registers.  The PIL level alone is therefore ambiguous, since multiple
112  * interrupt sources map to a single PIL.
113  *
114  * This ambiguity is resolved in the 'intr' property for device nodes
115  * in the OF device tree.  Each 'intr' property entry is composed of
116  * two 32-bit words.  The first word is the IRQ priority value, which
117  * is what we're intersted in.  The second word is the IRQ vector, which
118  * is unused.
119  *
120  * The low 4 bits of the IRQ priority indicate the PIL, and the upper
121  * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled.  0x20
122  * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
123  *
124  * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
125  * whereas a value of 0x33 is SBUS level 2.  Here are some sample
126  * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
127  * Tadpole S3 GX systems.
128  *
129  * esp:         0x24    onboard ESP SCSI
130  * le:          0x26    onboard Lance ETHERNET
131  * p9100:       0x32    SBUS level 1 P9100 video
132  * bpp:         0x33    SBUS level 2 BPP parallel port device
133  * DBRI:        0x39    SBUS level 5 DBRI ISDN audio
134  * SUNW,leo:    0x39    SBUS level 5 LEO video
135  * pcmcia:      0x3b    SBUS level 6 PCMCIA controller
136  * uctrl:       0x3b    SBUS level 6 UCTRL device
137  * modem:       0x3d    SBUS level 7 MODEM
138  * zs:          0x2c    onboard keyboard/mouse/serial
139  * floppy:      0x2b    onboard Floppy
140  * power:       0x22    onboard power device (XXX unknown mask bit XXX)
141  */
142
143 /* These tables only apply for interrupts greater than 15..
144  * 
145  * any intr value below 0x10 is considered to be a soft-int
146  * this may be useful or it may not.. but that's how I've done it.
147  * and it won't clash with what OBP is telling us about devices.
148  *
149  * take an encoded intr value and lookup if it's valid
150  * then get the mask bits that match from irq_mask
151  *
152  * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
153  */
154 static unsigned char irq_xlate[32] = {
155     /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
156         0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
157         0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
158 };
159
160 static unsigned long irq_mask[] = {
161         0,                                                /* illegal index */
162         SUN4M_INT_SCSI,                                   /*  1 irq 4 */
163         SUN4M_INT_ETHERNET,                               /*  2 irq 6 */
164         SUN4M_INT_VIDEO,                                  /*  3 irq 8 */
165         SUN4M_INT_REALTIME,                               /*  4 irq 10 */
166         SUN4M_INT_FLOPPY,                                 /*  5 irq 11 */
167         (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),             /*  6 irq 12 */
168         SUN4M_INT_MODULE_ERR,                             /*  7 irq 15 */
169         SUN4M_INT_SBUS(0),                                /*  8 irq 2 */
170         SUN4M_INT_SBUS(1),                                /*  9 irq 3 */
171         SUN4M_INT_SBUS(2),                                /* 10 irq 5 */
172         SUN4M_INT_SBUS(3),                                /* 11 irq 7 */
173         SUN4M_INT_SBUS(4),                                /* 12 irq 9 */
174         SUN4M_INT_SBUS(5),                                /* 13 irq 11 */
175         SUN4M_INT_SBUS(6)                                 /* 14 irq 13 */
176 };
177
178 static unsigned long sun4m_get_irqmask(unsigned int irq)
179 {
180         unsigned long mask;
181     
182         if (irq > 0x20) {
183                 /* OBIO/SBUS interrupts */
184                 irq &= 0x1f;
185                 mask = irq_mask[irq_xlate[irq]];
186                 if (!mask)
187                         printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
188         } else {
189                 /* Soft Interrupts will come here.
190                  * Currently there is no way to trigger them but I'm sure
191                  * something could be cooked up.
192                  */
193                 irq &= 0xf;
194                 mask = SUN4M_SOFT_INT(irq);
195         }
196         return mask;
197 }
198
199 static void sun4m_disable_irq(unsigned int irq_nr)
200 {
201         unsigned long mask, flags;
202         int cpu = smp_processor_id();
203
204         mask = sun4m_get_irqmask(irq_nr);
205         local_irq_save(flags);
206         if (irq_nr > 15)
207                 sbus_writel(mask, &sun4m_irq_global->mask_set);
208         else
209                 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
210         local_irq_restore(flags);    
211 }
212
213 static void sun4m_enable_irq(unsigned int irq_nr)
214 {
215         unsigned long mask, flags;
216         int cpu = smp_processor_id();
217
218         /* Dreadful floppy hack. When we use 0x2b instead of
219          * 0x0b the system blows (it starts to whistle!).
220          * So we continue to use 0x0b. Fixme ASAP. --P3
221          */
222         if (irq_nr != 0x0b) {
223                 mask = sun4m_get_irqmask(irq_nr);
224                 local_irq_save(flags);
225                 if (irq_nr > 15)
226                         sbus_writel(mask, &sun4m_irq_global->mask_clear);
227                 else
228                         sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
229                 local_irq_restore(flags);    
230         } else {
231                 local_irq_save(flags);
232                 sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
233                 local_irq_restore(flags);
234         }
235 }
236
237 static unsigned long cpu_pil_to_imask[16] = {
238 /*0*/   0x00000000,
239 /*1*/   0x00000000,
240 /*2*/   SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0),
241 /*3*/   SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1),
242 /*4*/   SUN4M_INT_SCSI,
243 /*5*/   SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2),
244 /*6*/   SUN4M_INT_ETHERNET,
245 /*7*/   SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3),
246 /*8*/   SUN4M_INT_VIDEO,
247 /*9*/   SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
248 /*10*/  SUN4M_INT_REALTIME,
249 /*11*/  SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
250 /*12*/  SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
251 /*13*/  SUN4M_INT_AUDIO,
252 /*14*/  SUN4M_INT_E14,
253 /*15*/  0x00000000
254 };
255
256 /* We assume the caller has disabled local interrupts when these are called,
257  * or else very bizarre behavior will result.
258  */
259 static void sun4m_disable_pil_irq(unsigned int pil)
260 {
261         sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
262 }
263
264 static void sun4m_enable_pil_irq(unsigned int pil)
265 {
266         sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
267 }
268
269 #ifdef CONFIG_SMP
270 static void sun4m_send_ipi(int cpu, int level)
271 {
272         unsigned long mask = sun4m_get_irqmask(level);
273         sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
274 }
275
276 static void sun4m_clear_ipi(int cpu, int level)
277 {
278         unsigned long mask = sun4m_get_irqmask(level);
279         sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
280 }
281
282 static void sun4m_set_udt(int cpu)
283 {
284         sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
285 }
286 #endif
287
288 struct sun4m_timer_percpu {
289         u32             l14_limit;
290         u32             l14_count;
291         u32             l14_limit_noclear;
292         u32             user_timer_start_stop;
293 };
294
295 static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
296
297 struct sun4m_timer_global {
298         u32             l10_limit;
299         u32             l10_count;
300         u32             l10_limit_noclear;
301         u32             reserved;
302         u32             timer_config;
303 };
304
305 static struct sun4m_timer_global __iomem *timers_global;
306
307 #define OBIO_INTR       0x20
308 #define TIMER_IRQ       (OBIO_INTR | 10)
309
310 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
311
312 static void sun4m_clear_clock_irq(void)
313 {
314         sbus_readl(&timers_global->l10_limit);
315 }
316
317 /* Exported for sun4m_smp.c */
318 void sun4m_clear_profile_irq(int cpu)
319 {
320         sbus_readl(&timers_percpu[cpu]->l14_limit);
321 }
322
323 static void sun4m_load_profile_irq(int cpu, unsigned int limit)
324 {
325         sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
326 }
327
328 static void __init sun4m_init_timers(irq_handler_t counter_fn)
329 {
330         struct device_node *dp = of_find_node_by_name(NULL, "counter");
331         int i, err, len, num_cpu_timers;
332         const u32 *addr;
333
334         if (!dp) {
335                 printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
336                 return;
337         }
338
339         addr = of_get_property(dp, "address", &len);
340         if (!addr) {
341                 printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
342                 return;
343         }
344
345         num_cpu_timers = (len / sizeof(u32)) - 1;
346         for (i = 0; i < num_cpu_timers; i++) {
347                 timers_percpu[i] = (void __iomem *)
348                         (unsigned long) addr[i];
349         }
350         timers_global = (void __iomem *)
351                 (unsigned long) addr[num_cpu_timers];
352
353         sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
354
355         master_l10_counter = &timers_global->l10_count;
356
357         err = request_irq(TIMER_IRQ, counter_fn,
358                           (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
359         if (err) {
360                 printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
361                         err);
362                 return;
363         }
364
365         for (i = 0; i < num_cpu_timers; i++)
366                 sbus_writel(0, &timers_percpu[i]->l14_limit);
367         if (num_cpu_timers == 4)
368                 sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
369
370 #ifdef CONFIG_SMP
371         {
372                 unsigned long flags;
373                 extern unsigned long lvl14_save[4];
374                 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
375
376                 /* For SMP we use the level 14 ticker, however the bootup code
377                  * has copied the firmware's level 14 vector into the boot cpu's
378                  * trap table, we must fix this now or we get squashed.
379                  */
380                 local_irq_save(flags);
381                 trap_table->inst_one = lvl14_save[0];
382                 trap_table->inst_two = lvl14_save[1];
383                 trap_table->inst_three = lvl14_save[2];
384                 trap_table->inst_four = lvl14_save[3];
385                 local_flush_cache_all();
386                 local_irq_restore(flags);
387         }
388 #endif
389 }
390
391 void __init sun4m_init_IRQ(void)
392 {
393         struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
394         int len, i, mid, num_cpu_iregs;
395         const u32 *addr;
396
397         if (!dp) {
398                 printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
399                 return;
400         }
401
402         addr = of_get_property(dp, "address", &len);
403         if (!addr) {
404                 printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
405                 return;
406         }
407
408         num_cpu_iregs = (len / sizeof(u32)) - 1;
409         for (i = 0; i < num_cpu_iregs; i++) {
410                 sun4m_irq_percpu[i] = (void __iomem *)
411                         (unsigned long) addr[i];
412         }
413         sun4m_irq_global = (void __iomem *)
414                 (unsigned long) addr[num_cpu_iregs];
415
416         local_irq_disable();
417
418         sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
419         for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
420                 sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
421
422         if (num_cpu_iregs == 4)
423                 sbus_writel(0, &sun4m_irq_global->interrupt_target);
424
425         BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
426         BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
427         BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
428         BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
429         BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
430         BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
431         sparc_init_timers = sun4m_init_timers;
432 #ifdef CONFIG_SMP
433         BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
434         BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
435         BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
436 #endif
437
438         /* Cannot enable interrupts until OBP ticker is disabled. */
439 }