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