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