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