1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Atheros AR71xx/AR724x/AR913x specific interrupt handling |
4 | * |
5 | * Copyright (C) 2015 Alban Bedel <albeu@free.fr> |
6 | * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> |
7 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> |
8 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> |
9 | * |
10 | * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP |
11 | */ |
12 | |
13 | #include <linux/interrupt.h> |
14 | #include <linux/irqchip.h> |
15 | #include <linux/of.h> |
16 | |
17 | #include <asm/irq_cpu.h> |
18 | #include <asm/mach-ath79/ath79.h> |
19 | |
20 | /* |
21 | * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for |
22 | * these devices typically allocate coherent DMA memory, however the |
23 | * DMA controller may still have some unsynchronized data in the FIFO. |
24 | * Issue a flush in the handlers to ensure that the driver sees |
25 | * the update. |
26 | * |
27 | * This array map the interrupt lines to the DDR write buffer channels. |
28 | */ |
29 | |
30 | static unsigned irq_wb_chan[8] = { |
31 | -1, -1, -1, -1, -1, -1, -1, -1, |
32 | }; |
33 | |
34 | asmlinkage void plat_irq_dispatch(void) |
35 | { |
36 | unsigned long pending; |
37 | int irq; |
38 | |
39 | pending = read_c0_status() & read_c0_cause() & ST0_IM; |
40 | |
41 | if (!pending) { |
42 | spurious_interrupt(); |
43 | return; |
44 | } |
45 | |
46 | pending >>= CAUSEB_IP; |
47 | while (pending) { |
48 | irq = fls(x: pending) - 1; |
49 | if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1) |
50 | ath79_ddr_wb_flush(irq_wb_chan[irq]); |
51 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); |
52 | pending &= ~BIT(irq); |
53 | } |
54 | } |
55 | |
56 | static int __init ar79_cpu_intc_of_init( |
57 | struct device_node *node, struct device_node *parent) |
58 | { |
59 | int err, i, count; |
60 | |
61 | /* Fill the irq_wb_chan table */ |
62 | count = of_count_phandle_with_args( |
63 | np: node, list_name: "qca,ddr-wb-channels" , cells_name: "#qca,ddr-wb-channel-cells" ); |
64 | |
65 | for (i = 0; i < count; i++) { |
66 | struct of_phandle_args args; |
67 | u32 irq = i; |
68 | |
69 | of_property_read_u32_index( |
70 | np: node, propname: "qca,ddr-wb-channel-interrupts" , index: i, out_value: &irq); |
71 | if (irq >= ARRAY_SIZE(irq_wb_chan)) |
72 | continue; |
73 | |
74 | err = of_parse_phandle_with_args( |
75 | np: node, list_name: "qca,ddr-wb-channels" , |
76 | cells_name: "#qca,ddr-wb-channel-cells" , |
77 | index: i, out_args: &args); |
78 | if (err) |
79 | return err; |
80 | |
81 | irq_wb_chan[irq] = args.args[0]; |
82 | } |
83 | |
84 | return mips_cpu_irq_of_init(node, parent); |
85 | } |
86 | IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc" , |
87 | ar79_cpu_intc_of_init); |
88 | |
89 | void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) |
90 | { |
91 | irq_wb_chan[2] = irq_wb_chan2; |
92 | irq_wb_chan[3] = irq_wb_chan3; |
93 | mips_cpu_irq_init(); |
94 | } |
95 | |