irq-armada-370-xp.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Marvell Armada 370 and Armada XP SoC IRQ handling
  3. *
  4. * Copyright (C) 2012 Marvell
  5. *
  6. * Lior Amsalem <alior@marvell.com>
  7. * Gregory CLEMENT <gregory.clement@free-electrons.com>
  8. * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  9. * Ben Dooks <ben.dooks@codethink.co.uk>
  10. *
  11. * This file is licensed under the terms of the GNU General Public
  12. * License version 2. This program is licensed "as is" without any
  13. * warranty of any kind, whether express or implied.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17. #include <linux/init.h>
  18. #include <linux/irq.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/io.h>
  21. #include <linux/of_address.h>
  22. #include <linux/of_irq.h>
  23. #include <linux/irqdomain.h>
  24. #include <asm/mach/arch.h>
  25. #include <asm/exception.h>
  26. /* Interrupt Controller Registers Map */
  27. #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48)
  28. #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C)
  29. #define ARMADA_370_XP_INT_CONTROL (0x00)
  30. #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30)
  31. #define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34)
  32. #define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
  33. static void __iomem *per_cpu_int_base;
  34. static void __iomem *main_int_base;
  35. static struct irq_domain *armada_370_xp_mpic_domain;
  36. static void armada_370_xp_irq_mask(struct irq_data *d)
  37. {
  38. writel(irqd_to_hwirq(d),
  39. per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
  40. }
  41. static void armada_370_xp_irq_unmask(struct irq_data *d)
  42. {
  43. writel(irqd_to_hwirq(d),
  44. per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
  45. }
  46. static struct irq_chip armada_370_xp_irq_chip = {
  47. .name = "armada_370_xp_irq",
  48. .irq_mask = armada_370_xp_irq_mask,
  49. .irq_mask_ack = armada_370_xp_irq_mask,
  50. .irq_unmask = armada_370_xp_irq_unmask,
  51. };
  52. static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
  53. unsigned int virq, irq_hw_number_t hw)
  54. {
  55. armada_370_xp_irq_mask(irq_get_irq_data(virq));
  56. writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
  57. irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
  58. handle_level_irq);
  59. irq_set_status_flags(virq, IRQ_LEVEL);
  60. set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
  61. return 0;
  62. }
  63. static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
  64. .map = armada_370_xp_mpic_irq_map,
  65. .xlate = irq_domain_xlate_onecell,
  66. };
  67. static int __init armada_370_xp_mpic_of_init(struct device_node *node,
  68. struct device_node *parent)
  69. {
  70. u32 control;
  71. main_int_base = of_iomap(node, 0);
  72. per_cpu_int_base = of_iomap(node, 1);
  73. BUG_ON(!main_int_base);
  74. BUG_ON(!per_cpu_int_base);
  75. control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
  76. armada_370_xp_mpic_domain =
  77. irq_domain_add_linear(node, (control >> 2) & 0x3ff,
  78. &armada_370_xp_mpic_irq_ops, NULL);
  79. if (!armada_370_xp_mpic_domain)
  80. panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n");
  81. irq_set_default_host(armada_370_xp_mpic_domain);
  82. return 0;
  83. }
  84. asmlinkage void __exception_irq_entry armada_370_xp_handle_irq(struct pt_regs
  85. *regs)
  86. {
  87. u32 irqstat, irqnr;
  88. do {
  89. irqstat = readl_relaxed(per_cpu_int_base +
  90. ARMADA_370_XP_CPU_INTACK_OFFS);
  91. irqnr = irqstat & 0x3FF;
  92. if (irqnr < 1023) {
  93. irqnr =
  94. irq_find_mapping(armada_370_xp_mpic_domain, irqnr);
  95. handle_IRQ(irqnr, regs);
  96. continue;
  97. }
  98. break;
  99. } while (1);
  100. }
  101. static const struct of_device_id mpic_of_match[] __initconst = {
  102. {.compatible = "marvell,mpic", .data = armada_370_xp_mpic_of_init},
  103. {},
  104. };
  105. void __init armada_370_xp_init_irq(void)
  106. {
  107. of_irq_init(mpic_of_match);
  108. }