ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / syslib / ppc8260_pic.c
1 #include <linux/stddef.h>
2 #include <linux/init.h>
3 #include <linux/sched.h>
4 #include <linux/signal.h>
5 #include <asm/irq.h>
6 #include <asm/immap_8260.h>
7 #include <asm/mpc8260.h>
8 #include "ppc8260_pic.h"
9
10 /* The 8260 internal interrupt controller.  It is usually
11  * the only interrupt controller.
12  * There are two 32-bit registers (high/low) for up to 64
13  * possible interrupts.
14  *
15  * Now, the fun starts.....Interrupt Numbers DO NOT MAP
16  * in a simple arithmetic fashion to mask or pending registers.
17  * That is, interrupt 4 does not map to bit position 4.
18  * We create two tables, indexed by vector number, to indicate
19  * which register to use and which bit in the register to use.
20  */
21 static  u_char  irq_to_siureg[] = {
22         1, 1, 1, 1, 1, 1, 1, 1,
23         1, 1, 1, 1, 1, 1, 1, 1,
24         0, 0, 0, 0, 0, 0, 0, 0,
25         0, 0, 0, 0, 0, 0, 0, 0,
26         1, 1, 1, 1, 1, 1, 1, 1,
27         1, 1, 1, 1, 1, 1, 1, 1,
28         0, 0, 0, 0, 0, 0, 0, 0,
29         0, 0, 0, 0, 0, 0, 0, 0
30 };
31
32 static  u_char  irq_to_siubit[] = {
33         31, 16, 17, 18, 19, 20, 21, 22,
34         23, 24, 25, 26, 27, 28, 29, 30,
35         29, 30, 16, 17, 18, 19, 20, 21,
36         22, 23, 24, 25, 26, 27, 28, 31,
37          0,  1,  2,  3,  4,  5,  6,  7,
38          8,  9, 10, 11, 12, 13, 14, 15,
39         15, 14, 13, 12, 11, 10,  9,  8,
40          7,  6,  5,  4,  3,  2,  1,  0
41 };
42
43 static void m8260_mask_irq(unsigned int irq_nr)
44 {
45         int     bit, word;
46         volatile uint   *simr;
47
48         bit = irq_to_siubit[irq_nr];
49         word = irq_to_siureg[irq_nr];
50
51         simr = &(immr->im_intctl.ic_simrh);
52         ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
53         simr[word] = ppc_cached_irq_mask[word];
54 }
55
56 static void m8260_unmask_irq(unsigned int irq_nr)
57 {
58         int     bit, word;
59         volatile uint   *simr;
60
61         bit = irq_to_siubit[irq_nr];
62         word = irq_to_siureg[irq_nr];
63
64         simr = &(immr->im_intctl.ic_simrh);
65         ppc_cached_irq_mask[word] |= (1 << (31 - bit));
66         simr[word] = ppc_cached_irq_mask[word];
67 }
68
69 static void m8260_mask_and_ack(unsigned int irq_nr)
70 {
71         int     bit, word;
72         volatile uint   *simr, *sipnr;
73
74         bit = irq_to_siubit[irq_nr];
75         word = irq_to_siureg[irq_nr];
76
77         simr = &(immr->im_intctl.ic_simrh);
78         sipnr = &(immr->im_intctl.ic_sipnrh);
79         ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
80         simr[word] = ppc_cached_irq_mask[word];
81         sipnr[word] = 1 << (31 - bit);
82 }
83
84 static void m8260_end_irq(unsigned int irq_nr)
85 {
86         int     bit, word;
87         volatile uint   *simr;
88
89         if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
90                         && irq_desc[irq_nr].action) {
91
92                 bit = irq_to_siubit[irq_nr];
93                 word = irq_to_siureg[irq_nr];
94
95                 simr = &(immr->im_intctl.ic_simrh);
96                 ppc_cached_irq_mask[word] |= (1 << (31 - bit));
97                 simr[word] = ppc_cached_irq_mask[word];
98         }
99 }
100
101 struct hw_interrupt_type ppc8260_pic = {
102         " 8260 SIU  ",
103         NULL,
104         NULL,
105         m8260_unmask_irq,
106         m8260_mask_irq,
107         m8260_mask_and_ack,
108         m8260_end_irq,
109         0
110 };
111
112
113 int
114 m8260_get_irq(struct pt_regs *regs)
115 {
116         int irq;
117         unsigned long bits;
118
119         /* For MPC8260, read the SIVEC register and shift the bits down
120          * to get the irq number.         */
121         bits = immr->im_intctl.ic_sivec;
122         irq = bits >> 26;
123
124         if (irq == 0)
125                 return(-1);
126 #if 0
127         irq += ppc8260_pic.irq_offset;
128 #endif
129         return irq;
130 }
131