adir_pic.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * arch/ppc/platforms/adir_pic.c
  3. *
  4. * Interrupt controller support for SBS Adirondack
  5. *
  6. * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
  7. * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com>
  8. */
  9. #include <linux/stddef.h>
  10. #include <linux/init.h>
  11. #include <linux/sched.h>
  12. #include <linux/pci.h>
  13. #include <linux/interrupt.h>
  14. #include <asm/io.h>
  15. #include <asm/i8259.h>
  16. #include "adir.h"
  17. static void adir_onboard_pic_enable(unsigned int irq);
  18. static void adir_onboard_pic_disable(unsigned int irq);
  19. __init static void
  20. adir_onboard_pic_init(void)
  21. {
  22. volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
  23. /* Disable all Adirondack onboard interrupts */
  24. out_be16(maskreg, 0xFFFF);
  25. }
  26. static int
  27. adir_onboard_pic_get_irq(void)
  28. {
  29. volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT;
  30. int irq;
  31. u_short int_status, int_test;
  32. int_status = in_be16(statreg);
  33. for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) {
  34. if (int_status & int_test)
  35. break;
  36. }
  37. if (irq == 16)
  38. return -1;
  39. return (irq+16);
  40. }
  41. static void
  42. adir_onboard_pic_enable(unsigned int irq)
  43. {
  44. volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
  45. /* Change irq to Adirondack onboard native value */
  46. irq -= 16;
  47. /* Enable requested irq number */
  48. out_be16(maskreg, in_be16(maskreg) & ~(1 << irq));
  49. }
  50. static void
  51. adir_onboard_pic_disable(unsigned int irq)
  52. {
  53. volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
  54. /* Change irq to Adirondack onboard native value */
  55. irq -= 16;
  56. /* Disable requested irq number */
  57. out_be16(maskreg, in_be16(maskreg) | (1 << irq));
  58. }
  59. static struct hw_interrupt_type adir_onboard_pic = {
  60. " ADIR PIC ",
  61. NULL,
  62. NULL,
  63. adir_onboard_pic_enable, /* unmask */
  64. adir_onboard_pic_disable, /* mask */
  65. adir_onboard_pic_disable, /* mask and ack */
  66. NULL,
  67. NULL
  68. };
  69. static struct irqaction noop_action = {
  70. .handler = no_action,
  71. .flags = SA_INTERRUPT,
  72. .mask = CPU_MASK_NONE,
  73. .name = "82c59 primary cascade",
  74. };
  75. /*
  76. * Linux interrupt values are assigned as follows:
  77. *
  78. * 0-15 VT82C686 8259 interrupts
  79. * 16-31 Adirondack CPLD interrupts
  80. */
  81. __init void
  82. adir_init_IRQ(void)
  83. {
  84. int i;
  85. /* Initialize the cascaded 8259's on the VT82C686 */
  86. for (i=0; i<16; i++)
  87. irq_desc[i].handler = &i8259_pic;
  88. i8259_init(NULL);
  89. /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */
  90. for (i=16; i<32; i++)
  91. irq_desc[i].handler = &adir_onboard_pic;
  92. adir_onboard_pic_init();
  93. /* Enable 8259 interrupt cascade */
  94. setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action);
  95. }
  96. int
  97. adir_get_irq(struct pt_regs *regs)
  98. {
  99. int irq;
  100. if ((irq = adir_onboard_pic_get_irq()) < 0)
  101. return irq;
  102. if (irq == ADIR_IRQ_VT82C686_INTR)
  103. irq = i8259_irq(regs);
  104. return irq;
  105. }