aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/cpm2_pic.c
diff options
context:
space:
mode:
authorVitaly Bordug <vbordug@ru.mvista.com>2007-01-30 18:08:54 -0500
committerPaul Mackerras <paulus@samba.org>2007-02-06 22:03:20 -0500
commit73844ecbaa58885c5e89af7d1b08faaffffa6833 (patch)
treedf2a4f20261e2cf348347786362dff0701e54359 /arch/powerpc/sysdev/cpm2_pic.c
parentc19cdcb1b8d33a20d372191eced2def7f901806b (diff)
[POWERPC] cpm2: CPM2 interrupt controller fix
This contains important fixes for the CPM2 PIC code. Eliminated CPM_IRQ_OFFSET, pulling the respective interrupt numbers from the interrupt mapping. Updated devicetree files to reflect that. Changed direct IC-related IO accesses to the IO accessors. Fixed all the sense values to keep coherency with ipic. In the current code, CPM2 stuff will have no IRQs and hence could be hardly usable. Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/sysdev/cpm2_pic.c')
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c150
1 files changed, 89 insertions, 61 deletions
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index e2739eb93cdf..eabfe06fe05c 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -36,9 +36,20 @@
36#include <asm/mpc8260.h> 36#include <asm/mpc8260.h>
37#include <asm/io.h> 37#include <asm/io.h>
38#include <asm/prom.h> 38#include <asm/prom.h>
39#include <asm/fs_pd.h>
39 40
40#include "cpm2_pic.h" 41#include "cpm2_pic.h"
41 42
43/* External IRQS */
44#define CPM2_IRQ_EXT1 19
45#define CPM2_IRQ_EXT7 25
46
47/* Port C IRQS */
48#define CPM2_IRQ_PORTC15 48
49#define CPM2_IRQ_PORTC0 63
50
51static intctl_cpm2_t *cpm2_intctl;
52
42static struct device_node *cpm2_pic_node; 53static struct device_node *cpm2_pic_node;
43static struct irq_host *cpm2_pic_host; 54static struct irq_host *cpm2_pic_host;
44#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) 55#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
@@ -68,68 +79,55 @@ static const u_char irq_to_siubit[] = {
68 24, 25, 26, 27, 28, 29, 30, 31, 79 24, 25, 26, 27, 28, 29, 30, 31,
69}; 80};
70 81
71static void cpm2_mask_irq(unsigned int irq_nr) 82static void cpm2_mask_irq(unsigned int virq)
72{ 83{
73 int bit, word; 84 int bit, word;
74 volatile uint *simr; 85 unsigned int irq_nr = virq_to_hw(virq);
75
76 irq_nr -= CPM_IRQ_OFFSET;
77 86
78 bit = irq_to_siubit[irq_nr]; 87 bit = irq_to_siubit[irq_nr];
79 word = irq_to_siureg[irq_nr]; 88 word = irq_to_siureg[irq_nr];
80 89
81 simr = &(cpm2_intctl->ic_simrh);
82 ppc_cached_irq_mask[word] &= ~(1 << bit); 90 ppc_cached_irq_mask[word] &= ~(1 << bit);
83 simr[word] = ppc_cached_irq_mask[word]; 91 out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
84} 92}
85 93
86static void cpm2_unmask_irq(unsigned int irq_nr) 94static void cpm2_unmask_irq(unsigned int virq)
87{ 95{
88 int bit, word; 96 int bit, word;
89 volatile uint *simr; 97 unsigned int irq_nr = virq_to_hw(virq);
90
91 irq_nr -= CPM_IRQ_OFFSET;
92 98
93 bit = irq_to_siubit[irq_nr]; 99 bit = irq_to_siubit[irq_nr];
94 word = irq_to_siureg[irq_nr]; 100 word = irq_to_siureg[irq_nr];
95 101
96 simr = &(cpm2_intctl->ic_simrh);
97 ppc_cached_irq_mask[word] |= 1 << bit; 102 ppc_cached_irq_mask[word] |= 1 << bit;
98 simr[word] = ppc_cached_irq_mask[word]; 103 out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
99} 104}
100 105
101static void cpm2_mask_and_ack(unsigned int irq_nr) 106static void cpm2_ack(unsigned int virq)
102{ 107{
103 int bit, word; 108 int bit, word;
104 volatile uint *simr, *sipnr; 109 unsigned int irq_nr = virq_to_hw(virq);
105
106 irq_nr -= CPM_IRQ_OFFSET;
107 110
108 bit = irq_to_siubit[irq_nr]; 111 bit = irq_to_siubit[irq_nr];
109 word = irq_to_siureg[irq_nr]; 112 word = irq_to_siureg[irq_nr];
110 113
111 simr = &(cpm2_intctl->ic_simrh); 114 out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
112 sipnr = &(cpm2_intctl->ic_sipnrh);
113 ppc_cached_irq_mask[word] &= ~(1 << bit);
114 simr[word] = ppc_cached_irq_mask[word];
115 sipnr[word] = 1 << bit;
116} 115}
117 116
118static void cpm2_end_irq(unsigned int irq_nr) 117static void cpm2_end_irq(unsigned int virq)
119{ 118{
120 int bit, word; 119 int bit, word;
121 volatile uint *simr; 120 unsigned int irq_nr = virq_to_hw(virq);
122 121
123 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 122 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
124 && irq_desc[irq_nr].action) { 123 && irq_desc[irq_nr].action) {
125 124
126 irq_nr -= CPM_IRQ_OFFSET;
127 bit = irq_to_siubit[irq_nr]; 125 bit = irq_to_siubit[irq_nr];
128 word = irq_to_siureg[irq_nr]; 126 word = irq_to_siureg[irq_nr];
129 127
130 simr = &(cpm2_intctl->ic_simrh);
131 ppc_cached_irq_mask[word] |= 1 << bit; 128 ppc_cached_irq_mask[word] |= 1 << bit;
132 simr[word] = ppc_cached_irq_mask[word]; 129 out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
130
133 /* 131 /*
134 * Work around large numbers of spurious IRQs on PowerPC 82xx 132 * Work around large numbers of spurious IRQs on PowerPC 82xx
135 * systems. 133 * systems.
@@ -138,13 +136,59 @@ static void cpm2_end_irq(unsigned int irq_nr)
138 } 136 }
139} 137}
140 138
139static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
140{
141 unsigned int src = virq_to_hw(virq);
142 struct irq_desc *desc = get_irq_desc(virq);
143 unsigned int vold, vnew, edibit;
144
145 if (flow_type == IRQ_TYPE_NONE)
146 flow_type = IRQ_TYPE_LEVEL_LOW;
147
148 if (flow_type & IRQ_TYPE_EDGE_RISING) {
149 printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n",
150 flow_type);
151 return -EINVAL;
152 }
153
154 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
155 desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
156 if (flow_type & IRQ_TYPE_LEVEL_LOW) {
157 desc->status |= IRQ_LEVEL;
158 desc->handle_irq = handle_level_irq;
159 } else
160 desc->handle_irq = handle_edge_irq;
161
162 /* internal IRQ senses are LEVEL_LOW
163 * EXT IRQ and Port C IRQ senses are programmable
164 */
165 if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
166 edibit = (14 - (src - CPM2_IRQ_EXT1));
167 else
168 if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
169 edibit = (31 - (src - CPM2_IRQ_PORTC15));
170 else
171 return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
172
173 vold = in_be32(&cpm2_intctl->ic_siexr);
174
175 if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
176 vnew = vold | (1 << edibit);
177 else
178 vnew = vold & ~(1 << edibit);
179
180 if (vold != vnew)
181 out_be32(&cpm2_intctl->ic_siexr, vnew);
182 return 0;
183}
184
141static struct irq_chip cpm2_pic = { 185static struct irq_chip cpm2_pic = {
142 .typename = " CPM2 SIU ", 186 .typename = " CPM2 SIU ",
143 .enable = cpm2_unmask_irq, 187 .mask = cpm2_mask_irq,
144 .disable = cpm2_mask_irq,
145 .unmask = cpm2_unmask_irq, 188 .unmask = cpm2_unmask_irq,
146 .mask_ack = cpm2_mask_and_ack, 189 .ack = cpm2_ack,
147 .end = cpm2_end_irq, 190 .eoi = cpm2_end_irq,
191 .set_type = cpm2_set_irq_type,
148}; 192};
149 193
150unsigned int cpm2_get_irq(void) 194unsigned int cpm2_get_irq(void)
@@ -154,17 +198,17 @@ unsigned int cpm2_get_irq(void)
154 198
155 /* For CPM2, read the SIVEC register and shift the bits down 199 /* For CPM2, read the SIVEC register and shift the bits down
156 * to get the irq number. */ 200 * to get the irq number. */
157 bits = cpm2_intctl->ic_sivec; 201 bits = in_be32(&cpm2_intctl->ic_sivec);
158 irq = bits >> 26; 202 irq = bits >> 26;
159 203
160 if (irq == 0) 204 if (irq == 0)
161 return(-1); 205 return(-1);
162 return irq+CPM_IRQ_OFFSET; 206 return irq_linear_revmap(cpm2_pic_host, irq);
163} 207}
164 208
165static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) 209static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
166{ 210{
167 return cpm2_pic_node == NULL || cpm2_pic_node == node; 211 return cpm2_pic_node == node;
168} 212}
169 213
170static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, 214static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
@@ -177,39 +221,21 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
177 return 0; 221 return 0;
178} 222}
179 223
180static void cpm2_host_unmap(struct irq_host *h, unsigned int virq)
181{
182 /* Make sure irq is masked in hardware */
183 cpm2_mask_irq(virq);
184
185 /* remove chip and handler */
186 set_irq_chip_and_handler(virq, NULL, NULL);
187}
188
189static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, 224static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
190 u32 *intspec, unsigned int intsize, 225 u32 *intspec, unsigned int intsize,
191 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 226 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
192{ 227{
193 static const unsigned char map_cpm2_senses[4] = {
194 IRQ_TYPE_LEVEL_LOW,
195 IRQ_TYPE_LEVEL_HIGH,
196 IRQ_TYPE_EDGE_FALLING,
197 IRQ_TYPE_EDGE_RISING,
198 };
199
200 *out_hwirq = intspec[0]; 228 *out_hwirq = intspec[0];
201 if (intsize > 1 && intspec[1] < 4) 229 if (intsize > 1)
202 *out_flags = map_cpm2_senses[intspec[1]]; 230 *out_flags = intspec[1];
203 else 231 else
204 *out_flags = IRQ_TYPE_NONE; 232 *out_flags = IRQ_TYPE_NONE;
205
206 return 0; 233 return 0;
207} 234}
208 235
209static struct irq_host_ops cpm2_pic_host_ops = { 236static struct irq_host_ops cpm2_pic_host_ops = {
210 .match = cpm2_pic_host_match, 237 .match = cpm2_pic_host_match,
211 .map = cpm2_pic_host_map, 238 .map = cpm2_pic_host_map,
212 .unmap = cpm2_host_unmap,
213 .xlate = cpm2_pic_host_xlate, 239 .xlate = cpm2_pic_host_xlate,
214}; 240};
215 241
@@ -217,32 +243,34 @@ void cpm2_pic_init(struct device_node *node)
217{ 243{
218 int i; 244 int i;
219 245
246 cpm2_intctl = cpm2_map(im_intctl);
247
220 /* Clear the CPM IRQ controller, in case it has any bits set 248 /* Clear the CPM IRQ controller, in case it has any bits set
221 * from the bootloader 249 * from the bootloader
222 */ 250 */
223 251
224 /* Mask out everything */ 252 /* Mask out everything */
225 253
226 cpm2_intctl->ic_simrh = 0x00000000; 254 out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
227 cpm2_intctl->ic_simrl = 0x00000000; 255 out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
228 256
229 wmb(); 257 wmb();
230 258
231 /* Ack everything */ 259 /* Ack everything */
232 cpm2_intctl->ic_sipnrh = 0xffffffff; 260 out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
233 cpm2_intctl->ic_sipnrl = 0xffffffff; 261 out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
234 wmb(); 262 wmb();
235 263
236 /* Dummy read of the vector */ 264 /* Dummy read of the vector */
237 i = cpm2_intctl->ic_sivec; 265 i = in_be32(&cpm2_intctl->ic_sivec);
238 rmb(); 266 rmb();
239 267
240 /* Initialize the default interrupt mapping priorities, 268 /* Initialize the default interrupt mapping priorities,
241 * in case the boot rom changed something on us. 269 * in case the boot rom changed something on us.
242 */ 270 */
243 cpm2_intctl->ic_sicr = 0; 271 out_be16(&cpm2_intctl->ic_sicr, 0);
244 cpm2_intctl->ic_scprrh = 0x05309770; 272 out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
245 cpm2_intctl->ic_scprrl = 0x05309770; 273 out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
246 274
247 /* create a legacy host */ 275 /* create a legacy host */
248 cpm2_pic_node = of_node_get(node); 276 cpm2_pic_node = of_node_get(node);