msp_irq_cic.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * This file define the irq handler for MSP SLM subsystem interrupts.
  3. *
  4. * Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c
  5. * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2 of the License, or (at your
  10. * option) any later version.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/kernel.h>
  15. #include <linux/bitops.h>
  16. #include <linux/irq.h>
  17. #include <asm/system.h>
  18. #include <msp_cic_int.h>
  19. #include <msp_regs.h>
  20. /*
  21. * NOTE: We are only enabling support for VPE0 right now.
  22. */
  23. static inline void unmask_msp_cic_irq(unsigned int irq)
  24. {
  25. /* check for PER interrupt range */
  26. if (irq < MSP_PER_INTBASE)
  27. *CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE));
  28. else
  29. *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
  30. }
  31. static inline void mask_msp_cic_irq(unsigned int irq)
  32. {
  33. /* check for PER interrupt range */
  34. if (irq < MSP_PER_INTBASE)
  35. *CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE));
  36. else
  37. *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
  38. }
  39. /*
  40. * While we ack the interrupt interrupts are disabled and thus we don't need
  41. * to deal with concurrency issues. Same for msp_cic_irq_end.
  42. */
  43. static inline void ack_msp_cic_irq(unsigned int irq)
  44. {
  45. mask_msp_cic_irq(irq);
  46. /*
  47. * only really necessary for 18, 16-14 and sometimes 3:0 (since
  48. * these can be edge sensitive) but it doesn't hurt for the others.
  49. */
  50. /* check for PER interrupt range */
  51. if (irq < MSP_PER_INTBASE)
  52. *CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE));
  53. else
  54. *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
  55. }
  56. static struct irq_chip msp_cic_irq_controller = {
  57. .name = "MSP_CIC",
  58. .ack = ack_msp_cic_irq,
  59. .mask = ack_msp_cic_irq,
  60. .mask_ack = ack_msp_cic_irq,
  61. .unmask = unmask_msp_cic_irq,
  62. };
  63. void __init msp_cic_irq_init(void)
  64. {
  65. int i;
  66. /* Mask/clear interrupts. */
  67. *CIC_VPE0_MSK_REG = 0x00000000;
  68. *PER_INT_MSK_REG = 0x00000000;
  69. *CIC_STS_REG = 0xFFFFFFFF;
  70. *PER_INT_STS_REG = 0xFFFFFFFF;
  71. #if defined(CONFIG_PMC_MSP7120_GW) || \
  72. defined(CONFIG_PMC_MSP7120_EVAL)
  73. /*
  74. * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
  75. * These inputs map to EXT_INT_POL[6:4] inside the CIC.
  76. * They are to be active low, level sensitive.
  77. */
  78. *CIC_EXT_CFG_REG &= 0xFFFF8F8F;
  79. #endif
  80. /* initialize all the IRQ descriptors */
  81. for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++)
  82. set_irq_chip_and_handler(i, &msp_cic_irq_controller,
  83. handle_level_irq);
  84. }
  85. void msp_cic_irq_dispatch(void)
  86. {
  87. u32 pending;
  88. int intbase;
  89. intbase = MSP_CIC_INTBASE;
  90. pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
  91. /* check for PER interrupt */
  92. if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
  93. intbase = MSP_PER_INTBASE;
  94. pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
  95. }
  96. /* check for spurious interrupt */
  97. if (pending == 0x00000000) {
  98. printk(KERN_ERR
  99. "Spurious %s interrupt? status %08x, mask %08x\n",
  100. (intbase == MSP_CIC_INTBASE) ? "CIC" : "PER",
  101. (intbase == MSP_CIC_INTBASE) ?
  102. *CIC_STS_REG : *PER_INT_STS_REG,
  103. (intbase == MSP_CIC_INTBASE) ?
  104. *CIC_VPE0_MSK_REG : *PER_INT_MSK_REG);
  105. return;
  106. }
  107. /* check for the timer and dispatch it first */
  108. if ((intbase == MSP_CIC_INTBASE) &&
  109. (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))))
  110. do_IRQ(MSP_INT_VPE0_TIMER);
  111. else
  112. do_IRQ(ffs(pending) + intbase - 1);
  113. }