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/irq.h>
  19
  20#include <asm/irq_cpu.h>
  21#include <asm/mipsregs.h>
  22
  23#include <asm/mach-ath79/ath79.h>
  24#include <asm/mach-ath79/ar71xx_regs.h>
  25#include "common.h"
  26
  27static void (*ath79_ip2_handler)(void);
  28static void (*ath79_ip3_handler)(void);
  29
  30static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
  31{
  32        void __iomem *base = ath79_reset_base;
  33        u32 pending;
  34
  35        pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
  36                  __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  37
  38        if (!pending) {
  39                spurious_interrupt();
  40                return;
  41        }
  42
  43        while (pending) {
  44                int bit = __ffs(pending);
  45
  46                generic_handle_irq(ATH79_MISC_IRQ(bit));
  47                pending &= ~BIT(bit);
  48        }
  49}
  50
  51static void ar71xx_misc_irq_unmask(struct irq_data *d)
  52{
  53        unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
  54        void __iomem *base = ath79_reset_base;
  55        u32 t;
  56
  57        t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  58        __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  59
  60        /* flush write */
  61        __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  62}
  63
  64static void ar71xx_misc_irq_mask(struct irq_data *d)
  65{
  66        unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
  67        void __iomem *base = ath79_reset_base;
  68        u32 t;
  69
  70        t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  71        __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  72
  73        /* flush write */
  74        __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  75}
  76
  77static void ar724x_misc_irq_ack(struct irq_data *d)
  78{
  79        unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
  80        void __iomem *base = ath79_reset_base;
  81        u32 t;
  82
  83        t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
  84        __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
  85
  86        /* flush write */
  87        __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
  88}
  89
  90static struct irq_chip ath79_misc_irq_chip = {
  91        .name           = "MISC",
  92        .irq_unmask     = ar71xx_misc_irq_unmask,
  93        .irq_mask       = ar71xx_misc_irq_mask,
  94};
  95
  96static void __init ath79_misc_irq_init(void)
  97{
  98        void __iomem *base = ath79_reset_base;
  99        int i;
 100
 101        __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 102        __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
 103
 104        if (soc_is_ar71xx() || soc_is_ar913x())
 105                ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
 106        else if (soc_is_ar724x() ||
 107                 soc_is_ar933x() ||
 108                 soc_is_ar934x() ||
 109                 soc_is_qca955x())
 110                ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
 111        else
 112                BUG();
 113
 114        for (i = ATH79_MISC_IRQ_BASE;
 115             i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) {
 116                irq_set_chip_and_handler(i, &ath79_misc_irq_chip,
 117                                         handle_level_irq);
 118        }
 119
 120        irq_set_chained_handler(ATH79_CPU_IRQ(6), ath79_misc_irq_handler);
 121}
 122
 123static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc)
 124{
 125        u32 status;
 126
 127        disable_irq_nosync(irq);
 128
 129        status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS);
 130
 131        if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) {
 132                ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_PCIE);
 133                generic_handle_irq(ATH79_IP2_IRQ(0));
 134        } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) {
 135                ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_WMAC);
 136                generic_handle_irq(ATH79_IP2_IRQ(1));
 137        } else {
 138                spurious_interrupt();
 139        }
 140
 141        enable_irq(irq);
 142}
 143
 144static void ar934x_ip2_irq_init(void)
 145{
 146        int i;
 147
 148        for (i = ATH79_IP2_IRQ_BASE;
 149             i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
 150                irq_set_chip_and_handler(i, &dummy_irq_chip,
 151                                         handle_level_irq);
 152
 153        irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch);
 154}
 155
 156static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc)
 157{
 158        u32 status;
 159
 160        disable_irq_nosync(irq);
 161
 162        status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS);
 163        status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL;
 164
 165        if (status == 0) {
 166                spurious_interrupt();
 167                goto enable;
 168        }
 169
 170        if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) {
 171                /* TODO: flush DDR? */
 172                generic_handle_irq(ATH79_IP2_IRQ(0));
 173        }
 174
 175        if (status & QCA955X_EXT_INT_WMAC_ALL) {
 176                /* TODO: flush DDR? */
 177                generic_handle_irq(ATH79_IP2_IRQ(1));
 178        }
 179
 180enable:
 181        enable_irq(irq);
 182}
 183
 184static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc)
 185{
 186        u32 status;
 187
 188        disable_irq_nosync(irq);
 189
 190        status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS);
 191        status &= QCA955X_EXT_INT_PCIE_RC2_ALL |
 192                  QCA955X_EXT_INT_USB1 |
 193                  QCA955X_EXT_INT_USB2;
 194
 195        if (status == 0) {
 196                spurious_interrupt();
 197                goto enable;
 198        }
 199
 200        if (status & QCA955X_EXT_INT_USB1) {
 201                /* TODO: flush DDR? */
 202                generic_handle_irq(ATH79_IP3_IRQ(0));
 203        }
 204
 205        if (status & QCA955X_EXT_INT_USB2) {
 206                /* TODO: flush DDR? */
 207                generic_handle_irq(ATH79_IP3_IRQ(1));
 208        }
 209
 210        if (status & QCA955X_EXT_INT_PCIE_RC2_ALL) {
 211                /* TODO: flush DDR? */
 212                generic_handle_irq(ATH79_IP3_IRQ(2));
 213        }
 214
 215enable:
 216        enable_irq(irq);
 217}
 218
 219static void qca955x_irq_init(void)
 220{
 221        int i;
 222
 223        for (i = ATH79_IP2_IRQ_BASE;
 224             i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
 225                irq_set_chip_and_handler(i, &dummy_irq_chip,
 226                                         handle_level_irq);
 227
 228        irq_set_chained_handler(ATH79_CPU_IRQ(2), qca955x_ip2_irq_dispatch);
 229
 230        for (i = ATH79_IP3_IRQ_BASE;
 231             i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++)
 232                irq_set_chip_and_handler(i, &dummy_irq_chip,
 233                                         handle_level_irq);
 234
 235        irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
 236}
 237
 238asmlinkage void plat_irq_dispatch(void)
 239{
 240        unsigned long pending;
 241
 242        pending = read_c0_status() & read_c0_cause() & ST0_IM;
 243
 244        if (pending & STATUSF_IP7)
 245                do_IRQ(ATH79_CPU_IRQ(7));
 246
 247        else if (pending & STATUSF_IP2)
 248                ath79_ip2_handler();
 249
 250        else if (pending & STATUSF_IP4)
 251                do_IRQ(ATH79_CPU_IRQ(4));
 252
 253        else if (pending & STATUSF_IP5)
 254                do_IRQ(ATH79_CPU_IRQ(5));
 255
 256        else if (pending & STATUSF_IP3)
 257                ath79_ip3_handler();
 258
 259        else if (pending & STATUSF_IP6)
 260                do_IRQ(ATH79_CPU_IRQ(6));
 261
 262        else
 263                spurious_interrupt();
 264}
 265
 266/*
 267 * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
 268 * these devices typically allocate coherent DMA memory, however the
 269 * DMA controller may still have some unsynchronized data in the FIFO.
 270 * Issue a flush in the handlers to ensure that the driver sees
 271 * the update.
 272 */
 273
 274static void ath79_default_ip2_handler(void)
 275{
 276        do_IRQ(ATH79_CPU_IRQ(2));
 277}
 278
 279static void ath79_default_ip3_handler(void)
 280{
 281        do_IRQ(ATH79_CPU_IRQ(3));
 282}
 283
 284static void ar71xx_ip2_handler(void)
 285{
 286        ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI);
 287        do_IRQ(ATH79_CPU_IRQ(2));
 288}
 289
 290static void ar724x_ip2_handler(void)
 291{
 292        ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE);
 293        do_IRQ(ATH79_CPU_IRQ(2));
 294}
 295
 296static void ar913x_ip2_handler(void)
 297{
 298        ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC);
 299        do_IRQ(ATH79_CPU_IRQ(2));
 300}
 301
 302static void ar933x_ip2_handler(void)
 303{
 304        ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_WMAC);
 305        do_IRQ(ATH79_CPU_IRQ(2));
 306}
 307
 308static void ar71xx_ip3_handler(void)
 309{
 310        ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB);
 311        do_IRQ(ATH79_CPU_IRQ(3));
 312}
 313
 314static void ar724x_ip3_handler(void)
 315{
 316        ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB);
 317        do_IRQ(ATH79_CPU_IRQ(3));
 318}
 319
 320static void ar913x_ip3_handler(void)
 321{
 322        ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB);
 323        do_IRQ(ATH79_CPU_IRQ(3));
 324}
 325
 326static void ar933x_ip3_handler(void)
 327{
 328        ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB);
 329        do_IRQ(ATH79_CPU_IRQ(3));
 330}
 331
 332static void ar934x_ip3_handler(void)
 333{
 334        ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB);
 335        do_IRQ(ATH79_CPU_IRQ(3));
 336}
 337
 338void __init arch_init_irq(void)
 339{
 340        if (soc_is_ar71xx()) {
 341                ath79_ip2_handler = ar71xx_ip2_handler;
 342                ath79_ip3_handler = ar71xx_ip3_handler;
 343        } else if (soc_is_ar724x()) {
 344                ath79_ip2_handler = ar724x_ip2_handler;
 345                ath79_ip3_handler = ar724x_ip3_handler;
 346        } else if (soc_is_ar913x()) {
 347                ath79_ip2_handler = ar913x_ip2_handler;
 348                ath79_ip3_handler = ar913x_ip3_handler;
 349        } else if (soc_is_ar933x()) {
 350                ath79_ip2_handler = ar933x_ip2_handler;
 351                ath79_ip3_handler = ar933x_ip3_handler;
 352        } else if (soc_is_ar934x()) {
 353                ath79_ip2_handler = ath79_default_ip2_handler;
 354                ath79_ip3_handler = ar934x_ip3_handler;
 355        } else if (soc_is_qca955x()) {
 356                ath79_ip2_handler = ath79_default_ip2_handler;
 357                ath79_ip3_handler = ath79_default_ip3_handler;
 358        } else {
 359                BUG();
 360        }
 361
 362        cp0_perfcount_irq = ATH79_MISC_IRQ(5);
 363        mips_cpu_irq_init();
 364        ath79_misc_irq_init();
 365
 366        if (soc_is_ar934x())
 367                ar934x_ip2_irq_init();
 368        else if (soc_is_qca955x())
 369                qca955x_irq_init();
 370}
 371