sead_int.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Carsten Langgaard, carstenl@mips.com
  3. * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
  4. * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org)
  5. * Copyright (C) 2004 Maciej W. Rozycki
  6. *
  7. * This program is free software; you can distribute it and/or modify it
  8. * under the terms of the GNU General Public License (Version 2) as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  19. *
  20. * Routines for generic manipulation of the interrupts found on the MIPS
  21. * Sead board.
  22. */
  23. #include <linux/init.h>
  24. #include <linux/irq.h>
  25. #include <asm/irq_cpu.h>
  26. #include <asm/mipsregs.h>
  27. #include <asm/system.h>
  28. #include <asm/mips-boards/seadint.h>
  29. static inline int clz(unsigned long x)
  30. {
  31. __asm__ (
  32. " .set push \n"
  33. " .set mips32 \n"
  34. " clz %0, %1 \n"
  35. " .set pop \n"
  36. : "=r" (x)
  37. : "r" (x));
  38. return x;
  39. }
  40. /*
  41. * Version of ffs that only looks at bits 12..15.
  42. */
  43. static inline unsigned int irq_ffs(unsigned int pending)
  44. {
  45. #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
  46. return -clz(pending) + 31 - CAUSEB_IP;
  47. #else
  48. unsigned int a0 = 7;
  49. unsigned int t0;
  50. t0 = s0 & 0xf000;
  51. t0 = t0 < 1;
  52. t0 = t0 << 2;
  53. a0 = a0 - t0;
  54. s0 = s0 << t0;
  55. t0 = s0 & 0xc000;
  56. t0 = t0 < 1;
  57. t0 = t0 << 1;
  58. a0 = a0 - t0;
  59. s0 = s0 << t0;
  60. t0 = s0 & 0x8000;
  61. t0 = t0 < 1;
  62. //t0 = t0 << 2;
  63. a0 = a0 - t0;
  64. //s0 = s0 << t0;
  65. return a0;
  66. #endif
  67. }
  68. /*
  69. * IRQs on the SEAD board look basically are combined together on hardware
  70. * interrupt 0 (MIPS IRQ 2)) like:
  71. *
  72. * MIPS IRQ Source
  73. * -------- ------
  74. * 0 Software (ignored)
  75. * 1 Software (ignored)
  76. * 2 UART0 (hw0)
  77. * 3 UART1 (hw1)
  78. * 4 Hardware (ignored)
  79. * 5 Hardware (ignored)
  80. * 6 Hardware (ignored)
  81. * 7 R4k timer (what we use)
  82. *
  83. * We handle the IRQ according to _our_ priority which is:
  84. *
  85. * Highest ---- R4k Timer
  86. * Lowest ---- Combined hardware interrupt
  87. *
  88. * then we just return, if multiple IRQs are pending then we will just take
  89. * another exception, big deal.
  90. */
  91. asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
  92. {
  93. unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
  94. int irq;
  95. irq = irq_ffs(pending);
  96. if (irq >= 0)
  97. do_IRQ(MIPSCPU_INT_BASE + irq, regs);
  98. else
  99. spurious_interrupt(regs);
  100. }
  101. void __init arch_init_irq(void)
  102. {
  103. mips_cpu_irq_init(MIPSCPU_INT_BASE);
  104. }