irq-mscc-ocelot.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /*
  3. * Microsemi Ocelot IRQ controller driver
  4. *
  5. * Copyright (c) 2017 Microsemi Corporation
  6. */
  7. #include <linux/bitops.h>
  8. #include <linux/irq.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_irq.h>
  11. #include <linux/irqchip.h>
  12. #include <linux/irqchip/chained_irq.h>
  13. #include <linux/interrupt.h>
  14. #define ICPU_CFG_INTR_INTR_STICKY 0x10
  15. #define ICPU_CFG_INTR_INTR_ENA 0x18
  16. #define ICPU_CFG_INTR_INTR_ENA_CLR 0x1c
  17. #define ICPU_CFG_INTR_INTR_ENA_SET 0x20
  18. #define ICPU_CFG_INTR_DST_INTR_IDENT(x) (0x38 + 0x4 * (x))
  19. #define ICPU_CFG_INTR_INTR_TRIGGER(x) (0x5c + 0x4 * (x))
  20. #define OCELOT_NR_IRQ 24
  21. static void ocelot_irq_unmask(struct irq_data *data)
  22. {
  23. struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
  24. struct irq_chip_type *ct = irq_data_get_chip_type(data);
  25. unsigned int mask = data->mask;
  26. u32 val;
  27. irq_gc_lock(gc);
  28. val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(0)) |
  29. irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(1));
  30. if (!(val & mask))
  31. irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_STICKY);
  32. *ct->mask_cache &= ~mask;
  33. irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_ENA_SET);
  34. irq_gc_unlock(gc);
  35. }
  36. static void ocelot_irq_handler(struct irq_desc *desc)
  37. {
  38. struct irq_chip *chip = irq_desc_get_chip(desc);
  39. struct irq_domain *d = irq_desc_get_handler_data(desc);
  40. struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
  41. u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(0));
  42. chained_irq_enter(chip, desc);
  43. while (reg) {
  44. u32 hwirq = __fls(reg);
  45. generic_handle_irq(irq_find_mapping(d, hwirq));
  46. reg &= ~(BIT(hwirq));
  47. }
  48. chained_irq_exit(chip, desc);
  49. }
  50. static int __init ocelot_irq_init(struct device_node *node,
  51. struct device_node *parent)
  52. {
  53. struct irq_domain *domain;
  54. struct irq_chip_generic *gc;
  55. int parent_irq, ret;
  56. parent_irq = irq_of_parse_and_map(node, 0);
  57. if (!parent_irq)
  58. return -EINVAL;
  59. domain = irq_domain_add_linear(node, OCELOT_NR_IRQ,
  60. &irq_generic_chip_ops, NULL);
  61. if (!domain) {
  62. pr_err("%pOFn: unable to add irq domain\n", node);
  63. return -ENOMEM;
  64. }
  65. ret = irq_alloc_domain_generic_chips(domain, OCELOT_NR_IRQ, 1,
  66. "icpu", handle_level_irq,
  67. 0, 0, 0);
  68. if (ret) {
  69. pr_err("%pOFn: unable to alloc irq domain gc\n", node);
  70. goto err_domain_remove;
  71. }
  72. gc = irq_get_domain_generic_chip(domain, 0);
  73. gc->reg_base = of_iomap(node, 0);
  74. if (!gc->reg_base) {
  75. pr_err("%pOFn: unable to map resource\n", node);
  76. ret = -ENOMEM;
  77. goto err_gc_free;
  78. }
  79. gc->chip_types[0].regs.ack = ICPU_CFG_INTR_INTR_STICKY;
  80. gc->chip_types[0].regs.mask = ICPU_CFG_INTR_INTR_ENA_CLR;
  81. gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
  82. gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
  83. gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask;
  84. /* Mask and ack all interrupts */
  85. irq_reg_writel(gc, 0, ICPU_CFG_INTR_INTR_ENA);
  86. irq_reg_writel(gc, 0xffffffff, ICPU_CFG_INTR_INTR_STICKY);
  87. irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler,
  88. domain);
  89. return 0;
  90. err_gc_free:
  91. irq_free_generic_chip(gc);
  92. err_domain_remove:
  93. irq_domain_remove(domain);
  94. return ret;
  95. }
  96. IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init);