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