linux/arch/mips/loongson32/common/irq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
   4 */
   5
   6#include <linux/interrupt.h>
   7#include <linux/irq.h>
   8#include <asm/irq_cpu.h>
   9
  10#include <loongson1.h>
  11#include <irq.h>
  12
  13#define LS1X_INTC_REG(n, x) \
  14                ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
  15
  16#define LS1X_INTC_INTISR(n)             LS1X_INTC_REG(n, 0x0)
  17#define LS1X_INTC_INTIEN(n)             LS1X_INTC_REG(n, 0x4)
  18#define LS1X_INTC_INTSET(n)             LS1X_INTC_REG(n, 0x8)
  19#define LS1X_INTC_INTCLR(n)             LS1X_INTC_REG(n, 0xc)
  20#define LS1X_INTC_INTPOL(n)             LS1X_INTC_REG(n, 0x10)
  21#define LS1X_INTC_INTEDGE(n)            LS1X_INTC_REG(n, 0x14)
  22
  23static void ls1x_irq_ack(struct irq_data *d)
  24{
  25        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  26        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  27
  28        __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
  29                        | (1 << bit), LS1X_INTC_INTCLR(n));
  30}
  31
  32static void ls1x_irq_mask(struct irq_data *d)
  33{
  34        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  35        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  36
  37        __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
  38                        & ~(1 << bit), LS1X_INTC_INTIEN(n));
  39}
  40
  41static void ls1x_irq_mask_ack(struct irq_data *d)
  42{
  43        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  44        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  45
  46        __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
  47                        & ~(1 << bit), LS1X_INTC_INTIEN(n));
  48        __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
  49                        | (1 << bit), LS1X_INTC_INTCLR(n));
  50}
  51
  52static void ls1x_irq_unmask(struct irq_data *d)
  53{
  54        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  55        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  56
  57        __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
  58                        | (1 << bit), LS1X_INTC_INTIEN(n));
  59}
  60
  61static int ls1x_irq_settype(struct irq_data *d, unsigned int type)
  62{
  63        unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
  64        unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
  65
  66        switch (type) {
  67        case IRQ_TYPE_LEVEL_HIGH:
  68                __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
  69                        | (1 << bit), LS1X_INTC_INTPOL(n));
  70                __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
  71                        & ~(1 << bit), LS1X_INTC_INTEDGE(n));
  72                break;
  73        case IRQ_TYPE_LEVEL_LOW:
  74                __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
  75                        & ~(1 << bit), LS1X_INTC_INTPOL(n));
  76                __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
  77                        & ~(1 << bit), LS1X_INTC_INTEDGE(n));
  78                break;
  79        case IRQ_TYPE_EDGE_RISING:
  80                __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
  81                        | (1 << bit), LS1X_INTC_INTPOL(n));
  82                __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
  83                        | (1 << bit), LS1X_INTC_INTEDGE(n));
  84                break;
  85        case IRQ_TYPE_EDGE_FALLING:
  86                __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
  87                        & ~(1 << bit), LS1X_INTC_INTPOL(n));
  88                __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
  89                        | (1 << bit), LS1X_INTC_INTEDGE(n));
  90                break;
  91        case IRQ_TYPE_EDGE_BOTH:
  92                __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
  93                        & ~(1 << bit), LS1X_INTC_INTPOL(n));
  94                __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
  95                        | (1 << bit), LS1X_INTC_INTEDGE(n));
  96                break;
  97        case IRQ_TYPE_NONE:
  98                break;
  99        default:
 100                return -EINVAL;
 101        }
 102
 103        return 0;
 104}
 105
 106static struct irq_chip ls1x_irq_chip = {
 107        .name           = "LS1X-INTC",
 108        .irq_ack        = ls1x_irq_ack,
 109        .irq_mask       = ls1x_irq_mask,
 110        .irq_mask_ack   = ls1x_irq_mask_ack,
 111        .irq_unmask     = ls1x_irq_unmask,
 112        .irq_set_type   = ls1x_irq_settype,
 113};
 114
 115static void ls1x_irq_dispatch(int n)
 116{
 117        u32 int_status, irq;
 118
 119        /* Get pending sources, masked by current enables */
 120        int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
 121                        __raw_readl(LS1X_INTC_INTIEN(n));
 122
 123        if (int_status) {
 124                irq = LS1X_IRQ(n, __ffs(int_status));
 125                do_IRQ(irq);
 126        }
 127}
 128
 129asmlinkage void plat_irq_dispatch(void)
 130{
 131        unsigned int pending;
 132
 133        pending = read_c0_cause() & read_c0_status() & ST0_IM;
 134
 135        if (pending & CAUSEF_IP7)
 136                do_IRQ(TIMER_IRQ);
 137        else if (pending & CAUSEF_IP2)
 138                ls1x_irq_dispatch(0); /* INT0 */
 139        else if (pending & CAUSEF_IP3)
 140                ls1x_irq_dispatch(1); /* INT1 */
 141        else if (pending & CAUSEF_IP4)
 142                ls1x_irq_dispatch(2); /* INT2 */
 143        else if (pending & CAUSEF_IP5)
 144                ls1x_irq_dispatch(3); /* INT3 */
 145        else if (pending & CAUSEF_IP6)
 146                ls1x_irq_dispatch(4); /* INT4 */
 147        else
 148                spurious_interrupt();
 149
 150}
 151
 152static void __init ls1x_irq_init(int base)
 153{
 154        int n;
 155
 156        /* Disable interrupts and clear pending,
 157         * setup all IRQs as high level triggered
 158         */
 159        for (n = 0; n < INTN; n++) {
 160                __raw_writel(0x0, LS1X_INTC_INTIEN(n));
 161                __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
 162                __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
 163                /* set DMA0, DMA1 and DMA2 to edge trigger */
 164                __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
 165        }
 166
 167
 168        for (n = base; n < NR_IRQS; n++) {
 169                irq_set_chip_and_handler(n, &ls1x_irq_chip,
 170                                         handle_level_irq);
 171        }
 172
 173        if (request_irq(INT0_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
 174                pr_err("Failed to request irq %d (cascade)\n", INT0_IRQ);
 175        if (request_irq(INT1_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
 176                pr_err("Failed to request irq %d (cascade)\n", INT1_IRQ);
 177        if (request_irq(INT2_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
 178                pr_err("Failed to request irq %d (cascade)\n", INT2_IRQ);
 179        if (request_irq(INT3_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
 180                pr_err("Failed to request irq %d (cascade)\n", INT3_IRQ);
 181#if defined(CONFIG_LOONGSON1_LS1C)
 182        if (request_irq(INT4_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
 183                pr_err("Failed to request irq %d (cascade)\n", INT4_IRQ);
 184#endif
 185}
 186
 187void __init arch_init_irq(void)
 188{
 189        mips_cpu_irq_init();
 190        ls1x_irq_init(LS1X_IRQ_BASE);
 191}
 192