diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/syslib/cpm2_pic.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/syslib/cpm2_pic.c')
-rw-r--r-- | arch/ppc/syslib/cpm2_pic.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c new file mode 100644 index 000000000000..954b07fc1df3 --- /dev/null +++ b/arch/ppc/syslib/cpm2_pic.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* The CPM2 internal interrupt controller. It is usually | ||
2 | * the only interrupt controller. | ||
3 | * There are two 32-bit registers (high/low) for up to 64 | ||
4 | * possible interrupts. | ||
5 | * | ||
6 | * Now, the fun starts.....Interrupt Numbers DO NOT MAP | ||
7 | * in a simple arithmetic fashion to mask or pending registers. | ||
8 | * That is, interrupt 4 does not map to bit position 4. | ||
9 | * We create two tables, indexed by vector number, to indicate | ||
10 | * which register to use and which bit in the register to use. | ||
11 | */ | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/signal.h> | ||
17 | #include <linux/irq.h> | ||
18 | |||
19 | #include <asm/immap_cpm2.h> | ||
20 | #include <asm/mpc8260.h> | ||
21 | |||
22 | #include "cpm2_pic.h" | ||
23 | |||
24 | static u_char irq_to_siureg[] = { | ||
25 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
26 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
27 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
28 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
29 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
30 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
31 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
32 | 0, 0, 0, 0, 0, 0, 0, 0 | ||
33 | }; | ||
34 | |||
35 | /* bit numbers do not match the docs, these are precomputed so the bit for | ||
36 | * a given irq is (1 << irq_to_siubit[irq]) */ | ||
37 | static u_char irq_to_siubit[] = { | ||
38 | 0, 15, 14, 13, 12, 11, 10, 9, | ||
39 | 8, 7, 6, 5, 4, 3, 2, 1, | ||
40 | 2, 1, 15, 14, 13, 12, 11, 10, | ||
41 | 9, 8, 7, 6, 5, 4, 3, 0, | ||
42 | 31, 30, 29, 28, 27, 26, 25, 24, | ||
43 | 23, 22, 21, 20, 19, 18, 17, 16, | ||
44 | 16, 17, 18, 19, 20, 21, 22, 23, | ||
45 | 24, 25, 26, 27, 28, 29, 30, 31, | ||
46 | }; | ||
47 | |||
48 | static void cpm2_mask_irq(unsigned int irq_nr) | ||
49 | { | ||
50 | int bit, word; | ||
51 | volatile uint *simr; | ||
52 | |||
53 | irq_nr -= CPM_IRQ_OFFSET; | ||
54 | |||
55 | bit = irq_to_siubit[irq_nr]; | ||
56 | word = irq_to_siureg[irq_nr]; | ||
57 | |||
58 | simr = &(cpm2_immr->im_intctl.ic_simrh); | ||
59 | ppc_cached_irq_mask[word] &= ~(1 << bit); | ||
60 | simr[word] = ppc_cached_irq_mask[word]; | ||
61 | } | ||
62 | |||
63 | static void cpm2_unmask_irq(unsigned int irq_nr) | ||
64 | { | ||
65 | int bit, word; | ||
66 | volatile uint *simr; | ||
67 | |||
68 | irq_nr -= CPM_IRQ_OFFSET; | ||
69 | |||
70 | bit = irq_to_siubit[irq_nr]; | ||
71 | word = irq_to_siureg[irq_nr]; | ||
72 | |||
73 | simr = &(cpm2_immr->im_intctl.ic_simrh); | ||
74 | ppc_cached_irq_mask[word] |= 1 << bit; | ||
75 | simr[word] = ppc_cached_irq_mask[word]; | ||
76 | } | ||
77 | |||
78 | static void cpm2_mask_and_ack(unsigned int irq_nr) | ||
79 | { | ||
80 | int bit, word; | ||
81 | volatile uint *simr, *sipnr; | ||
82 | |||
83 | irq_nr -= CPM_IRQ_OFFSET; | ||
84 | |||
85 | bit = irq_to_siubit[irq_nr]; | ||
86 | word = irq_to_siureg[irq_nr]; | ||
87 | |||
88 | simr = &(cpm2_immr->im_intctl.ic_simrh); | ||
89 | sipnr = &(cpm2_immr->im_intctl.ic_sipnrh); | ||
90 | ppc_cached_irq_mask[word] &= ~(1 << bit); | ||
91 | simr[word] = ppc_cached_irq_mask[word]; | ||
92 | sipnr[word] = 1 << bit; | ||
93 | } | ||
94 | |||
95 | static void cpm2_end_irq(unsigned int irq_nr) | ||
96 | { | ||
97 | int bit, word; | ||
98 | volatile uint *simr; | ||
99 | |||
100 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | ||
101 | && irq_desc[irq_nr].action) { | ||
102 | |||
103 | irq_nr -= CPM_IRQ_OFFSET; | ||
104 | bit = irq_to_siubit[irq_nr]; | ||
105 | word = irq_to_siureg[irq_nr]; | ||
106 | |||
107 | simr = &(cpm2_immr->im_intctl.ic_simrh); | ||
108 | ppc_cached_irq_mask[word] |= 1 << bit; | ||
109 | simr[word] = ppc_cached_irq_mask[word]; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static struct hw_interrupt_type cpm2_pic = { | ||
114 | .typename = " CPM2 SIU ", | ||
115 | .enable = cpm2_unmask_irq, | ||
116 | .disable = cpm2_mask_irq, | ||
117 | .ack = cpm2_mask_and_ack, | ||
118 | .end = cpm2_end_irq, | ||
119 | }; | ||
120 | |||
121 | int cpm2_get_irq(struct pt_regs *regs) | ||
122 | { | ||
123 | int irq; | ||
124 | unsigned long bits; | ||
125 | |||
126 | /* For CPM2, read the SIVEC register and shift the bits down | ||
127 | * to get the irq number. */ | ||
128 | bits = cpm2_immr->im_intctl.ic_sivec; | ||
129 | irq = bits >> 26; | ||
130 | |||
131 | if (irq == 0) | ||
132 | return(-1); | ||
133 | return irq+CPM_IRQ_OFFSET; | ||
134 | } | ||
135 | |||
136 | void cpm2_init_IRQ(void) | ||
137 | { | ||
138 | int i; | ||
139 | |||
140 | /* Clear the CPM IRQ controller, in case it has any bits set | ||
141 | * from the bootloader | ||
142 | */ | ||
143 | |||
144 | /* Mask out everything */ | ||
145 | cpm2_immr->im_intctl.ic_simrh = 0x00000000; | ||
146 | cpm2_immr->im_intctl.ic_simrl = 0x00000000; | ||
147 | wmb(); | ||
148 | |||
149 | /* Ack everything */ | ||
150 | cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff; | ||
151 | cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff; | ||
152 | wmb(); | ||
153 | |||
154 | /* Dummy read of the vector */ | ||
155 | i = cpm2_immr->im_intctl.ic_sivec; | ||
156 | rmb(); | ||
157 | |||
158 | /* Initialize the default interrupt mapping priorities, | ||
159 | * in case the boot rom changed something on us. | ||
160 | */ | ||
161 | cpm2_immr->im_intctl.ic_sicr = 0; | ||
162 | cpm2_immr->im_intctl.ic_scprrh = 0x05309770; | ||
163 | cpm2_immr->im_intctl.ic_scprrl = 0x05309770; | ||
164 | |||
165 | |||
166 | /* Enable chaining to OpenPIC, and make everything level | ||
167 | */ | ||
168 | for (i = 0; i < NR_CPM_INTS; i++) { | ||
169 | irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic; | ||
170 | irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL; | ||
171 | } | ||
172 | } | ||