Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[deliverable/linux.git] / arch / ppc / syslib / cpm2_pic.c
CommitLineData
1da177e4
LT
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
24static 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]) */
37static u_char irq_to_siubit[] = {
38 0, 15, 14, 13, 12, 11, 10, 9,
39 8, 7, 6, 5, 4, 3, 2, 1,
7f7fda04 40 2, 1, 0, 14, 13, 12, 11, 10,
1da177e4
LT
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
48static 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
63static 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
78static 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
95static 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];
1bdacf88
DM
110 /*
111 * Work around large numbers of spurious IRQs on PowerPC 82xx
112 * systems.
113 */
114 mb();
1da177e4
LT
115 }
116}
117
118static struct hw_interrupt_type cpm2_pic = {
119 .typename = " CPM2 SIU ",
120 .enable = cpm2_unmask_irq,
121 .disable = cpm2_mask_irq,
122 .ack = cpm2_mask_and_ack,
123 .end = cpm2_end_irq,
124};
125
39e3eb72 126int cpm2_get_irq(void)
1da177e4
LT
127{
128 int irq;
129 unsigned long bits;
130
131 /* For CPM2, read the SIVEC register and shift the bits down
132 * to get the irq number. */
133 bits = cpm2_immr->im_intctl.ic_sivec;
134 irq = bits >> 26;
135
136 if (irq == 0)
137 return(-1);
138 return irq+CPM_IRQ_OFFSET;
139}
140
141void cpm2_init_IRQ(void)
142{
143 int i;
144
145 /* Clear the CPM IRQ controller, in case it has any bits set
146 * from the bootloader
147 */
148
149 /* Mask out everything */
150 cpm2_immr->im_intctl.ic_simrh = 0x00000000;
151 cpm2_immr->im_intctl.ic_simrl = 0x00000000;
152 wmb();
153
154 /* Ack everything */
155 cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
156 cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
157 wmb();
158
159 /* Dummy read of the vector */
160 i = cpm2_immr->im_intctl.ic_sivec;
161 rmb();
162
163 /* Initialize the default interrupt mapping priorities,
164 * in case the boot rom changed something on us.
165 */
166 cpm2_immr->im_intctl.ic_sicr = 0;
167 cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
168 cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
169
170
171 /* Enable chaining to OpenPIC, and make everything level
172 */
173 for (i = 0; i < NR_CPM_INTS; i++) {
d1bef4ed 174 irq_desc[i+CPM_IRQ_OFFSET].chip = &cpm2_pic;
1da177e4
LT
175 irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
176 }
177}
This page took 0.282301 seconds and 5 git commands to generate.