intc2.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * Interrupt handling for INTC2-based IRQ.
  3. *
  4. * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
  5. * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org)
  6. *
  7. * May be copied or modified under the terms of the GNU General Public
  8. * License. See linux/COPYING for more information.
  9. *
  10. * These are the "new Hitachi style" interrupts, as present on the
  11. * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
  12. */
  13. #include <linux/kernel.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/io.h>
  16. #include <asm/smp.h>
  17. static inline struct intc2_desc *get_intc2_desc(unsigned int irq)
  18. {
  19. struct irq_chip *chip = get_irq_chip(irq);
  20. return (void *)((char *)chip - offsetof(struct intc2_desc, chip));
  21. }
  22. static void disable_intc2_irq(unsigned int irq)
  23. {
  24. struct intc2_data *p = get_irq_chip_data(irq);
  25. struct intc2_desc *d = get_intc2_desc(irq);
  26. ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset +
  27. (hard_smp_processor_id() * 4));
  28. }
  29. static void enable_intc2_irq(unsigned int irq)
  30. {
  31. struct intc2_data *p = get_irq_chip_data(irq);
  32. struct intc2_desc *d = get_intc2_desc(irq);
  33. ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset +
  34. (hard_smp_processor_id() * 4));
  35. }
  36. /*
  37. * Setup an INTC2 style interrupt.
  38. * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
  39. * allowing the use of the numbers straight out of the datasheet.
  40. * For example:
  41. * PIO1 which is INTPRI00[19,16] and INTMSK00[13]
  42. * would be: ^ ^ ^ ^
  43. * | | | |
  44. * { 84, 0, 16, 0, 13 },
  45. *
  46. * in the intc2_data table.
  47. */
  48. void register_intc2_controller(struct intc2_desc *desc)
  49. {
  50. int i;
  51. desc->chip.mask = disable_intc2_irq;
  52. desc->chip.unmask = enable_intc2_irq;
  53. desc->chip.mask_ack = disable_intc2_irq;
  54. for (i = 0; i < desc->nr_irqs; i++) {
  55. unsigned long ipr, flags;
  56. struct intc2_data *p = desc->intc2_data + i;
  57. disable_irq_nosync(p->irq);
  58. if (desc->prio_base) {
  59. /* Set the priority level */
  60. local_irq_save(flags);
  61. ipr = ctrl_inl(desc->prio_base + p->ipr_offset);
  62. ipr &= ~(0xf << p->ipr_shift);
  63. ipr |= p->priority << p->ipr_shift;
  64. ctrl_outl(ipr, desc->prio_base + p->ipr_offset);
  65. local_irq_restore(flags);
  66. }
  67. set_irq_chip_and_handler_name(p->irq, &desc->chip,
  68. handle_level_irq, "level");
  69. set_irq_chip_data(p->irq, p);
  70. disable_intc2_irq(p->irq);
  71. }
  72. }