mpc8xx_pic.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include <linux/kernel.h>
  2. #include <linux/stddef.h>
  3. #include <linux/init.h>
  4. #include <linux/sched.h>
  5. #include <linux/signal.h>
  6. #include <linux/irq.h>
  7. #include <linux/dma-mapping.h>
  8. #include <asm/prom.h>
  9. #include <asm/irq.h>
  10. #include <asm/io.h>
  11. #include <asm/8xx_immap.h>
  12. #include "mpc8xx_pic.h"
  13. #define PIC_VEC_SPURRIOUS 15
  14. extern int cpm_get_irq(struct pt_regs *regs);
  15. static struct irq_domain *mpc8xx_pic_host;
  16. static unsigned long mpc8xx_cached_irq_mask;
  17. static sysconf8xx_t __iomem *siu_reg;
  18. static inline unsigned long mpc8xx_irqd_to_bit(struct irq_data *d)
  19. {
  20. return 0x80000000 >> irqd_to_hwirq(d);
  21. }
  22. static void mpc8xx_unmask_irq(struct irq_data *d)
  23. {
  24. mpc8xx_cached_irq_mask |= mpc8xx_irqd_to_bit(d);
  25. out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
  26. }
  27. static void mpc8xx_mask_irq(struct irq_data *d)
  28. {
  29. mpc8xx_cached_irq_mask &= ~mpc8xx_irqd_to_bit(d);
  30. out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
  31. }
  32. static void mpc8xx_ack(struct irq_data *d)
  33. {
  34. out_be32(&siu_reg->sc_sipend, mpc8xx_irqd_to_bit(d));
  35. }
  36. static void mpc8xx_end_irq(struct irq_data *d)
  37. {
  38. mpc8xx_cached_irq_mask |= mpc8xx_irqd_to_bit(d);
  39. out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
  40. }
  41. static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type)
  42. {
  43. /* only external IRQ senses are programmable */
  44. if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !(irqd_to_hwirq(d) & 1)) {
  45. unsigned int siel = in_be32(&siu_reg->sc_siel);
  46. siel |= mpc8xx_irqd_to_bit(d);
  47. out_be32(&siu_reg->sc_siel, siel);
  48. __irq_set_handler_locked(d->irq, handle_edge_irq);
  49. }
  50. return 0;
  51. }
  52. static struct irq_chip mpc8xx_pic = {
  53. .name = "MPC8XX SIU",
  54. .irq_unmask = mpc8xx_unmask_irq,
  55. .irq_mask = mpc8xx_mask_irq,
  56. .irq_ack = mpc8xx_ack,
  57. .irq_eoi = mpc8xx_end_irq,
  58. .irq_set_type = mpc8xx_set_irq_type,
  59. };
  60. unsigned int mpc8xx_get_irq(void)
  61. {
  62. int irq;
  63. /* For MPC8xx, read the SIVEC register and shift the bits down
  64. * to get the irq number.
  65. */
  66. irq = in_be32(&siu_reg->sc_sivec) >> 26;
  67. if (irq == PIC_VEC_SPURRIOUS)
  68. irq = NO_IRQ;
  69. return irq_linear_revmap(mpc8xx_pic_host, irq);
  70. }
  71. static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq,
  72. irq_hw_number_t hw)
  73. {
  74. pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
  75. /* Set default irq handle */
  76. irq_set_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
  77. return 0;
  78. }
  79. static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
  80. const u32 *intspec, unsigned int intsize,
  81. irq_hw_number_t *out_hwirq, unsigned int *out_flags)
  82. {
  83. static unsigned char map_pic_senses[4] = {
  84. IRQ_TYPE_EDGE_RISING,
  85. IRQ_TYPE_LEVEL_LOW,
  86. IRQ_TYPE_LEVEL_HIGH,
  87. IRQ_TYPE_EDGE_FALLING,
  88. };
  89. if (intspec[0] > 0x1f)
  90. return 0;
  91. *out_hwirq = intspec[0];
  92. if (intsize > 1 && intspec[1] < 4)
  93. *out_flags = map_pic_senses[intspec[1]];
  94. else
  95. *out_flags = IRQ_TYPE_NONE;
  96. return 0;
  97. }
  98. static struct irq_domain_ops mpc8xx_pic_host_ops = {
  99. .map = mpc8xx_pic_host_map,
  100. .xlate = mpc8xx_pic_host_xlate,
  101. };
  102. int mpc8xx_pic_init(void)
  103. {
  104. struct resource res;
  105. struct device_node *np;
  106. int ret;
  107. np = of_find_compatible_node(NULL, NULL, "fsl,pq1-pic");
  108. if (np == NULL)
  109. np = of_find_node_by_type(NULL, "mpc8xx-pic");
  110. if (np == NULL) {
  111. printk(KERN_ERR "Could not find fsl,pq1-pic node\n");
  112. return -ENOMEM;
  113. }
  114. ret = of_address_to_resource(np, 0, &res);
  115. if (ret)
  116. goto out;
  117. siu_reg = ioremap(res.start, resource_size(&res));
  118. if (siu_reg == NULL) {
  119. ret = -EINVAL;
  120. goto out;
  121. }
  122. mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL);
  123. if (mpc8xx_pic_host == NULL) {
  124. printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
  125. ret = -ENOMEM;
  126. goto out;
  127. }
  128. return 0;
  129. out:
  130. of_node_put(np);
  131. return ret;
  132. }