xref: /linux/arch/mips/bcm63xx/irq.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7  * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr>
8  */
9 
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/irq.h>
14 #include <linux/spinlock.h>
15 #include <asm/irq_cpu.h>
16 #include <asm/mipsregs.h>
17 #include <bcm63xx_cpu.h>
18 #include <bcm63xx_regs.h>
19 #include <bcm63xx_io.h>
20 #include <bcm63xx_irq.h>
21 
22 
23 static DEFINE_SPINLOCK(ipic_lock);
24 static DEFINE_SPINLOCK(epic_lock);
25 
26 static u32 irq_stat_addr[2];
27 static u32 irq_mask_addr[2];
28 static void (*dispatch_internal)(int cpu);
29 static int is_ext_irq_cascaded;
30 static unsigned int ext_irq_count;
31 static unsigned int ext_irq_start, ext_irq_end;
32 static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
33 static void (*internal_irq_mask)(struct irq_data *d);
34 static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m);
35 
36 
37 static inline u32 get_ext_irq_perf_reg(int irq)
38 {
39 	if (irq < 4)
40 		return ext_irq_cfg_reg1;
41 	return ext_irq_cfg_reg2;
42 }
43 
44 static inline void handle_internal(int intbit)
45 {
46 	if (is_ext_irq_cascaded &&
47 	    intbit >= ext_irq_start && intbit <= ext_irq_end)
48 		do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
49 	else
50 		do_IRQ(intbit + IRQ_INTERNAL_BASE);
51 }
52 
53 static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
54 				     const struct cpumask *m)
55 {
56 	bool enable = cpu_online(cpu);
57 
58 #ifdef CONFIG_SMP
59 	if (m)
60 		enable &= cpumask_test_cpu(cpu, m);
61 	else if (irqd_affinity_was_set(d))
62 		enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d));
63 #endif
64 	return enable;
65 }
66 
67 /*
68  * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
69  * prioritize any interrupt relatively to another. the static counter
70  * will resume the loop where it ended the last time we left this
71  * function.
72  */
73 
74 #define BUILD_IPIC_INTERNAL(width)					\
75 void __dispatch_internal_##width(int cpu)				\
76 {									\
77 	u32 pending[width / 32];					\
78 	unsigned int src, tgt;						\
79 	bool irqs_pending = false;					\
80 	static unsigned int i[2];					\
81 	unsigned int *next = &i[cpu];					\
82 	unsigned long flags;						\
83 									\
84 	/* read registers in reverse order */				\
85 	spin_lock_irqsave(&ipic_lock, flags);				\
86 	for (src = 0, tgt = (width / 32); src < (width / 32); src++) {	\
87 		u32 val;						\
88 									\
89 		val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \
90 		val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \
91 		pending[--tgt] = val;					\
92 									\
93 		if (val)						\
94 			irqs_pending = true;				\
95 	}								\
96 	spin_unlock_irqrestore(&ipic_lock, flags);			\
97 									\
98 	if (!irqs_pending)						\
99 		return;							\
100 									\
101 	while (1) {							\
102 		unsigned int to_call = *next;				\
103 									\
104 		*next = (*next + 1) & (width - 1);			\
105 		if (pending[to_call / 32] & (1 << (to_call & 0x1f))) {	\
106 			handle_internal(to_call);			\
107 			break;						\
108 		}							\
109 	}								\
110 }									\
111 									\
112 static void __internal_irq_mask_##width(struct irq_data *d)		\
113 {									\
114 	u32 val;							\
115 	unsigned irq = d->irq - IRQ_INTERNAL_BASE;			\
116 	unsigned reg = (irq / 32) ^ (width/32 - 1);			\
117 	unsigned bit = irq & 0x1f;					\
118 	unsigned long flags;						\
119 	int cpu;							\
120 									\
121 	spin_lock_irqsave(&ipic_lock, flags);				\
122 	for_each_present_cpu(cpu) {					\
123 		if (!irq_mask_addr[cpu])				\
124 			break;						\
125 									\
126 		val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
127 		val &= ~(1 << bit);					\
128 		bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
129 	}								\
130 	spin_unlock_irqrestore(&ipic_lock, flags);			\
131 }									\
132 									\
133 static void __internal_irq_unmask_##width(struct irq_data *d,		\
134 					  const struct cpumask *m)	\
135 {									\
136 	u32 val;							\
137 	unsigned irq = d->irq - IRQ_INTERNAL_BASE;			\
138 	unsigned reg = (irq / 32) ^ (width/32 - 1);			\
139 	unsigned bit = irq & 0x1f;					\
140 	unsigned long flags;						\
141 	int cpu;							\
142 									\
143 	spin_lock_irqsave(&ipic_lock, flags);				\
144 	for_each_present_cpu(cpu) {					\
145 		if (!irq_mask_addr[cpu])				\
146 			break;						\
147 									\
148 		val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
149 		if (enable_irq_for_cpu(cpu, d, m))			\
150 			val |= (1 << bit);				\
151 		else							\
152 			val &= ~(1 << bit);				\
153 		bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
154 	}								\
155 	spin_unlock_irqrestore(&ipic_lock, flags);			\
156 }
157 
158 BUILD_IPIC_INTERNAL(32);
159 BUILD_IPIC_INTERNAL(64);
160 
161 asmlinkage void plat_irq_dispatch(void)
162 {
163 	u32 cause;
164 
165 	do {
166 		cause = read_c0_cause() & read_c0_status() & ST0_IM;
167 
168 		if (!cause)
169 			break;
170 
171 		if (cause & CAUSEF_IP7)
172 			do_IRQ(7);
173 		if (cause & CAUSEF_IP0)
174 			do_IRQ(0);
175 		if (cause & CAUSEF_IP1)
176 			do_IRQ(1);
177 		if (cause & CAUSEF_IP2)
178 			dispatch_internal(0);
179 		if (is_ext_irq_cascaded) {
180 			if (cause & CAUSEF_IP3)
181 				dispatch_internal(1);
182 		} else {
183 			if (cause & CAUSEF_IP3)
184 				do_IRQ(IRQ_EXT_0);
185 			if (cause & CAUSEF_IP4)
186 				do_IRQ(IRQ_EXT_1);
187 			if (cause & CAUSEF_IP5)
188 				do_IRQ(IRQ_EXT_2);
189 			if (cause & CAUSEF_IP6)
190 				do_IRQ(IRQ_EXT_3);
191 		}
192 	} while (1);
193 }
194 
195 /*
196  * internal IRQs operations: only mask/unmask on PERF irq mask
197  * register.
198  */
199 static void bcm63xx_internal_irq_mask(struct irq_data *d)
200 {
201 	internal_irq_mask(d);
202 }
203 
204 static void bcm63xx_internal_irq_unmask(struct irq_data *d)
205 {
206 	internal_irq_unmask(d, NULL);
207 }
208 
209 /*
210  * external IRQs operations: mask/unmask and clear on PERF external
211  * irq control register.
212  */
213 static void bcm63xx_external_irq_mask(struct irq_data *d)
214 {
215 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
216 	u32 reg, regaddr;
217 	unsigned long flags;
218 
219 	regaddr = get_ext_irq_perf_reg(irq);
220 	spin_lock_irqsave(&epic_lock, flags);
221 	reg = bcm_perf_readl(regaddr);
222 
223 	if (BCMCPU_IS_6348())
224 		reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
225 	else
226 		reg &= ~EXTIRQ_CFG_MASK(irq % 4);
227 
228 	bcm_perf_writel(reg, regaddr);
229 	spin_unlock_irqrestore(&epic_lock, flags);
230 
231 	if (is_ext_irq_cascaded)
232 		internal_irq_mask(irq_get_irq_data(irq + ext_irq_start));
233 }
234 
235 static void bcm63xx_external_irq_unmask(struct irq_data *d)
236 {
237 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
238 	u32 reg, regaddr;
239 	unsigned long flags;
240 
241 	regaddr = get_ext_irq_perf_reg(irq);
242 	spin_lock_irqsave(&epic_lock, flags);
243 	reg = bcm_perf_readl(regaddr);
244 
245 	if (BCMCPU_IS_6348())
246 		reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
247 	else
248 		reg |= EXTIRQ_CFG_MASK(irq % 4);
249 
250 	bcm_perf_writel(reg, regaddr);
251 	spin_unlock_irqrestore(&epic_lock, flags);
252 
253 	if (is_ext_irq_cascaded)
254 		internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start),
255 				    NULL);
256 }
257 
258 static void bcm63xx_external_irq_clear(struct irq_data *d)
259 {
260 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
261 	u32 reg, regaddr;
262 	unsigned long flags;
263 
264 	regaddr = get_ext_irq_perf_reg(irq);
265 	spin_lock_irqsave(&epic_lock, flags);
266 	reg = bcm_perf_readl(regaddr);
267 
268 	if (BCMCPU_IS_6348())
269 		reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
270 	else
271 		reg |= EXTIRQ_CFG_CLEAR(irq % 4);
272 
273 	bcm_perf_writel(reg, regaddr);
274 	spin_unlock_irqrestore(&epic_lock, flags);
275 }
276 
277 static int bcm63xx_external_irq_set_type(struct irq_data *d,
278 					 unsigned int flow_type)
279 {
280 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
281 	u32 reg, regaddr;
282 	int levelsense, sense, bothedge;
283 	unsigned long flags;
284 
285 	flow_type &= IRQ_TYPE_SENSE_MASK;
286 
287 	if (flow_type == IRQ_TYPE_NONE)
288 		flow_type = IRQ_TYPE_LEVEL_LOW;
289 
290 	levelsense = sense = bothedge = 0;
291 	switch (flow_type) {
292 	case IRQ_TYPE_EDGE_BOTH:
293 		bothedge = 1;
294 		break;
295 
296 	case IRQ_TYPE_EDGE_RISING:
297 		sense = 1;
298 		break;
299 
300 	case IRQ_TYPE_EDGE_FALLING:
301 		break;
302 
303 	case IRQ_TYPE_LEVEL_HIGH:
304 		levelsense = 1;
305 		sense = 1;
306 		break;
307 
308 	case IRQ_TYPE_LEVEL_LOW:
309 		levelsense = 1;
310 		break;
311 
312 	default:
313 		pr_err("bogus flow type combination given !\n");
314 		return -EINVAL;
315 	}
316 
317 	regaddr = get_ext_irq_perf_reg(irq);
318 	spin_lock_irqsave(&epic_lock, flags);
319 	reg = bcm_perf_readl(regaddr);
320 	irq %= 4;
321 
322 	switch (bcm63xx_get_cpu_id()) {
323 	case BCM6348_CPU_ID:
324 		if (levelsense)
325 			reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
326 		else
327 			reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
328 		if (sense)
329 			reg |= EXTIRQ_CFG_SENSE_6348(irq);
330 		else
331 			reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
332 		if (bothedge)
333 			reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
334 		else
335 			reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
336 		break;
337 
338 	case BCM3368_CPU_ID:
339 	case BCM6328_CPU_ID:
340 	case BCM6338_CPU_ID:
341 	case BCM6345_CPU_ID:
342 	case BCM6358_CPU_ID:
343 	case BCM6362_CPU_ID:
344 	case BCM6368_CPU_ID:
345 		if (levelsense)
346 			reg |= EXTIRQ_CFG_LEVELSENSE(irq);
347 		else
348 			reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
349 		if (sense)
350 			reg |= EXTIRQ_CFG_SENSE(irq);
351 		else
352 			reg &= ~EXTIRQ_CFG_SENSE(irq);
353 		if (bothedge)
354 			reg |= EXTIRQ_CFG_BOTHEDGE(irq);
355 		else
356 			reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
357 		break;
358 	default:
359 		BUG();
360 	}
361 
362 	bcm_perf_writel(reg, regaddr);
363 	spin_unlock_irqrestore(&epic_lock, flags);
364 
365 	irqd_set_trigger_type(d, flow_type);
366 	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
367 		irq_set_handler_locked(d, handle_level_irq);
368 	else
369 		irq_set_handler_locked(d, handle_edge_irq);
370 
371 	return IRQ_SET_MASK_OK_NOCOPY;
372 }
373 
374 #ifdef CONFIG_SMP
375 static int bcm63xx_internal_set_affinity(struct irq_data *data,
376 					 const struct cpumask *dest,
377 					 bool force)
378 {
379 	if (!irqd_irq_disabled(data))
380 		internal_irq_unmask(data, dest);
381 
382 	return 0;
383 }
384 #endif
385 
386 static struct irq_chip bcm63xx_internal_irq_chip = {
387 	.name		= "bcm63xx_ipic",
388 	.irq_mask	= bcm63xx_internal_irq_mask,
389 	.irq_unmask	= bcm63xx_internal_irq_unmask,
390 };
391 
392 static struct irq_chip bcm63xx_external_irq_chip = {
393 	.name		= "bcm63xx_epic",
394 	.irq_ack	= bcm63xx_external_irq_clear,
395 
396 	.irq_mask	= bcm63xx_external_irq_mask,
397 	.irq_unmask	= bcm63xx_external_irq_unmask,
398 
399 	.irq_set_type	= bcm63xx_external_irq_set_type,
400 };
401 
402 static void bcm63xx_init_irq(void)
403 {
404 	int irq_bits;
405 
406 	irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
407 	irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
408 	irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
409 	irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
410 
411 	switch (bcm63xx_get_cpu_id()) {
412 	case BCM3368_CPU_ID:
413 		irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
414 		irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
415 		irq_stat_addr[1] = 0;
416 		irq_mask_addr[1] = 0;
417 		irq_bits = 32;
418 		ext_irq_count = 4;
419 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
420 		break;
421 	case BCM6328_CPU_ID:
422 		irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
423 		irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
424 		irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
425 		irq_mask_addr[1] += PERF_IRQMASK_6328_REG(1);
426 		irq_bits = 64;
427 		ext_irq_count = 4;
428 		is_ext_irq_cascaded = 1;
429 		ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
430 		ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
431 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
432 		break;
433 	case BCM6338_CPU_ID:
434 		irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
435 		irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
436 		irq_stat_addr[1] = 0;
437 		irq_mask_addr[1] = 0;
438 		irq_bits = 32;
439 		ext_irq_count = 4;
440 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
441 		break;
442 	case BCM6345_CPU_ID:
443 		irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
444 		irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
445 		irq_stat_addr[1] = 0;
446 		irq_mask_addr[1] = 0;
447 		irq_bits = 32;
448 		ext_irq_count = 4;
449 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
450 		break;
451 	case BCM6348_CPU_ID:
452 		irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
453 		irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
454 		irq_stat_addr[1] = 0;
455 		irq_mask_addr[1] = 0;
456 		irq_bits = 32;
457 		ext_irq_count = 4;
458 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
459 		break;
460 	case BCM6358_CPU_ID:
461 		irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
462 		irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
463 		irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
464 		irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
465 		irq_bits = 32;
466 		ext_irq_count = 4;
467 		is_ext_irq_cascaded = 1;
468 		ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
469 		ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
470 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
471 		break;
472 	case BCM6362_CPU_ID:
473 		irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
474 		irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
475 		irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
476 		irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
477 		irq_bits = 64;
478 		ext_irq_count = 4;
479 		is_ext_irq_cascaded = 1;
480 		ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
481 		ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
482 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
483 		break;
484 	case BCM6368_CPU_ID:
485 		irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
486 		irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
487 		irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
488 		irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
489 		irq_bits = 64;
490 		ext_irq_count = 6;
491 		is_ext_irq_cascaded = 1;
492 		ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
493 		ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
494 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
495 		ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
496 		break;
497 	default:
498 		BUG();
499 	}
500 
501 	if (irq_bits == 32) {
502 		dispatch_internal = __dispatch_internal_32;
503 		internal_irq_mask = __internal_irq_mask_32;
504 		internal_irq_unmask = __internal_irq_unmask_32;
505 	} else {
506 		dispatch_internal = __dispatch_internal_64;
507 		internal_irq_mask = __internal_irq_mask_64;
508 		internal_irq_unmask = __internal_irq_unmask_64;
509 	}
510 }
511 
512 void __init arch_init_irq(void)
513 {
514 	int i, irq;
515 
516 	bcm63xx_init_irq();
517 	mips_cpu_irq_init();
518 	for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
519 		irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
520 					 handle_level_irq);
521 
522 	for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
523 		irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
524 					 handle_edge_irq);
525 
526 	if (!is_ext_irq_cascaded) {
527 		for (i = 3; i < 3 + ext_irq_count; ++i) {
528 			irq = MIPS_CPU_IRQ_BASE + i;
529 			if (request_irq(irq, no_action, IRQF_NO_THREAD,
530 					"cascade_extirq", NULL)) {
531 				pr_err("Failed to request irq %d (cascade_extirq)\n",
532 				       irq);
533 			}
534 		}
535 	}
536 
537 	irq = MIPS_CPU_IRQ_BASE + 2;
538 	if (request_irq(irq, no_action, IRQF_NO_THREAD,	"cascade_ip2", NULL))
539 		pr_err("Failed to request irq %d (cascade_ip2)\n", irq);
540 #ifdef CONFIG_SMP
541 	if (is_ext_irq_cascaded) {
542 		irq = MIPS_CPU_IRQ_BASE + 3;
543 		if (request_irq(irq, no_action,	IRQF_NO_THREAD, "cascade_ip3",
544 				NULL))
545 			pr_err("Failed to request irq %d (cascade_ip3)\n", irq);
546 		bcm63xx_internal_irq_chip.irq_set_affinity =
547 			bcm63xx_internal_set_affinity;
548 
549 		cpumask_clear(irq_default_affinity);
550 		cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
551 	}
552 #endif
553 }
554