linux/drivers/irqchip/irq-ath79-cpu.c
<<
>>
Prefs
   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
  30static unsigned irq_wb_chan[8] = {
  31        -1, -1, -1, -1, -1, -1, -1, -1,
  32};
  33
  34asmlinkage 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
  56static 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                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}
  86IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
  87                ar79_cpu_intc_of_init);
  88
  89void __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