linux/arch/mips/ath79/irq.c
<<
>>
Prefs
   1/*
   2 *  Atheros AR71xx/AR724x/AR913x specific interrupt handling
   3 *
   4 *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
   5 *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
   6 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
   7 *
   8 *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
   9 *
  10 *  This program is free software; you can redistribute it and/or modify it
  11 *  under the terms of the GNU General Public License version 2 as published
  12 *  by the Free Software Foundation.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/init.h>
  17#include <linux/interrupt.h>
  18#include <linux/irqchip.h>
  19#include <linux/of_irq.h>
  20
  21#include <asm/irq_cpu.h>
  22#include <asm/mipsregs.h>
  23
  24#include <asm/mach-ath79/ath79.h>
  25#include <asm/mach-ath79/ar71xx_regs.h>
  26#include "common.h"
  27#include "machtypes.h"
  28
  29
  30static void ar934x_ip2_irq_dispatch(struct irq_desc *desc)
  31{
  32        u32 status;
  33
  34        status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS);
  35
  36        if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) {
  37                ath79_ddr_wb_flush(3);
  38                generic_handle_irq(ATH79_IP2_IRQ(0));
  39        } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) {
  40                ath79_ddr_wb_flush(4);
  41                generic_handle_irq(ATH79_IP2_IRQ(1));
  42        } else {
  43                spurious_interrupt();
  44        }
  45}
  46
  47static void ar934x_ip2_irq_init(void)
  48{
  49        int i;
  50
  51        for (i = ATH79_IP2_IRQ_BASE;
  52             i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
  53                irq_set_chip_and_handler(i, &dummy_irq_chip,
  54                                         handle_level_irq);
  55
  56        irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch);
  57}
  58
  59static void qca955x_ip2_irq_dispatch(struct irq_desc *desc)
  60{
  61        u32 status;
  62
  63        status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS);
  64        status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL;
  65
  66        if (status == 0) {
  67                spurious_interrupt();
  68                return;
  69        }
  70
  71        if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) {
  72                /* TODO: flush DDR? */
  73                generic_handle_irq(ATH79_IP2_IRQ(0));
  74        }
  75
  76        if (status & QCA955X_EXT_INT_WMAC_ALL) {
  77                /* TODO: flush DDR? */
  78                generic_handle_irq(ATH79_IP2_IRQ(1));
  79        }
  80}
  81
  82static void qca955x_ip3_irq_dispatch(struct irq_desc *desc)
  83{
  84        u32 status;
  85
  86        status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS);
  87        status &= QCA955X_EXT_INT_PCIE_RC2_ALL |
  88                  QCA955X_EXT_INT_USB1 |
  89                  QCA955X_EXT_INT_USB2;
  90
  91        if (status == 0) {
  92                spurious_interrupt();
  93                return;
  94        }
  95
  96        if (status & QCA955X_EXT_INT_USB1) {
  97                /* TODO: flush DDR? */
  98                generic_handle_irq(ATH79_IP3_IRQ(0));
  99        }
 100
 101        if (status & QCA955X_EXT_INT_USB2) {
 102                /* TODO: flush DDR? */
 103                generic_handle_irq(ATH79_IP3_IRQ(1));
 104        }
 105
 106        if (status & QCA955X_EXT_INT_PCIE_RC2_ALL) {
 107                /* TODO: flush DDR? */
 108                generic_handle_irq(ATH79_IP3_IRQ(2));
 109        }
 110}
 111
 112static void qca955x_irq_init(void)
 113{
 114        int i;
 115
 116        for (i = ATH79_IP2_IRQ_BASE;
 117             i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
 118                irq_set_chip_and_handler(i, &dummy_irq_chip,
 119                                         handle_level_irq);
 120
 121        irq_set_chained_handler(ATH79_CPU_IRQ(2), qca955x_ip2_irq_dispatch);
 122
 123        for (i = ATH79_IP3_IRQ_BASE;
 124             i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++)
 125                irq_set_chip_and_handler(i, &dummy_irq_chip,
 126                                         handle_level_irq);
 127
 128        irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
 129}
 130
 131void __init arch_init_irq(void)
 132{
 133        unsigned irq_wb_chan2 = -1;
 134        unsigned irq_wb_chan3 = -1;
 135        bool misc_is_ar71xx;
 136
 137        if (mips_machtype == ATH79_MACH_GENERIC_OF) {
 138                irqchip_init();
 139                return;
 140        }
 141
 142        if (soc_is_ar71xx() || soc_is_ar724x() ||
 143            soc_is_ar913x() || soc_is_ar933x()) {
 144                irq_wb_chan2 = 3;
 145                irq_wb_chan3 = 2;
 146        } else if (soc_is_ar934x()) {
 147                irq_wb_chan3 = 2;
 148        }
 149
 150        ath79_cpu_irq_init(irq_wb_chan2, irq_wb_chan3);
 151
 152        if (soc_is_ar71xx() || soc_is_ar913x())
 153                misc_is_ar71xx = true;
 154        else if (soc_is_ar724x() ||
 155                 soc_is_ar933x() ||
 156                 soc_is_ar934x() ||
 157                 soc_is_qca955x())
 158                misc_is_ar71xx = false;
 159        else
 160                BUG();
 161        ath79_misc_irq_init(
 162                ath79_reset_base + AR71XX_RESET_REG_MISC_INT_STATUS,
 163                ATH79_CPU_IRQ(6), ATH79_MISC_IRQ_BASE, misc_is_ar71xx);
 164
 165        if (soc_is_ar934x())
 166                ar934x_ip2_irq_init();
 167        else if (soc_is_qca955x())
 168                qca955x_irq_init();
 169}
 170