18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Atheros AR71xx/AR724x/AR913x specific interrupt handling
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2015 Alban Bedel <albeu@free.fr>
68c2ecf20Sopenharmony_ci *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
78c2ecf20Sopenharmony_ci *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
88c2ecf20Sopenharmony_ci *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/irqchip.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/irq_cpu.h>
188c2ecf20Sopenharmony_ci#include <asm/mach-ath79/ath79.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
228c2ecf20Sopenharmony_ci * these devices typically allocate coherent DMA memory, however the
238c2ecf20Sopenharmony_ci * DMA controller may still have some unsynchronized data in the FIFO.
248c2ecf20Sopenharmony_ci * Issue a flush in the handlers to ensure that the driver sees
258c2ecf20Sopenharmony_ci * the update.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * This array map the interrupt lines to the DDR write buffer channels.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic unsigned irq_wb_chan[8] = {
318c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciasmlinkage void plat_irq_dispatch(void)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	unsigned long pending;
378c2ecf20Sopenharmony_ci	int irq;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	pending = read_c0_status() & read_c0_cause() & ST0_IM;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (!pending) {
428c2ecf20Sopenharmony_ci		spurious_interrupt();
438c2ecf20Sopenharmony_ci		return;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	pending >>= CAUSEB_IP;
478c2ecf20Sopenharmony_ci	while (pending) {
488c2ecf20Sopenharmony_ci		irq = fls(pending) - 1;
498c2ecf20Sopenharmony_ci		if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1)
508c2ecf20Sopenharmony_ci			ath79_ddr_wb_flush(irq_wb_chan[irq]);
518c2ecf20Sopenharmony_ci		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
528c2ecf20Sopenharmony_ci		pending &= ~BIT(irq);
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int __init ar79_cpu_intc_of_init(
578c2ecf20Sopenharmony_ci	struct device_node *node, struct device_node *parent)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	int err, i, count;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* Fill the irq_wb_chan table */
628c2ecf20Sopenharmony_ci	count = of_count_phandle_with_args(
638c2ecf20Sopenharmony_ci		node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
668c2ecf20Sopenharmony_ci		struct of_phandle_args args;
678c2ecf20Sopenharmony_ci		u32 irq = i;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		of_property_read_u32_index(
708c2ecf20Sopenharmony_ci			node, "qca,ddr-wb-channel-interrupts", i, &irq);
718c2ecf20Sopenharmony_ci		if (irq >= ARRAY_SIZE(irq_wb_chan))
728c2ecf20Sopenharmony_ci			continue;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		err = of_parse_phandle_with_args(
758c2ecf20Sopenharmony_ci			node, "qca,ddr-wb-channels",
768c2ecf20Sopenharmony_ci			"#qca,ddr-wb-channel-cells",
778c2ecf20Sopenharmony_ci			i, &args);
788c2ecf20Sopenharmony_ci		if (err)
798c2ecf20Sopenharmony_ci			return err;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci		irq_wb_chan[irq] = args.args[0];
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return mips_cpu_irq_of_init(node, parent);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ciIRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
878c2ecf20Sopenharmony_ci		ar79_cpu_intc_of_init);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_civoid __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	irq_wb_chan[2] = irq_wb_chan2;
928c2ecf20Sopenharmony_ci	irq_wb_chan[3] = irq_wb_chan3;
938c2ecf20Sopenharmony_ci	mips_cpu_irq_init();
948c2ecf20Sopenharmony_ci}
95