linux/arch/mips/loongson1/common/irq.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
   3 *
   4 * This program is free software; you can redistribute  it and/or modify it
   5 * under  the terms of  the GNU General  Public License as published by the
   6 * Free Software Foundation;  either version 2 of the  License, or (at your
   7 * option) any later version.
   8 */
   9
  10#include <linux/interrupt.h>
  11#include <linux/irq.h>
  12#include <asm/irq_cpu.h>
  13
  14#include <loongson1.h>
  15#include <irq.h>
  16
  17#define LS1X_INTC_REG(n, x) \
  18                ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
  19
  20#define LS1X_INTC_INTISR(n)             LS1X_INTC_REG(n, 0x0)
  21#define LS1X_INTC_INTIEN(n)             LS1X_INTC_REG(n, 0x4)
  22#define LS1X_INTC_INTSET(n)             LS1X_INTC_REG(n, 0x8)
  23#define LS1X_INTC_INTCLR(n)             LS1X_INTC_REG(n, 0xc)
  24#define LS1X_INTC_INTPOL(n)             LS1X_INTC_REG(n, 0x10)
  25#define LS1X_INTC_INTEDGE(n)            LS1X_INTC_REG(n, 0x14)
  26
  27static void ls1x_irq_ack(struct irq_data *d)
  28{
  29        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  30        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  31
  32        __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
  33                        | (1 << bit), LS1X_INTC_INTCLR(n));
  34}
  35
  36static void ls1x_irq_mask(struct irq_data *d)
  37{
  38        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  39        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  40
  41        __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
  42                        & ~(1 << bit), LS1X_INTC_INTIEN(n));
  43}
  44
  45static void ls1x_irq_mask_ack(struct irq_data *d)
  46{
  47        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  48        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  49
  50        __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
  51                        & ~(1 << bit), LS1X_INTC_INTIEN(n));
  52        __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
  53                        | (1 << bit), LS1X_INTC_INTCLR(n));
  54}
  55
  56static void ls1x_irq_unmask(struct irq_data *d)
  57{
  58        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  59        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  60
  61        __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
  62                        | (1 << bit), LS1X_INTC_INTIEN(n));
  63}
  64
  65static struct irq_chip ls1x_irq_chip = {
  66        .name           = "LS1X-INTC",
  67        .irq_ack        = ls1x_irq_ack,
  68        .irq_mask       = ls1x_irq_mask,
  69        .irq_mask_ack   = ls1x_irq_mask_ack,
  70        .irq_unmask     = ls1x_irq_unmask,
  71};
  72
  73static void ls1x_irq_dispatch(int n)
  74{
  75        u32 int_status, irq;
  76
  77        /* Get pending sources, masked by current enables */
  78        int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
  79                        __raw_readl(LS1X_INTC_INTIEN(n));
  80
  81        if (int_status) {
  82                irq = LS1X_IRQ(n, __ffs(int_status));
  83                do_IRQ(irq);
  84        }
  85}
  86
  87asmlinkage void plat_irq_dispatch(void)
  88{
  89        unsigned int pending;
  90
  91        pending = read_c0_cause() & read_c0_status() & ST0_IM;
  92
  93        if (pending & CAUSEF_IP7)
  94                do_IRQ(TIMER_IRQ);
  95        else if (pending & CAUSEF_IP2)
  96                ls1x_irq_dispatch(0); /* INT0 */
  97        else if (pending & CAUSEF_IP3)
  98                ls1x_irq_dispatch(1); /* INT1 */
  99        else if (pending & CAUSEF_IP4)
 100                ls1x_irq_dispatch(2); /* INT2 */
 101        else if (pending & CAUSEF_IP5)
 102                ls1x_irq_dispatch(3); /* INT3 */
 103        else if (pending & CAUSEF_IP6)
 104                ls1x_irq_dispatch(4); /* INT4 */
 105        else
 106                spurious_interrupt();
 107
 108}
 109
 110struct irqaction cascade_irqaction = {
 111        .handler = no_action,
 112        .name = "cascade",
 113        .flags = IRQF_NO_THREAD,
 114};
 115
 116static void __init ls1x_irq_init(int base)
 117{
 118        int n;
 119
 120        /* Disable interrupts and clear pending,
 121         * setup all IRQs as high level triggered
 122         */
 123        for (n = 0; n < 4; n++) {
 124                __raw_writel(0x0, LS1X_INTC_INTIEN(n));
 125                __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
 126                __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
 127                /* set DMA0, DMA1 and DMA2 to edge trigger */
 128                __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
 129        }
 130
 131
 132        for (n = base; n < LS1X_IRQS; n++) {
 133                irq_set_chip_and_handler(n, &ls1x_irq_chip,
 134                                         handle_level_irq);
 135        }
 136
 137        setup_irq(INT0_IRQ, &cascade_irqaction);
 138        setup_irq(INT1_IRQ, &cascade_irqaction);
 139        setup_irq(INT2_IRQ, &cascade_irqaction);
 140        setup_irq(INT3_IRQ, &cascade_irqaction);
 141}
 142
 143void __init arch_init_irq(void)
 144{
 145        mips_cpu_irq_init();
 146        ls1x_irq_init(LS1X_IRQ_BASE);
 147}
 148