irq-ath79-cpu.c 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Atheros AR71xx/AR724x/AR913x specific interrupt handling
  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/interrupt.h>
  13. #include <linux/irqchip.h>
  14. #include <linux/of.h>
  15. #include <asm/irq_cpu.h>
  16. #include <asm/mach-ath79/ath79.h>
  17. /*
  18. * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
  19. * these devices typically allocate coherent DMA memory, however the
  20. * DMA controller may still have some unsynchronized data in the FIFO.
  21. * Issue a flush in the handlers to ensure that the driver sees
  22. * the update.
  23. *
  24. * This array map the interrupt lines to the DDR write buffer channels.
  25. */
  26. static unsigned irq_wb_chan[8] = {
  27. -1, -1, -1, -1, -1, -1, -1, -1,
  28. };
  29. asmlinkage void plat_irq_dispatch(void)
  30. {
  31. unsigned long pending;
  32. int irq;
  33. pending = read_c0_status() & read_c0_cause() & ST0_IM;
  34. if (!pending) {
  35. spurious_interrupt();
  36. return;
  37. }
  38. pending >>= CAUSEB_IP;
  39. while (pending) {
  40. irq = fls(pending) - 1;
  41. if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1)
  42. ath79_ddr_wb_flush(irq_wb_chan[irq]);
  43. do_IRQ(MIPS_CPU_IRQ_BASE + irq);
  44. pending &= ~BIT(irq);
  45. }
  46. }
  47. static int __init ar79_cpu_intc_of_init(
  48. struct device_node *node, struct device_node *parent)
  49. {
  50. int err, i, count;
  51. /* Fill the irq_wb_chan table */
  52. count = of_count_phandle_with_args(
  53. node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
  54. for (i = 0; i < count; i++) {
  55. struct of_phandle_args args;
  56. u32 irq = i;
  57. of_property_read_u32_index(
  58. node, "qca,ddr-wb-channel-interrupts", i, &irq);
  59. if (irq >= ARRAY_SIZE(irq_wb_chan))
  60. continue;
  61. err = of_parse_phandle_with_args(
  62. node, "qca,ddr-wb-channels",
  63. "#qca,ddr-wb-channel-cells",
  64. i, &args);
  65. if (err)
  66. return err;
  67. irq_wb_chan[irq] = args.args[0];
  68. }
  69. return mips_cpu_irq_of_init(node, parent);
  70. }
  71. IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
  72. ar79_cpu_intc_of_init);
  73. void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)
  74. {
  75. irq_wb_chan[2] = irq_wb_chan2;
  76. irq_wb_chan[3] = irq_wb_chan3;
  77. mips_cpu_irq_init();
  78. }