irq.c 3.0 KB

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