irq-ath79-misc.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Atheros AR71xx/AR724x/AR913x MISC interrupt controller
  4. *
  5. * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
  6. * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
  7. * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  8. * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  9. *
  10. * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
  11. */
  12. #include <linux/irqchip.h>
  13. #include <linux/irqchip/chained_irq.h>
  14. #include <linux/of_address.h>
  15. #include <linux/of_irq.h>
  16. #define AR71XX_RESET_REG_MISC_INT_STATUS 0
  17. #define AR71XX_RESET_REG_MISC_INT_ENABLE 4
  18. #define ATH79_MISC_IRQ_COUNT 32
  19. #define ATH79_MISC_PERF_IRQ 5
  20. static int ath79_perfcount_irq;
  21. int get_c0_perfcount_int(void)
  22. {
  23. return ath79_perfcount_irq;
  24. }
  25. EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
  26. static void ath79_misc_irq_handler(struct irq_desc *desc)
  27. {
  28. struct irq_domain *domain = irq_desc_get_handler_data(desc);
  29. struct irq_chip *chip = irq_desc_get_chip(desc);
  30. void __iomem *base = domain->host_data;
  31. u32 pending;
  32. chained_irq_enter(chip, desc);
  33. pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
  34. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  35. if (!pending) {
  36. spurious_interrupt();
  37. chained_irq_exit(chip, desc);
  38. return;
  39. }
  40. while (pending) {
  41. int bit = __ffs(pending);
  42. generic_handle_irq(irq_linear_revmap(domain, bit));
  43. pending &= ~BIT(bit);
  44. }
  45. chained_irq_exit(chip, desc);
  46. }
  47. static void ar71xx_misc_irq_unmask(struct irq_data *d)
  48. {
  49. void __iomem *base = irq_data_get_irq_chip_data(d);
  50. unsigned int irq = d->hwirq;
  51. u32 t;
  52. t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  53. __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  54. /* flush write */
  55. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  56. }
  57. static void ar71xx_misc_irq_mask(struct irq_data *d)
  58. {
  59. void __iomem *base = irq_data_get_irq_chip_data(d);
  60. unsigned int irq = d->hwirq;
  61. u32 t;
  62. t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  63. __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  64. /* flush write */
  65. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  66. }
  67. static void ar724x_misc_irq_ack(struct irq_data *d)
  68. {
  69. void __iomem *base = irq_data_get_irq_chip_data(d);
  70. unsigned int irq = d->hwirq;
  71. u32 t;
  72. t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
  73. __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
  74. /* flush write */
  75. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
  76. }
  77. static struct irq_chip ath79_misc_irq_chip = {
  78. .name = "MISC",
  79. .irq_unmask = ar71xx_misc_irq_unmask,
  80. .irq_mask = ar71xx_misc_irq_mask,
  81. };
  82. static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
  83. {
  84. irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq);
  85. irq_set_chip_data(irq, d->host_data);
  86. return 0;
  87. }
  88. static const struct irq_domain_ops misc_irq_domain_ops = {
  89. .xlate = irq_domain_xlate_onecell,
  90. .map = misc_map,
  91. };
  92. static void __init ath79_misc_intc_domain_init(
  93. struct irq_domain *domain, int irq)
  94. {
  95. void __iomem *base = domain->host_data;
  96. ath79_perfcount_irq = irq_create_mapping(domain, ATH79_MISC_PERF_IRQ);
  97. /* Disable and clear all interrupts */
  98. __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  99. __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
  100. irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain);
  101. }
  102. static int __init ath79_misc_intc_of_init(
  103. struct device_node *node, struct device_node *parent)
  104. {
  105. struct irq_domain *domain;
  106. void __iomem *base;
  107. int irq;
  108. irq = irq_of_parse_and_map(node, 0);
  109. if (!irq) {
  110. pr_err("Failed to get MISC IRQ\n");
  111. return -EINVAL;
  112. }
  113. base = of_iomap(node, 0);
  114. if (!base) {
  115. pr_err("Failed to get MISC IRQ registers\n");
  116. return -ENOMEM;
  117. }
  118. domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT,
  119. &misc_irq_domain_ops, base);
  120. if (!domain) {
  121. pr_err("Failed to add MISC irqdomain\n");
  122. return -EINVAL;
  123. }
  124. ath79_misc_intc_domain_init(domain, irq);
  125. return 0;
  126. }
  127. static int __init ar7100_misc_intc_of_init(
  128. struct device_node *node, struct device_node *parent)
  129. {
  130. ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
  131. return ath79_misc_intc_of_init(node, parent);
  132. }
  133. IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",
  134. ar7100_misc_intc_of_init);
  135. static int __init ar7240_misc_intc_of_init(
  136. struct device_node *node, struct device_node *parent)
  137. {
  138. ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
  139. return ath79_misc_intc_of_init(node, parent);
  140. }
  141. IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",
  142. ar7240_misc_intc_of_init);
  143. void __init ath79_misc_irq_init(void __iomem *regs, int irq,
  144. int irq_base, bool is_ar71xx)
  145. {
  146. struct irq_domain *domain;
  147. if (is_ar71xx)
  148. ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
  149. else
  150. ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
  151. domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT,
  152. irq_base, 0, &misc_irq_domain_ops, regs);
  153. if (!domain)
  154. panic("Failed to create MISC irqdomain");
  155. ath79_misc_intc_domain_init(domain, irq);
  156. }