xref: /openbmc/linux/arch/mips/bcm63xx/irq.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
1e7300d04SMaxime Bizon /*
2e7300d04SMaxime Bizon  * This file is subject to the terms and conditions of the GNU General Public
3e7300d04SMaxime Bizon  * License.  See the file "COPYING" in the main directory of this archive
4e7300d04SMaxime Bizon  * for more details.
5e7300d04SMaxime Bizon  *
6e7300d04SMaxime Bizon  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7e7300d04SMaxime Bizon  * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr>
8e7300d04SMaxime Bizon  */
9e7300d04SMaxime Bizon 
10e7300d04SMaxime Bizon #include <linux/kernel.h>
11e7300d04SMaxime Bizon #include <linux/init.h>
12e7300d04SMaxime Bizon #include <linux/interrupt.h>
13ca4d3e67SDavid Howells #include <linux/irq.h>
1474b8ca3fSJonas Gorski #include <linux/spinlock.h>
15e7300d04SMaxime Bizon #include <asm/irq_cpu.h>
16e7300d04SMaxime Bizon #include <asm/mipsregs.h>
17e7300d04SMaxime Bizon #include <bcm63xx_cpu.h>
18e7300d04SMaxime Bizon #include <bcm63xx_regs.h>
19e7300d04SMaxime Bizon #include <bcm63xx_io.h>
20e7300d04SMaxime Bizon #include <bcm63xx_irq.h>
21e7300d04SMaxime Bizon 
227a9fd14dSJonas Gorski 
2374b8ca3fSJonas Gorski static DEFINE_SPINLOCK(ipic_lock);
2474b8ca3fSJonas Gorski static DEFINE_SPINLOCK(epic_lock);
2574b8ca3fSJonas Gorski 
26cc81d7f3SJonas Gorski static u32 irq_stat_addr[2];
27cc81d7f3SJonas Gorski static u32 irq_mask_addr[2];
287a9fd14dSJonas Gorski static void (*dispatch_internal)(int cpu);
2937c42a74SMaxime Bizon static int is_ext_irq_cascaded;
306224892cSMaxime Bizon static unsigned int ext_irq_count;
3137c42a74SMaxime Bizon static unsigned int ext_irq_start, ext_irq_end;
326224892cSMaxime Bizon static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
33553e25b3SJonas Gorski static void (*internal_irq_mask)(struct irq_data *d);
34b37f0f69SJonas Gorski static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m);
35f61cced9SMaxime Bizon 
36f61cced9SMaxime Bizon 
get_ext_irq_perf_reg(int irq)376224892cSMaxime Bizon static inline u32 get_ext_irq_perf_reg(int irq)
386224892cSMaxime Bizon {
396224892cSMaxime Bizon 	if (irq < 4)
406224892cSMaxime Bizon 		return ext_irq_cfg_reg1;
416224892cSMaxime Bizon 	return ext_irq_cfg_reg2;
426224892cSMaxime Bizon }
436224892cSMaxime Bizon 
handle_internal(int intbit)44f61cced9SMaxime Bizon static inline void handle_internal(int intbit)
45f61cced9SMaxime Bizon {
4637c42a74SMaxime Bizon 	if (is_ext_irq_cascaded &&
4737c42a74SMaxime Bizon 	    intbit >= ext_irq_start && intbit <= ext_irq_end)
4837c42a74SMaxime Bizon 		do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
4937c42a74SMaxime Bizon 	else
50f61cced9SMaxime Bizon 		do_IRQ(intbit + IRQ_INTERNAL_BASE);
51f61cced9SMaxime Bizon }
52f61cced9SMaxime Bizon 
enable_irq_for_cpu(int cpu,struct irq_data * d,const struct cpumask * m)53b37f0f69SJonas Gorski static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
54b37f0f69SJonas Gorski 				     const struct cpumask *m)
55b37f0f69SJonas Gorski {
56b37f0f69SJonas Gorski 	bool enable = cpu_online(cpu);
57b37f0f69SJonas Gorski 
58b37f0f69SJonas Gorski #ifdef CONFIG_SMP
59b37f0f69SJonas Gorski 	if (m)
608dd92891SRusty Russell 		enable &= cpumask_test_cpu(cpu, m);
61b37f0f69SJonas Gorski 	else if (irqd_affinity_was_set(d))
625c159422SJiang Liu 		enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d));
63b37f0f69SJonas Gorski #endif
64b37f0f69SJonas Gorski 	return enable;
65b37f0f69SJonas Gorski }
66b37f0f69SJonas Gorski 
67e7300d04SMaxime Bizon /*
68e7300d04SMaxime Bizon  * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
69e7300d04SMaxime Bizon  * prioritize any interrupt relatively to another. the static counter
70e7300d04SMaxime Bizon  * will resume the loop where it ended the last time we left this
71e7300d04SMaxime Bizon  * function.
72e7300d04SMaxime Bizon  */
73e7300d04SMaxime Bizon 
7486ee4333SJonas Gorski #define BUILD_IPIC_INTERNAL(width)					\
757a9fd14dSJonas Gorski void __dispatch_internal_##width(int cpu)				\
7686ee4333SJonas Gorski {									\
7786ee4333SJonas Gorski 	u32 pending[width / 32];					\
7886ee4333SJonas Gorski 	unsigned int src, tgt;						\
7986ee4333SJonas Gorski 	bool irqs_pending = false;					\
807a9fd14dSJonas Gorski 	static unsigned int i[2];					\
817a9fd14dSJonas Gorski 	unsigned int *next = &i[cpu];					\
8274b8ca3fSJonas Gorski 	unsigned long flags;						\
8386ee4333SJonas Gorski 									\
8486ee4333SJonas Gorski 	/* read registers in reverse order */				\
8574b8ca3fSJonas Gorski 	spin_lock_irqsave(&ipic_lock, flags);				\
8686ee4333SJonas Gorski 	for (src = 0, tgt = (width / 32); src < (width / 32); src++) {	\
8786ee4333SJonas Gorski 		u32 val;						\
8886ee4333SJonas Gorski 									\
897a9fd14dSJonas Gorski 		val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \
907a9fd14dSJonas Gorski 		val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \
9186ee4333SJonas Gorski 		pending[--tgt] = val;					\
9286ee4333SJonas Gorski 									\
9386ee4333SJonas Gorski 		if (val)						\
9486ee4333SJonas Gorski 			irqs_pending = true;				\
9586ee4333SJonas Gorski 	}								\
9674b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&ipic_lock, flags);			\
9786ee4333SJonas Gorski 									\
9886ee4333SJonas Gorski 	if (!irqs_pending)						\
9986ee4333SJonas Gorski 		return;							\
10086ee4333SJonas Gorski 									\
10186ee4333SJonas Gorski 	while (1) {							\
1027a9fd14dSJonas Gorski 		unsigned int to_call = *next;				\
10386ee4333SJonas Gorski 									\
1047a9fd14dSJonas Gorski 		*next = (*next + 1) & (width - 1);			\
10586ee4333SJonas Gorski 		if (pending[to_call / 32] & (1 << (to_call & 0x1f))) {	\
10686ee4333SJonas Gorski 			handle_internal(to_call);			\
10786ee4333SJonas Gorski 			break;						\
10886ee4333SJonas Gorski 		}							\
10986ee4333SJonas Gorski 	}								\
11086ee4333SJonas Gorski }									\
11186ee4333SJonas Gorski 									\
112553e25b3SJonas Gorski static void __internal_irq_mask_##width(struct irq_data *d)		\
11386ee4333SJonas Gorski {									\
11486ee4333SJonas Gorski 	u32 val;							\
115553e25b3SJonas Gorski 	unsigned irq = d->irq - IRQ_INTERNAL_BASE;			\
11686ee4333SJonas Gorski 	unsigned reg = (irq / 32) ^ (width/32 - 1);			\
11786ee4333SJonas Gorski 	unsigned bit = irq & 0x1f;					\
11874b8ca3fSJonas Gorski 	unsigned long flags;						\
11956d53eaeSJonas Gorski 	int cpu;							\
12086ee4333SJonas Gorski 									\
12174b8ca3fSJonas Gorski 	spin_lock_irqsave(&ipic_lock, flags);				\
12256d53eaeSJonas Gorski 	for_each_present_cpu(cpu) {					\
12356d53eaeSJonas Gorski 		if (!irq_mask_addr[cpu])				\
12456d53eaeSJonas Gorski 			break;						\
12556d53eaeSJonas Gorski 									\
12656d53eaeSJonas Gorski 		val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
12786ee4333SJonas Gorski 		val &= ~(1 << bit);					\
12856d53eaeSJonas Gorski 		bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
12956d53eaeSJonas Gorski 	}								\
13074b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&ipic_lock, flags);			\
13186ee4333SJonas Gorski }									\
13286ee4333SJonas Gorski 									\
133b37f0f69SJonas Gorski static void __internal_irq_unmask_##width(struct irq_data *d,		\
134b37f0f69SJonas Gorski 					  const struct cpumask *m)	\
13586ee4333SJonas Gorski {									\
13686ee4333SJonas Gorski 	u32 val;							\
137553e25b3SJonas Gorski 	unsigned irq = d->irq - IRQ_INTERNAL_BASE;			\
13886ee4333SJonas Gorski 	unsigned reg = (irq / 32) ^ (width/32 - 1);			\
13986ee4333SJonas Gorski 	unsigned bit = irq & 0x1f;					\
14074b8ca3fSJonas Gorski 	unsigned long flags;						\
14156d53eaeSJonas Gorski 	int cpu;							\
14286ee4333SJonas Gorski 									\
14374b8ca3fSJonas Gorski 	spin_lock_irqsave(&ipic_lock, flags);				\
14456d53eaeSJonas Gorski 	for_each_present_cpu(cpu) {					\
14556d53eaeSJonas Gorski 		if (!irq_mask_addr[cpu])				\
14656d53eaeSJonas Gorski 			break;						\
14756d53eaeSJonas Gorski 									\
14856d53eaeSJonas Gorski 		val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
149b37f0f69SJonas Gorski 		if (enable_irq_for_cpu(cpu, d, m))			\
15086ee4333SJonas Gorski 			val |= (1 << bit);				\
15156d53eaeSJonas Gorski 		else							\
15256d53eaeSJonas Gorski 			val &= ~(1 << bit);				\
15356d53eaeSJonas Gorski 		bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
15456d53eaeSJonas Gorski 	}								\
15574b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&ipic_lock, flags);			\
156e7300d04SMaxime Bizon }
157e7300d04SMaxime Bizon 
15886ee4333SJonas Gorski BUILD_IPIC_INTERNAL(32);
15986ee4333SJonas Gorski BUILD_IPIC_INTERNAL(64);
16071a43927SMaxime Bizon 
plat_irq_dispatch(void)161e7300d04SMaxime Bizon asmlinkage void plat_irq_dispatch(void)
162e7300d04SMaxime Bizon {
163e7300d04SMaxime Bizon 	u32 cause;
164e7300d04SMaxime Bizon 
165e7300d04SMaxime Bizon 	do {
166e7300d04SMaxime Bizon 		cause = read_c0_cause() & read_c0_status() & ST0_IM;
167e7300d04SMaxime Bizon 
168e7300d04SMaxime Bizon 		if (!cause)
169e7300d04SMaxime Bizon 			break;
170e7300d04SMaxime Bizon 
171e7300d04SMaxime Bizon 		if (cause & CAUSEF_IP7)
172e7300d04SMaxime Bizon 			do_IRQ(7);
173937ad104SKevin Cernekee 		if (cause & CAUSEF_IP0)
174937ad104SKevin Cernekee 			do_IRQ(0);
175937ad104SKevin Cernekee 		if (cause & CAUSEF_IP1)
176937ad104SKevin Cernekee 			do_IRQ(1);
177e7300d04SMaxime Bizon 		if (cause & CAUSEF_IP2)
1787a9fd14dSJonas Gorski 			dispatch_internal(0);
17956d53eaeSJonas Gorski 		if (is_ext_irq_cascaded) {
18056d53eaeSJonas Gorski 			if (cause & CAUSEF_IP3)
18156d53eaeSJonas Gorski 				dispatch_internal(1);
18256d53eaeSJonas Gorski 		} else {
183e7300d04SMaxime Bizon 			if (cause & CAUSEF_IP3)
184e7300d04SMaxime Bizon 				do_IRQ(IRQ_EXT_0);
185e7300d04SMaxime Bizon 			if (cause & CAUSEF_IP4)
186e7300d04SMaxime Bizon 				do_IRQ(IRQ_EXT_1);
187e7300d04SMaxime Bizon 			if (cause & CAUSEF_IP5)
188e7300d04SMaxime Bizon 				do_IRQ(IRQ_EXT_2);
189e7300d04SMaxime Bizon 			if (cause & CAUSEF_IP6)
190e7300d04SMaxime Bizon 				do_IRQ(IRQ_EXT_3);
19137c42a74SMaxime Bizon 		}
192e7300d04SMaxime Bizon 	} while (1);
193e7300d04SMaxime Bizon }
194e7300d04SMaxime Bizon 
195e7300d04SMaxime Bizon /*
196e7300d04SMaxime Bizon  * internal IRQs operations: only mask/unmask on PERF irq mask
197e7300d04SMaxime Bizon  * register.
198e7300d04SMaxime Bizon  */
bcm63xx_internal_irq_mask(struct irq_data * d)19937c42a74SMaxime Bizon static void bcm63xx_internal_irq_mask(struct irq_data *d)
20037c42a74SMaxime Bizon {
201553e25b3SJonas Gorski 	internal_irq_mask(d);
20237c42a74SMaxime Bizon }
20337c42a74SMaxime Bizon 
bcm63xx_internal_irq_unmask(struct irq_data * d)20437c42a74SMaxime Bizon static void bcm63xx_internal_irq_unmask(struct irq_data *d)
20537c42a74SMaxime Bizon {
206b37f0f69SJonas Gorski 	internal_irq_unmask(d, NULL);
20737c42a74SMaxime Bizon }
20837c42a74SMaxime Bizon 
209e7300d04SMaxime Bizon /*
210e7300d04SMaxime Bizon  * external IRQs operations: mask/unmask and clear on PERF external
211e7300d04SMaxime Bizon  * irq control register.
212e7300d04SMaxime Bizon  */
bcm63xx_external_irq_mask(struct irq_data * d)21393f29361SThomas Gleixner static void bcm63xx_external_irq_mask(struct irq_data *d)
214e7300d04SMaxime Bizon {
21537c42a74SMaxime Bizon 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
2166224892cSMaxime Bizon 	u32 reg, regaddr;
21774b8ca3fSJonas Gorski 	unsigned long flags;
218e7300d04SMaxime Bizon 
2196224892cSMaxime Bizon 	regaddr = get_ext_irq_perf_reg(irq);
22074b8ca3fSJonas Gorski 	spin_lock_irqsave(&epic_lock, flags);
2216224892cSMaxime Bizon 	reg = bcm_perf_readl(regaddr);
2226224892cSMaxime Bizon 
2236224892cSMaxime Bizon 	if (BCMCPU_IS_6348())
2246224892cSMaxime Bizon 		reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
2256224892cSMaxime Bizon 	else
2266224892cSMaxime Bizon 		reg &= ~EXTIRQ_CFG_MASK(irq % 4);
2276224892cSMaxime Bizon 
2286224892cSMaxime Bizon 	bcm_perf_writel(reg, regaddr);
22974b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&epic_lock, flags);
23074b8ca3fSJonas Gorski 
23137c42a74SMaxime Bizon 	if (is_ext_irq_cascaded)
232553e25b3SJonas Gorski 		internal_irq_mask(irq_get_irq_data(irq + ext_irq_start));
233e7300d04SMaxime Bizon }
234e7300d04SMaxime Bizon 
bcm63xx_external_irq_unmask(struct irq_data * d)23593f29361SThomas Gleixner static void bcm63xx_external_irq_unmask(struct irq_data *d)
236e7300d04SMaxime Bizon {
23737c42a74SMaxime Bizon 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
2386224892cSMaxime Bizon 	u32 reg, regaddr;
23974b8ca3fSJonas Gorski 	unsigned long flags;
240e7300d04SMaxime Bizon 
2416224892cSMaxime Bizon 	regaddr = get_ext_irq_perf_reg(irq);
24274b8ca3fSJonas Gorski 	spin_lock_irqsave(&epic_lock, flags);
2436224892cSMaxime Bizon 	reg = bcm_perf_readl(regaddr);
2446224892cSMaxime Bizon 
2456224892cSMaxime Bizon 	if (BCMCPU_IS_6348())
2466224892cSMaxime Bizon 		reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
2476224892cSMaxime Bizon 	else
2486224892cSMaxime Bizon 		reg |= EXTIRQ_CFG_MASK(irq % 4);
2496224892cSMaxime Bizon 
2506224892cSMaxime Bizon 	bcm_perf_writel(reg, regaddr);
25174b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&epic_lock, flags);
2526224892cSMaxime Bizon 
25337c42a74SMaxime Bizon 	if (is_ext_irq_cascaded)
254b37f0f69SJonas Gorski 		internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start),
255b37f0f69SJonas Gorski 				    NULL);
256e7300d04SMaxime Bizon }
257e7300d04SMaxime Bizon 
bcm63xx_external_irq_clear(struct irq_data * d)25893f29361SThomas Gleixner static void bcm63xx_external_irq_clear(struct irq_data *d)
259e7300d04SMaxime Bizon {
26037c42a74SMaxime Bizon 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
2616224892cSMaxime Bizon 	u32 reg, regaddr;
26274b8ca3fSJonas Gorski 	unsigned long flags;
263e7300d04SMaxime Bizon 
2646224892cSMaxime Bizon 	regaddr = get_ext_irq_perf_reg(irq);
26574b8ca3fSJonas Gorski 	spin_lock_irqsave(&epic_lock, flags);
2666224892cSMaxime Bizon 	reg = bcm_perf_readl(regaddr);
2676224892cSMaxime Bizon 
2686224892cSMaxime Bizon 	if (BCMCPU_IS_6348())
2696224892cSMaxime Bizon 		reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
2706224892cSMaxime Bizon 	else
2716224892cSMaxime Bizon 		reg |= EXTIRQ_CFG_CLEAR(irq % 4);
2726224892cSMaxime Bizon 
2736224892cSMaxime Bizon 	bcm_perf_writel(reg, regaddr);
27474b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&epic_lock, flags);
275e7300d04SMaxime Bizon }
276e7300d04SMaxime Bizon 
bcm63xx_external_irq_set_type(struct irq_data * d,unsigned int flow_type)27793f29361SThomas Gleixner static int bcm63xx_external_irq_set_type(struct irq_data *d,
278e7300d04SMaxime Bizon 					 unsigned int flow_type)
279e7300d04SMaxime Bizon {
28037c42a74SMaxime Bizon 	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
2816224892cSMaxime Bizon 	u32 reg, regaddr;
2826224892cSMaxime Bizon 	int levelsense, sense, bothedge;
28374b8ca3fSJonas Gorski 	unsigned long flags;
284e7300d04SMaxime Bizon 
285e7300d04SMaxime Bizon 	flow_type &= IRQ_TYPE_SENSE_MASK;
286e7300d04SMaxime Bizon 
287e7300d04SMaxime Bizon 	if (flow_type == IRQ_TYPE_NONE)
288e7300d04SMaxime Bizon 		flow_type = IRQ_TYPE_LEVEL_LOW;
289e7300d04SMaxime Bizon 
2906224892cSMaxime Bizon 	levelsense = sense = bothedge = 0;
291e7300d04SMaxime Bizon 	switch (flow_type) {
292e7300d04SMaxime Bizon 	case IRQ_TYPE_EDGE_BOTH:
2936224892cSMaxime Bizon 		bothedge = 1;
294e7300d04SMaxime Bizon 		break;
295e7300d04SMaxime Bizon 
296e7300d04SMaxime Bizon 	case IRQ_TYPE_EDGE_RISING:
2976224892cSMaxime Bizon 		sense = 1;
298e7300d04SMaxime Bizon 		break;
299e7300d04SMaxime Bizon 
300e7300d04SMaxime Bizon 	case IRQ_TYPE_EDGE_FALLING:
301e7300d04SMaxime Bizon 		break;
302e7300d04SMaxime Bizon 
303e7300d04SMaxime Bizon 	case IRQ_TYPE_LEVEL_HIGH:
3046224892cSMaxime Bizon 		levelsense = 1;
3056224892cSMaxime Bizon 		sense = 1;
306e7300d04SMaxime Bizon 		break;
307e7300d04SMaxime Bizon 
308e7300d04SMaxime Bizon 	case IRQ_TYPE_LEVEL_LOW:
3096224892cSMaxime Bizon 		levelsense = 1;
310e7300d04SMaxime Bizon 		break;
311e7300d04SMaxime Bizon 
312e7300d04SMaxime Bizon 	default:
31363893ea5SGregory Fong 		pr_err("bogus flow type combination given !\n");
314e7300d04SMaxime Bizon 		return -EINVAL;
315e7300d04SMaxime Bizon 	}
3166224892cSMaxime Bizon 
3176224892cSMaxime Bizon 	regaddr = get_ext_irq_perf_reg(irq);
31874b8ca3fSJonas Gorski 	spin_lock_irqsave(&epic_lock, flags);
3196224892cSMaxime Bizon 	reg = bcm_perf_readl(regaddr);
3206224892cSMaxime Bizon 	irq %= 4;
3216224892cSMaxime Bizon 
32258e380afSMaxime Bizon 	switch (bcm63xx_get_cpu_id()) {
32358e380afSMaxime Bizon 	case BCM6348_CPU_ID:
3246224892cSMaxime Bizon 		if (levelsense)
3256224892cSMaxime Bizon 			reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
3266224892cSMaxime Bizon 		else
3276224892cSMaxime Bizon 			reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
3286224892cSMaxime Bizon 		if (sense)
3296224892cSMaxime Bizon 			reg |= EXTIRQ_CFG_SENSE_6348(irq);
3306224892cSMaxime Bizon 		else
3316224892cSMaxime Bizon 			reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
3326224892cSMaxime Bizon 		if (bothedge)
3336224892cSMaxime Bizon 			reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
3346224892cSMaxime Bizon 		else
3356224892cSMaxime Bizon 			reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
33658e380afSMaxime Bizon 		break;
3376224892cSMaxime Bizon 
3387b933421SFlorian Fainelli 	case BCM3368_CPU_ID:
33958e380afSMaxime Bizon 	case BCM6328_CPU_ID:
34058e380afSMaxime Bizon 	case BCM6338_CPU_ID:
34158e380afSMaxime Bizon 	case BCM6345_CPU_ID:
34258e380afSMaxime Bizon 	case BCM6358_CPU_ID:
3432c8aaf71SJonas Gorski 	case BCM6362_CPU_ID:
34458e380afSMaxime Bizon 	case BCM6368_CPU_ID:
3456224892cSMaxime Bizon 		if (levelsense)
3466224892cSMaxime Bizon 			reg |= EXTIRQ_CFG_LEVELSENSE(irq);
3476224892cSMaxime Bizon 		else
3486224892cSMaxime Bizon 			reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
3496224892cSMaxime Bizon 		if (sense)
3506224892cSMaxime Bizon 			reg |= EXTIRQ_CFG_SENSE(irq);
3516224892cSMaxime Bizon 		else
3526224892cSMaxime Bizon 			reg &= ~EXTIRQ_CFG_SENSE(irq);
3536224892cSMaxime Bizon 		if (bothedge)
3546224892cSMaxime Bizon 			reg |= EXTIRQ_CFG_BOTHEDGE(irq);
3556224892cSMaxime Bizon 		else
3566224892cSMaxime Bizon 			reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
35758e380afSMaxime Bizon 		break;
35858e380afSMaxime Bizon 	default:
35958e380afSMaxime Bizon 		BUG();
3606224892cSMaxime Bizon 	}
3616224892cSMaxime Bizon 
3626224892cSMaxime Bizon 	bcm_perf_writel(reg, regaddr);
36374b8ca3fSJonas Gorski 	spin_unlock_irqrestore(&epic_lock, flags);
364e7300d04SMaxime Bizon 
36593f29361SThomas Gleixner 	irqd_set_trigger_type(d, flow_type);
36693f29361SThomas Gleixner 	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
3679154566eSThomas Gleixner 		irq_set_handler_locked(d, handle_level_irq);
36893f29361SThomas Gleixner 	else
3699154566eSThomas Gleixner 		irq_set_handler_locked(d, handle_edge_irq);
370e7300d04SMaxime Bizon 
37193f29361SThomas Gleixner 	return IRQ_SET_MASK_OK_NOCOPY;
372e7300d04SMaxime Bizon }
373e7300d04SMaxime Bizon 
374b37f0f69SJonas Gorski #ifdef CONFIG_SMP
bcm63xx_internal_set_affinity(struct irq_data * data,const struct cpumask * dest,bool force)375b37f0f69SJonas Gorski static int bcm63xx_internal_set_affinity(struct irq_data *data,
376b37f0f69SJonas Gorski 					 const struct cpumask *dest,
377b37f0f69SJonas Gorski 					 bool force)
378b37f0f69SJonas Gorski {
379b37f0f69SJonas Gorski 	if (!irqd_irq_disabled(data))
380b37f0f69SJonas Gorski 		internal_irq_unmask(data, dest);
381b37f0f69SJonas Gorski 
382b37f0f69SJonas Gorski 	return 0;
383b37f0f69SJonas Gorski }
384b37f0f69SJonas Gorski #endif
385b37f0f69SJonas Gorski 
386e7300d04SMaxime Bizon static struct irq_chip bcm63xx_internal_irq_chip = {
387e7300d04SMaxime Bizon 	.name		= "bcm63xx_ipic",
38893f29361SThomas Gleixner 	.irq_mask	= bcm63xx_internal_irq_mask,
38993f29361SThomas Gleixner 	.irq_unmask	= bcm63xx_internal_irq_unmask,
390e7300d04SMaxime Bizon };
391e7300d04SMaxime Bizon 
392e7300d04SMaxime Bizon static struct irq_chip bcm63xx_external_irq_chip = {
393e7300d04SMaxime Bizon 	.name		= "bcm63xx_epic",
39493f29361SThomas Gleixner 	.irq_ack	= bcm63xx_external_irq_clear,
395e7300d04SMaxime Bizon 
39693f29361SThomas Gleixner 	.irq_mask	= bcm63xx_external_irq_mask,
39793f29361SThomas Gleixner 	.irq_unmask	= bcm63xx_external_irq_unmask,
398e7300d04SMaxime Bizon 
39993f29361SThomas Gleixner 	.irq_set_type	= bcm63xx_external_irq_set_type,
400e7300d04SMaxime Bizon };
401e7300d04SMaxime Bizon 
bcm63xx_init_irq(void)402a6dfde81SJonas Gorski static void bcm63xx_init_irq(void)
403a6dfde81SJonas Gorski {
404a6dfde81SJonas Gorski 	int irq_bits;
405a6dfde81SJonas Gorski 
406cc81d7f3SJonas Gorski 	irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
407cc81d7f3SJonas Gorski 	irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
4083534b5ceSJonas Gorski 	irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
4093534b5ceSJonas Gorski 	irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
410a6dfde81SJonas Gorski 
411a6dfde81SJonas Gorski 	switch (bcm63xx_get_cpu_id()) {
412a6dfde81SJonas Gorski 	case BCM3368_CPU_ID:
413cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
414cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
4153534b5ceSJonas Gorski 		irq_stat_addr[1] = 0;
416bbc5367fSJulia Lawall 		irq_mask_addr[1] = 0;
417a6dfde81SJonas Gorski 		irq_bits = 32;
418a6dfde81SJonas Gorski 		ext_irq_count = 4;
419a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
420a6dfde81SJonas Gorski 		break;
421a6dfde81SJonas Gorski 	case BCM6328_CPU_ID:
422cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
423cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
4243534b5ceSJonas Gorski 		irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
425bbc5367fSJulia Lawall 		irq_mask_addr[1] += PERF_IRQMASK_6328_REG(1);
426a6dfde81SJonas Gorski 		irq_bits = 64;
427a6dfde81SJonas Gorski 		ext_irq_count = 4;
428a6dfde81SJonas Gorski 		is_ext_irq_cascaded = 1;
429a6dfde81SJonas Gorski 		ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
430a6dfde81SJonas Gorski 		ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
431a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
432a6dfde81SJonas Gorski 		break;
433a6dfde81SJonas Gorski 	case BCM6338_CPU_ID:
434cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
435cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
4363534b5ceSJonas Gorski 		irq_stat_addr[1] = 0;
4373534b5ceSJonas Gorski 		irq_mask_addr[1] = 0;
438a6dfde81SJonas Gorski 		irq_bits = 32;
439a6dfde81SJonas Gorski 		ext_irq_count = 4;
440a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
441a6dfde81SJonas Gorski 		break;
442a6dfde81SJonas Gorski 	case BCM6345_CPU_ID:
443cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
444cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
4453534b5ceSJonas Gorski 		irq_stat_addr[1] = 0;
4463534b5ceSJonas Gorski 		irq_mask_addr[1] = 0;
447a6dfde81SJonas Gorski 		irq_bits = 32;
448a6dfde81SJonas Gorski 		ext_irq_count = 4;
449a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
450a6dfde81SJonas Gorski 		break;
451a6dfde81SJonas Gorski 	case BCM6348_CPU_ID:
452cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
453cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
4543534b5ceSJonas Gorski 		irq_stat_addr[1] = 0;
4553534b5ceSJonas Gorski 		irq_mask_addr[1] = 0;
456a6dfde81SJonas Gorski 		irq_bits = 32;
457a6dfde81SJonas Gorski 		ext_irq_count = 4;
458a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
459a6dfde81SJonas Gorski 		break;
460a6dfde81SJonas Gorski 	case BCM6358_CPU_ID:
461cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
462cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
4633534b5ceSJonas Gorski 		irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
4643534b5ceSJonas Gorski 		irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
465a6dfde81SJonas Gorski 		irq_bits = 32;
466a6dfde81SJonas Gorski 		ext_irq_count = 4;
467a6dfde81SJonas Gorski 		is_ext_irq_cascaded = 1;
468a6dfde81SJonas Gorski 		ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
469a6dfde81SJonas Gorski 		ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
470a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
471a6dfde81SJonas Gorski 		break;
472a6dfde81SJonas Gorski 	case BCM6362_CPU_ID:
473cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
474cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
4753534b5ceSJonas Gorski 		irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
4763534b5ceSJonas Gorski 		irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
477a6dfde81SJonas Gorski 		irq_bits = 64;
478a6dfde81SJonas Gorski 		ext_irq_count = 4;
479a6dfde81SJonas Gorski 		is_ext_irq_cascaded = 1;
480a6dfde81SJonas Gorski 		ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
481a6dfde81SJonas Gorski 		ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
482a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
483a6dfde81SJonas Gorski 		break;
484a6dfde81SJonas Gorski 	case BCM6368_CPU_ID:
485cc81d7f3SJonas Gorski 		irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
486cc81d7f3SJonas Gorski 		irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
4873534b5ceSJonas Gorski 		irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
4883534b5ceSJonas Gorski 		irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
489a6dfde81SJonas Gorski 		irq_bits = 64;
490a6dfde81SJonas Gorski 		ext_irq_count = 6;
491a6dfde81SJonas Gorski 		is_ext_irq_cascaded = 1;
492a6dfde81SJonas Gorski 		ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
493a6dfde81SJonas Gorski 		ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
494a6dfde81SJonas Gorski 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
495a6dfde81SJonas Gorski 		ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
496a6dfde81SJonas Gorski 		break;
497a6dfde81SJonas Gorski 	default:
498a6dfde81SJonas Gorski 		BUG();
499a6dfde81SJonas Gorski 	}
500a6dfde81SJonas Gorski 
501a6dfde81SJonas Gorski 	if (irq_bits == 32) {
502a6dfde81SJonas Gorski 		dispatch_internal = __dispatch_internal_32;
503a6dfde81SJonas Gorski 		internal_irq_mask = __internal_irq_mask_32;
504a6dfde81SJonas Gorski 		internal_irq_unmask = __internal_irq_unmask_32;
505a6dfde81SJonas Gorski 	} else {
506a6dfde81SJonas Gorski 		dispatch_internal = __dispatch_internal_64;
507a6dfde81SJonas Gorski 		internal_irq_mask = __internal_irq_mask_64;
508a6dfde81SJonas Gorski 		internal_irq_unmask = __internal_irq_unmask_64;
509a6dfde81SJonas Gorski 	}
510a6dfde81SJonas Gorski }
511a6dfde81SJonas Gorski 
arch_init_irq(void)512e7300d04SMaxime Bizon void __init arch_init_irq(void)
513e7300d04SMaxime Bizon {
514*ac8fd122Safzal mohammed 	int i, irq;
515e7300d04SMaxime Bizon 
516f61cced9SMaxime Bizon 	bcm63xx_init_irq();
517e7300d04SMaxime Bizon 	mips_cpu_irq_init();
518e7300d04SMaxime Bizon 	for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
519e4ec7989SThomas Gleixner 		irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
520e7300d04SMaxime Bizon 					 handle_level_irq);
521e7300d04SMaxime Bizon 
5226224892cSMaxime Bizon 	for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
523e4ec7989SThomas Gleixner 		irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
524e7300d04SMaxime Bizon 					 handle_edge_irq);
525e7300d04SMaxime Bizon 
52637c42a74SMaxime Bizon 	if (!is_ext_irq_cascaded) {
527*ac8fd122Safzal mohammed 		for (i = 3; i < 3 + ext_irq_count; ++i) {
528*ac8fd122Safzal mohammed 			irq = MIPS_CPU_IRQ_BASE + i;
529*ac8fd122Safzal mohammed 			if (request_irq(irq, no_action, IRQF_NO_THREAD,
530*ac8fd122Safzal mohammed 					"cascade_extirq", NULL)) {
531*ac8fd122Safzal mohammed 				pr_err("Failed to request irq %d (cascade_extirq)\n",
532*ac8fd122Safzal mohammed 				       irq);
533*ac8fd122Safzal mohammed 			}
534*ac8fd122Safzal mohammed 		}
53537c42a74SMaxime Bizon 	}
53637c42a74SMaxime Bizon 
537*ac8fd122Safzal mohammed 	irq = MIPS_CPU_IRQ_BASE + 2;
538*ac8fd122Safzal mohammed 	if (request_irq(irq, no_action, IRQF_NO_THREAD,	"cascade_ip2", NULL))
539*ac8fd122Safzal mohammed 		pr_err("Failed to request irq %d (cascade_ip2)\n", irq);
54056d53eaeSJonas Gorski #ifdef CONFIG_SMP
541b37f0f69SJonas Gorski 	if (is_ext_irq_cascaded) {
542*ac8fd122Safzal mohammed 		irq = MIPS_CPU_IRQ_BASE + 3;
543*ac8fd122Safzal mohammed 		if (request_irq(irq, no_action,	IRQF_NO_THREAD, "cascade_ip3",
544*ac8fd122Safzal mohammed 				NULL))
545*ac8fd122Safzal mohammed 			pr_err("Failed to request irq %d (cascade_ip3)\n", irq);
546b37f0f69SJonas Gorski 		bcm63xx_internal_irq_chip.irq_set_affinity =
547b37f0f69SJonas Gorski 			bcm63xx_internal_set_affinity;
548b37f0f69SJonas Gorski 
549b37f0f69SJonas Gorski 		cpumask_clear(irq_default_affinity);
550b37f0f69SJonas Gorski 		cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
551b37f0f69SJonas Gorski 	}
55256d53eaeSJonas Gorski #endif
553e7300d04SMaxime Bizon }
554