aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c116
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h2
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c106
3 files changed, 169 insertions, 55 deletions
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 63aa52acf441..9d41e07b0c95 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -123,7 +123,7 @@ static int iic_external_get_irq(struct iic_pending_bits pending)
123 pending.class != 2) 123 pending.class != 2)
124 break; 124 break;
125 irq = IIC_EXT_OFFSET 125 irq = IIC_EXT_OFFSET
126 + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE) 126 + spider_get_irq(node)
127 + node * IIC_NODE_STRIDE; 127 + node * IIC_NODE_STRIDE;
128 break; 128 break;
129 case 0x01 ... 0x04: 129 case 0x01 ... 0x04:
@@ -174,38 +174,102 @@ int iic_get_irq(struct pt_regs *regs)
174 return irq; 174 return irq;
175} 175}
176 176
177static int setup_iic(int cpu, struct iic *iic) 177/* hardcoded part to be compatible with older firmware */
178
179static int setup_iic_hardcoded(void)
178{ 180{
179 struct device_node *np; 181 struct device_node *np;
180 int nodeid = cpu / 2; 182 int nodeid, cpu;
181 unsigned long regs; 183 unsigned long regs;
184 struct iic *iic;
182 185
183 for (np = of_find_node_by_type(NULL, "cpu"); 186 for_each_cpu(cpu) {
184 np; 187 iic = &per_cpu(iic, cpu);
185 np = of_find_node_by_type(np, "cpu")) { 188 nodeid = cpu/2;
186 if (nodeid == *(int *)get_property(np, "node-id", NULL)) 189
187 break; 190 for (np = of_find_node_by_type(NULL, "cpu");
191 np;
192 np = of_find_node_by_type(np, "cpu")) {
193 if (nodeid == *(int *)get_property(np, "node-id", NULL))
194 break;
195 }
196
197 if (!np) {
198 printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
199 iic->regs = NULL;
200 iic->target_id = 0xff;
201 return -ENODEV;
202 }
203
204 regs = *(long *)get_property(np, "iic", NULL);
205
206 /* hack until we have decided on the devtree info */
207 regs += 0x400;
208 if (cpu & 1)
209 regs += 0x20;
210
211 printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
212 iic->regs = __ioremap(regs, sizeof(struct iic_regs),
213 _PAGE_NO_CACHE);
214
215 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
188 } 216 }
189 217
190 if (!np) { 218 return 0;
191 printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); 219}
192 iic->regs = NULL;
193 iic->target_id = 0xff;
194 return -ENODEV;
195 }
196 220
197 regs = *(long *)get_property(np, "iic", NULL); 221static int setup_iic(void)
222{
223 struct device_node *dn;
224 unsigned long *regs;
225 char *compatible;
226 unsigned *np, found = 0;
227 struct iic *iic = NULL;
228
229 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
230 compatible = (char *)get_property(dn, "compatible", NULL);
231
232 if (!compatible) {
233 printk(KERN_WARNING "no compatible property found !\n");
234 continue;
235 }
198 236
199 /* hack until we have decided on the devtree info */ 237 if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
200 regs += 0x400; 238 regs = (unsigned long *)get_property(dn,"reg", NULL);
201 if (cpu & 1) 239 else
202 regs += 0x20; 240 continue;
203 241
204 printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); 242 if (!regs)
205 iic->regs = __ioremap(regs, sizeof(struct iic_regs), 243 printk(KERN_WARNING "IIC: no reg property\n");
206 _PAGE_NO_CACHE); 244
207 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); 245 np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
208 return 0; 246
247 if (!np) {
248 printk(KERN_WARNING "IIC: CPU association not found\n");
249 iic->regs = NULL;
250 iic->target_id = 0xff;
251 return -ENODEV;
252 }
253
254 iic = &per_cpu(iic, np[0]);
255 iic->regs = __ioremap(regs[0], sizeof(struct iic_regs),
256 _PAGE_NO_CACHE);
257 iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
258 printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
259
260 iic = &per_cpu(iic, np[1]);
261 iic->regs = __ioremap(regs[2], sizeof(struct iic_regs),
262 _PAGE_NO_CACHE);
263 iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
264 printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
265
266 found++;
267 }
268
269 if (found)
270 return 0;
271 else
272 return -ENODEV;
209} 273}
210 274
211#ifdef CONFIG_SMP 275#ifdef CONFIG_SMP
@@ -283,10 +347,12 @@ void iic_init_IRQ(void)
283 int cpu, irq_offset; 347 int cpu, irq_offset;
284 struct iic *iic; 348 struct iic *iic;
285 349
350 if (setup_iic() < 0)
351 setup_iic_hardcoded();
352
286 irq_offset = 0; 353 irq_offset = 0;
287 for_each_cpu(cpu) { 354 for_each_cpu(cpu) {
288 iic = &per_cpu(iic, cpu); 355 iic = &per_cpu(iic, cpu);
289 setup_iic(cpu, iic);
290 if (iic->regs) 356 if (iic->regs)
291 out_be64(&iic->regs->prio, 0xff); 357 out_be64(&iic->regs->prio, 0xff);
292 } 358 }
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index a14bd38791c0..799f77d98f96 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -57,7 +57,7 @@ extern void iic_local_disable(void);
57extern u8 iic_get_target_id(int cpu); 57extern u8 iic_get_target_id(int cpu);
58 58
59extern void spider_init_IRQ(void); 59extern void spider_init_IRQ(void);
60extern int spider_get_irq(unsigned long int_pending); 60extern int spider_get_irq(int node);
61 61
62#endif 62#endif
63#endif /* ASM_CELL_PIC_H */ 63#endif /* ASM_CELL_PIC_H */
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index e74132188bdf..0e9bb0b72c50 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -84,10 +84,11 @@ static void __iomem *spider_get_irq_config(int irq)
84 84
85static void spider_enable_irq(unsigned int irq) 85static void spider_enable_irq(unsigned int irq)
86{ 86{
87 int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
87 void __iomem *cfg = spider_get_irq_config(irq); 88 void __iomem *cfg = spider_get_irq_config(irq);
88 irq = spider_get_nr(irq); 89 irq = spider_get_nr(irq);
89 90
90 out_be32(cfg, in_be32(cfg) | 0x3107000eu); 91 out_be32(cfg, in_be32(cfg) | 0x3107000eu | nodeid);
91 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); 92 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
92} 93}
93 94
@@ -131,61 +132,108 @@ static struct hw_interrupt_type spider_pic = {
131 .end = spider_end_irq, 132 .end = spider_end_irq,
132}; 133};
133 134
134 135int spider_get_irq(int node)
135int spider_get_irq(unsigned long int_pending)
136{ 136{
137 void __iomem *regs = spider_get_pic(int_pending);
138 unsigned long cs; 137 unsigned long cs;
139 int irq; 138 void __iomem *regs = spider_pics[node];
140
141 cs = in_be32(regs + TIR_CS);
142 139
143 irq = cs >> 24; 140 cs = in_be32(regs + TIR_CS) >> 24;
144 if (irq != 63)
145 return irq;
146 141
147 return -1; 142 if (cs == 63)
143 return -1;
144 else
145 return cs;
148} 146}
149 147
150void spider_init_IRQ(void) 148/* hardcoded part to be compatible with older firmware */
149
150void spider_init_IRQ_hardcoded(void)
151{ 151{
152 int node; 152 int node;
153 struct device_node *dn;
154 unsigned int *property;
155 long spiderpic; 153 long spiderpic;
154 long pics[] = { 0x24000008000, 0x34000008000 };
156 int n; 155 int n;
157 156
158/* FIXME: detect multiple PICs as soon as the device tree has them */ 157 pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
159 for (node = 0; node < 1; node++) {
160 dn = of_find_node_by_path("/");
161 n = prom_n_addr_cells(dn);
162 property = (unsigned int *) get_property(dn,
163 "platform-spider-pic", NULL);
164 158
165 if (!property) 159 for (node = 0; node < num_present_cpus()/2; node++) {
166 continue; 160 spiderpic = pics[node];
167 for (spiderpic = 0; n > 0; --n)
168 spiderpic = (spiderpic << 32) + *property++;
169 printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); 161 printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
170 spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE); 162 spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE);
171 for (n = 0; n < IIC_NUM_EXT; n++) { 163 for (n = 0; n < IIC_NUM_EXT; n++) {
172 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; 164 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
173 get_irq_desc(irq)->handler = &spider_pic; 165 get_irq_desc(irq)->handler = &spider_pic;
166 }
174 167
175 /* do not mask any interrupts because of level */ 168 /* do not mask any interrupts because of level */
176 out_be32(spider_pics[node] + TIR_MSK, 0x0); 169 out_be32(spider_pics[node] + TIR_MSK, 0x0);
177 170
178 /* disable edge detection clear */ 171 /* disable edge detection clear */
179 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ 172 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
180 173
181 /* enable interrupt packets to be output */ 174 /* enable interrupt packets to be output */
182 out_be32(spider_pics[node] + TIR_PIEN, 175 out_be32(spider_pics[node] + TIR_PIEN,
183 in_be32(spider_pics[node] + TIR_PIEN) | 0x1); 176 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
184 177
185 /* Enable the interrupt detection enable bit. Do this last! */ 178 /* Enable the interrupt detection enable bit. Do this last! */
186 out_be32(spider_pics[node] + TIR_DEN, 179 out_be32(spider_pics[node] + TIR_DEN,
187 in_be32(spider_pics[node] +TIR_DEN) | 0x1); 180 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
181 }
182}
183
184void spider_init_IRQ(void)
185{
186 long spider_reg;
187 struct device_node *dn;
188 char *compatible;
189 int n, node = 0;
190
191 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
192 compatible = (char *)get_property(dn, "compatible", NULL);
188 193
194 if (!compatible)
195 continue;
196
197 if (strstr(compatible, "CBEA,platform-spider-pic"))
198 spider_reg = *(long *)get_property(dn,"reg", NULL);
199 else if (strstr(compatible, "sti,platform-spider-pic")) {
200 spider_init_IRQ_hardcoded();
201 return;
202 } else
203 continue;
204
205 if (!spider_reg)
206 printk("interrupt controller does not have reg property !\n");
207
208 n = prom_n_addr_cells(dn);
209
210 if ( n != 2)
211 printk("reg property with invalid number of elements \n");
212
213 spider_pics[node] = __ioremap(spider_reg, 0x800, _PAGE_NO_CACHE);
214
215 printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
216 spider_reg, n, spider_pics[node]);
217
218 for (n = 0; n < IIC_NUM_EXT; n++) {
219 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
220 get_irq_desc(irq)->handler = &spider_pic;
189 } 221 }
222
223 /* do not mask any interrupts because of level */
224 out_be32(spider_pics[node] + TIR_MSK, 0x0);
225
226 /* disable edge detection clear */
227 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
228
229 /* enable interrupt packets to be output */
230 out_be32(spider_pics[node] + TIR_PIEN,
231 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
232
233 /* Enable the interrupt detection enable bit. Do this last! */
234 out_be32(spider_pics[node] + TIR_DEN,
235 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
236
237 node++;
190 } 238 }
191} 239}