^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) 2007 Lemote Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Fuxin Zhang, zhangfx@lemote.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/irq_cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/i8259.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/mipsregs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <loongson.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <machine.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define LOONGSON_SOUTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 2) /* i8259 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define LOONGSON_INT_BIT_INT0 (1 << 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define LOONGSON_INT_BIT_INT1 (1 << 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * The generic i8259_irq() make the kernel hang on booting. Since we cannot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * get the irq via the IRR directly, we access the ISR instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int mach_i8259_irq(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int irq, isr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if ((LOONGSON_INTISR & LOONGSON_INTEN) & LOONGSON_INT_BIT_INT0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) raw_spin_lock(&i8259A_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) isr = inb(PIC_MASTER_CMD) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ~inb(PIC_MASTER_IMR) & ~(1 << PIC_CASCADE_IR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!isr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) isr = (inb(PIC_SLAVE_CMD) & ~inb(PIC_SLAVE_IMR)) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) irq = ffs(isr) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (unlikely(irq == 7)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * This may be a spurious interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Read the interrupt status register (ISR). If the most
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * significant bit is not set then there is no valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) outb(0x0B, PIC_MASTER_ISR); /* ISR register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (~inb(PIC_MASTER_ISR) & 0x80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) raw_spin_unlock(&i8259A_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) EXPORT_SYMBOL(mach_i8259_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static void i8259_irqdispatch(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) irq = mach_i8259_irq();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) do_IRQ(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) spurious_interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) void mach_irq_dispatch(unsigned int pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (pending & CAUSEF_IP7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) do_IRQ(LOONGSON_TIMER_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) do_perfcnt_IRQ();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) bonito_irqdispatch();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) } else if (pending & CAUSEF_IP3) /* CPU UART */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) do_IRQ(LOONGSON_UART_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) else if (pending & CAUSEF_IP2) /* South Bridge */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) i8259_irqdispatch();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) spurious_interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static irqreturn_t ip6_action(int cpl, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) void __init mach_init_irq(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* init all controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * 0-15 ------> i8259 interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * 16-23 ------> mips cpu interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * 32-63 ------> bonito irq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* setup cs5536 as high level trigger */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Sets the first-level interrupt dispatcher. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) mips_cpu_irq_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) init_i8259_irqs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) bonito_irq_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* setup north bridge irq (bonito) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (request_irq(LOONGSON_NORTH_BRIDGE_IRQ, ip6_action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) IRQF_SHARED | IRQF_NO_THREAD, "cascade", ip6_action))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) pr_err("Failed to register north bridge cascade interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* setup source bridge irq (i8259) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (request_irq(LOONGSON_SOUTH_BRIDGE_IRQ, no_action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) IRQF_NO_THREAD | IRQF_NO_SUSPEND, "cascade", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pr_err("Failed to register south bridge cascade interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }