| 1 | |
| 2 | |
| 3 | * Atheros AR71xx/AR724x/AR913x specific interrupt handling
|
| 4 | *
|
| 5 | * Copyright (C) 2015 Alban Bedel <[email protected]>
|
| 6 | * Copyright (C) 2010-2011 Jaiganesh Narayanan <[email protected]>
|
| 7 | * Copyright (C) 2008-2011 Gabor Juhos <[email protected]>
|
| 8 | * Copyright (C) 2008 Imre Kaloz <[email protected]>
|
| 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(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 |
|
| 62 | count = of_count_phandle_with_args(
|
| 63 | node, "qca,ddr-wb-channels", "#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 | node, "qca,ddr-wb-channel-interrupts", i, &irq);
|
| 71 | if (irq >= ARRAY_SIZE(irq_wb_chan))
|
| 72 | continue;
|
| 73 |
|
| 74 | err = of_parse_phandle_with_args(
|
| 75 | node, "qca,ddr-wb-channels",
|
| 76 | "#qca,ddr-wb-channel-cells",
|
| 77 | i, &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);
|