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