300-irqchip-irq-ath79-intc-add-irq-cascade-driver-for-QC.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. From f3eacff2310a60348a755c50a8da6fc251fc8587 Mon Sep 17 00:00:00 2001
  2. From: John Crispin <[email protected]>
  3. Date: Tue, 6 Mar 2018 09:55:13 +0100
  4. Subject: [PATCH 07/33] irqchip/irq-ath79-intc: add irq cascade driver for
  5. QCA9556 SoCs
  6. Signed-off-by: John Crispin <[email protected]>
  7. ---
  8. drivers/irqchip/Makefile | 1 +
  9. drivers/irqchip/irq-ath79-intc.c | 142 +++++++++++++++++++++++++++++++++++++++
  10. 2 files changed, 143 insertions(+)
  11. create mode 100644 drivers/irqchip/irq-ath79-intc.c
  12. --- a/drivers/irqchip/Makefile
  13. +++ b/drivers/irqchip/Makefile
  14. @@ -4,6 +4,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o
  15. obj-$(CONFIG_AL_FIC) += irq-al-fic.o
  16. obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o
  17. obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
  18. +obj-$(CONFIG_ATH79) += irq-ath79-intc.o
  19. obj-$(CONFIG_ATH79) += irq-ath79-misc.o
  20. obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
  21. obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
  22. --- /dev/null
  23. +++ b/drivers/irqchip/irq-ath79-intc.c
  24. @@ -0,0 +1,142 @@
  25. +/*
  26. + * Atheros AR71xx/AR724x/AR913x specific interrupt handling
  27. + *
  28. + * Copyright (C) 2018 John Crispin <[email protected]>
  29. + *
  30. + * This program is free software; you can redistribute it and/or modify it
  31. + * under the terms of the GNU General Public License version 2 as published
  32. + * by the Free Software Foundation.
  33. + */
  34. +
  35. +#include <linux/interrupt.h>
  36. +#include <linux/irqchip.h>
  37. +#include <linux/of.h>
  38. +#include <linux/of_irq.h>
  39. +#include <linux/irqdomain.h>
  40. +
  41. +#include <asm/irq_cpu.h>
  42. +#include <asm/mach-ath79/ath79.h>
  43. +#include <asm/mach-ath79/ar71xx_regs.h>
  44. +
  45. +#define ATH79_MAX_INTC_CASCADE 3
  46. +
  47. +struct ath79_intc {
  48. + struct irq_chip chip;
  49. + u32 irq;
  50. + u32 pending_mask;
  51. + u32 int_status;
  52. + u32 irq_mask[ATH79_MAX_INTC_CASCADE];
  53. + u32 irq_wb_chan[ATH79_MAX_INTC_CASCADE];
  54. +};
  55. +
  56. +static void ath79_intc_irq_handler(struct irq_desc *desc)
  57. +{
  58. + struct irq_domain *domain = irq_desc_get_handler_data(desc);
  59. + struct ath79_intc *intc = domain->host_data;
  60. + u32 pending;
  61. +
  62. + pending = ath79_reset_rr(intc->int_status);
  63. + pending &= intc->pending_mask;
  64. +
  65. + if (pending) {
  66. + int i;
  67. +
  68. + for (i = 0; i < domain->hwirq_max; i++)
  69. + if (pending & intc->irq_mask[i]) {
  70. + if (intc->irq_wb_chan[i] != 0xffffffff)
  71. + ath79_ddr_wb_flush(intc->irq_wb_chan[i]);
  72. + generic_handle_irq(irq_find_mapping(domain, i));
  73. + }
  74. + } else {
  75. + spurious_interrupt();
  76. + }
  77. +}
  78. +
  79. +static void ath79_intc_irq_enable(struct irq_data *d)
  80. +{
  81. + struct ath79_intc *intc = d->domain->host_data;
  82. + enable_irq(intc->irq);
  83. +}
  84. +
  85. +static void ath79_intc_irq_disable(struct irq_data *d)
  86. +{
  87. + struct ath79_intc *intc = d->domain->host_data;
  88. + disable_irq(intc->irq);
  89. +}
  90. +
  91. +static int ath79_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
  92. +{
  93. + struct ath79_intc *intc = d->host_data;
  94. +
  95. + irq_set_chip_and_handler(irq, &intc->chip, handle_level_irq);
  96. +
  97. + return 0;
  98. +}
  99. +
  100. +static const struct irq_domain_ops ath79_irq_domain_ops = {
  101. + .xlate = irq_domain_xlate_onecell,
  102. + .map = ath79_intc_map,
  103. +};
  104. +
  105. +static int __init ath79_intc_of_init(
  106. + struct device_node *node, struct device_node *parent)
  107. +{
  108. + struct irq_domain *domain;
  109. + struct ath79_intc *intc;
  110. + int cnt, cntwb, i, err;
  111. +
  112. + cnt = of_property_count_u32_elems(node, "qca,pending-bits");
  113. + if (cnt > ATH79_MAX_INTC_CASCADE)
  114. + panic("Too many INTC pending bits\n");
  115. +
  116. + intc = kzalloc(sizeof(*intc), GFP_KERNEL);
  117. + if (!intc)
  118. + panic("Failed to allocate INTC memory\n");
  119. + intc->chip = dummy_irq_chip;
  120. + intc->chip.name = "INTC";
  121. + intc->chip.irq_disable = ath79_intc_irq_disable;
  122. + intc->chip.irq_enable = ath79_intc_irq_enable;
  123. +
  124. + if (of_property_read_u32(node, "qca,int-status-addr", &intc->int_status) < 0) {
  125. + panic("Missing address of interrupt status register\n");
  126. + }
  127. +
  128. + of_property_read_u32_array(node, "qca,pending-bits", intc->irq_mask, cnt);
  129. + for (i = 0; i < cnt; i++) {
  130. + intc->pending_mask |= intc->irq_mask[i];
  131. + intc->irq_wb_chan[i] = 0xffffffff;
  132. + }
  133. +
  134. + cntwb = of_count_phandle_with_args(
  135. + node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
  136. +
  137. + for (i = 0; i < cntwb; i++) {
  138. + struct of_phandle_args args;
  139. + u32 irq = i;
  140. +
  141. + of_property_read_u32_index(
  142. + node, "qca,ddr-wb-channel-interrupts", i, &irq);
  143. + if (irq >= ATH79_MAX_INTC_CASCADE)
  144. + continue;
  145. +
  146. + err = of_parse_phandle_with_args(
  147. + node, "qca,ddr-wb-channels",
  148. + "#qca,ddr-wb-channel-cells",
  149. + i, &args);
  150. + if (err)
  151. + return err;
  152. +
  153. + intc->irq_wb_chan[irq] = args.args[0];
  154. + }
  155. +
  156. + intc->irq = irq_of_parse_and_map(node, 0);
  157. + if (!intc->irq)
  158. + panic("Failed to get INTC IRQ");
  159. +
  160. + domain = irq_domain_add_linear(node, cnt, &ath79_irq_domain_ops, intc);
  161. + irq_set_chained_handler_and_data(intc->irq, ath79_intc_irq_handler, domain);
  162. +
  163. + return 0;
  164. +}
  165. +IRQCHIP_DECLARE(ath79_intc, "qca,ar9340-intc",
  166. + ath79_intc_of_init);