irq-mscc-ocelot.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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_DST_INTR_IDENT(_p, x) ((_p)->reg_off_ident + 0x4 * (x))
  15. #define ICPU_CFG_INTR_INTR_TRIGGER(_p, x) ((_p)->reg_off_trigger + 0x4 * (x))
  16. #define FLAGS_HAS_TRIGGER BIT(0)
  17. #define FLAGS_NEED_INIT_ENABLE BIT(1)
  18. struct chip_props {
  19. u8 flags;
  20. u8 reg_off_sticky;
  21. u8 reg_off_ena;
  22. u8 reg_off_ena_clr;
  23. u8 reg_off_ena_set;
  24. u8 reg_off_ident;
  25. u8 reg_off_trigger;
  26. u8 reg_off_ena_irq0;
  27. u8 n_irq;
  28. };
  29. static struct chip_props ocelot_props = {
  30. .flags = FLAGS_HAS_TRIGGER,
  31. .reg_off_sticky = 0x10,
  32. .reg_off_ena = 0x18,
  33. .reg_off_ena_clr = 0x1c,
  34. .reg_off_ena_set = 0x20,
  35. .reg_off_ident = 0x38,
  36. .reg_off_trigger = 0x5c,
  37. .n_irq = 24,
  38. };
  39. static struct chip_props serval_props = {
  40. .flags = FLAGS_HAS_TRIGGER,
  41. .reg_off_sticky = 0xc,
  42. .reg_off_ena = 0x14,
  43. .reg_off_ena_clr = 0x18,
  44. .reg_off_ena_set = 0x1c,
  45. .reg_off_ident = 0x20,
  46. .reg_off_trigger = 0x4,
  47. .n_irq = 24,
  48. };
  49. static struct chip_props luton_props = {
  50. .flags = FLAGS_NEED_INIT_ENABLE,
  51. .reg_off_sticky = 0,
  52. .reg_off_ena = 0x4,
  53. .reg_off_ena_clr = 0x8,
  54. .reg_off_ena_set = 0xc,
  55. .reg_off_ident = 0x18,
  56. .reg_off_ena_irq0 = 0x14,
  57. .n_irq = 28,
  58. };
  59. static struct chip_props jaguar2_props = {
  60. .flags = FLAGS_HAS_TRIGGER,
  61. .reg_off_sticky = 0x10,
  62. .reg_off_ena = 0x18,
  63. .reg_off_ena_clr = 0x1c,
  64. .reg_off_ena_set = 0x20,
  65. .reg_off_ident = 0x38,
  66. .reg_off_trigger = 0x5c,
  67. .n_irq = 29,
  68. };
  69. static void ocelot_irq_unmask(struct irq_data *data)
  70. {
  71. struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
  72. struct irq_domain *d = data->domain;
  73. struct chip_props *p = d->host_data;
  74. struct irq_chip_type *ct = irq_data_get_chip_type(data);
  75. unsigned int mask = data->mask;
  76. u32 val;
  77. irq_gc_lock(gc);
  78. val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 0)) |
  79. irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 1));
  80. if (!(val & mask))
  81. irq_reg_writel(gc, mask, p->reg_off_sticky);
  82. *ct->mask_cache &= ~mask;
  83. irq_reg_writel(gc, mask, p->reg_off_ena_set);
  84. irq_gc_unlock(gc);
  85. }
  86. static void ocelot_irq_handler(struct irq_desc *desc)
  87. {
  88. struct irq_chip *chip = irq_desc_get_chip(desc);
  89. struct irq_domain *d = irq_desc_get_handler_data(desc);
  90. struct chip_props *p = d->host_data;
  91. struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
  92. u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(p, 0));
  93. chained_irq_enter(chip, desc);
  94. while (reg) {
  95. u32 hwirq = __fls(reg);
  96. generic_handle_domain_irq(d, hwirq);
  97. reg &= ~(BIT(hwirq));
  98. }
  99. chained_irq_exit(chip, desc);
  100. }
  101. static int __init vcoreiii_irq_init(struct device_node *node,
  102. struct device_node *parent,
  103. struct chip_props *p)
  104. {
  105. struct irq_domain *domain;
  106. struct irq_chip_generic *gc;
  107. int parent_irq, ret;
  108. parent_irq = irq_of_parse_and_map(node, 0);
  109. if (!parent_irq)
  110. return -EINVAL;
  111. domain = irq_domain_add_linear(node, p->n_irq,
  112. &irq_generic_chip_ops, NULL);
  113. if (!domain) {
  114. pr_err("%pOFn: unable to add irq domain\n", node);
  115. return -ENOMEM;
  116. }
  117. ret = irq_alloc_domain_generic_chips(domain, p->n_irq, 1,
  118. "icpu", handle_level_irq,
  119. 0, 0, 0);
  120. if (ret) {
  121. pr_err("%pOFn: unable to alloc irq domain gc\n", node);
  122. goto err_domain_remove;
  123. }
  124. gc = irq_get_domain_generic_chip(domain, 0);
  125. gc->reg_base = of_iomap(node, 0);
  126. if (!gc->reg_base) {
  127. pr_err("%pOFn: unable to map resource\n", node);
  128. ret = -ENOMEM;
  129. goto err_gc_free;
  130. }
  131. gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
  132. gc->chip_types[0].regs.ack = p->reg_off_sticky;
  133. if (p->flags & FLAGS_HAS_TRIGGER) {
  134. gc->chip_types[0].regs.mask = p->reg_off_ena_clr;
  135. gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask;
  136. gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
  137. } else {
  138. gc->chip_types[0].regs.enable = p->reg_off_ena_set;
  139. gc->chip_types[0].regs.disable = p->reg_off_ena_clr;
  140. gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
  141. gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
  142. }
  143. /* Mask and ack all interrupts */
  144. irq_reg_writel(gc, 0, p->reg_off_ena);
  145. irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky);
  146. /* Overall init */
  147. if (p->flags & FLAGS_NEED_INIT_ENABLE)
  148. irq_reg_writel(gc, BIT(0), p->reg_off_ena_irq0);
  149. domain->host_data = p;
  150. irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler,
  151. domain);
  152. return 0;
  153. err_gc_free:
  154. irq_free_generic_chip(gc);
  155. err_domain_remove:
  156. irq_domain_remove(domain);
  157. return ret;
  158. }
  159. static int __init ocelot_irq_init(struct device_node *node,
  160. struct device_node *parent)
  161. {
  162. return vcoreiii_irq_init(node, parent, &ocelot_props);
  163. }
  164. IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init);
  165. static int __init serval_irq_init(struct device_node *node,
  166. struct device_node *parent)
  167. {
  168. return vcoreiii_irq_init(node, parent, &serval_props);
  169. }
  170. IRQCHIP_DECLARE(serval_icpu, "mscc,serval-icpu-intr", serval_irq_init);
  171. static int __init luton_irq_init(struct device_node *node,
  172. struct device_node *parent)
  173. {
  174. return vcoreiii_irq_init(node, parent, &luton_props);
  175. }
  176. IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init);
  177. static int __init jaguar2_irq_init(struct device_node *node,
  178. struct device_node *parent)
  179. {
  180. return vcoreiii_irq_init(node, parent, &jaguar2_props);
  181. }
  182. IRQCHIP_DECLARE(jaguar2_icpu, "mscc,jaguar2-icpu-intr", jaguar2_irq_init);