Linux Audio

Check our new training course

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