irq-ath79-cpu.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Atheros AR71xx/AR724x/AR913x specific interrupt handling
  3. *
  4. * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
  5. * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
  6. * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  7. * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  8. *
  9. * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
  10. *
  11. * This program is free software; you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License version 2 as published
  13. * by the Free Software Foundation.
  14. */
  15. #include <linux/interrupt.h>
  16. #include <linux/irqchip.h>
  17. #include <linux/of.h>
  18. #include <asm/irq_cpu.h>
  19. #include <asm/mach-ath79/ath79.h>
  20. /*
  21. * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
  22. * these devices typically allocate coherent DMA memory, however the
  23. * DMA controller may still have some unsynchronized data in the FIFO.
  24. * Issue a flush in the handlers to ensure that the driver sees
  25. * the update.
  26. *
  27. * This array map the interrupt lines to the DDR write buffer channels.
  28. */
  29. static unsigned irq_wb_chan[8] = {
  30. -1, -1, -1, -1, -1, -1, -1, -1,
  31. };
  32. asmlinkage void plat_irq_dispatch(void)
  33. {
  34. unsigned long pending;
  35. int irq;
  36. pending = read_c0_status() & read_c0_cause() & ST0_IM;
  37. if (!pending) {
  38. spurious_interrupt();
  39. return;
  40. }
  41. pending >>= CAUSEB_IP;
  42. while (pending) {
  43. irq = fls(pending) - 1;
  44. if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1)
  45. ath79_ddr_wb_flush(irq_wb_chan[irq]);
  46. do_IRQ(MIPS_CPU_IRQ_BASE + irq);
  47. pending &= ~BIT(irq);
  48. }
  49. }
  50. static int __init ar79_cpu_intc_of_init(
  51. struct device_node *node, struct device_node *parent)
  52. {
  53. int err, i, count;
  54. /* Fill the irq_wb_chan table */
  55. count = of_count_phandle_with_args(
  56. node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
  57. for (i = 0; i < count; i++) {
  58. struct of_phandle_args args;
  59. u32 irq = i;
  60. of_property_read_u32_index(
  61. node, "qca,ddr-wb-channel-interrupts", i, &irq);
  62. if (irq >= ARRAY_SIZE(irq_wb_chan))
  63. continue;
  64. err = of_parse_phandle_with_args(
  65. node, "qca,ddr-wb-channels",
  66. "#qca,ddr-wb-channel-cells",
  67. i, &args);
  68. if (err)
  69. return err;
  70. irq_wb_chan[irq] = args.args[0];
  71. }
  72. return mips_cpu_irq_of_init(node, parent);
  73. }
  74. IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
  75. ar79_cpu_intc_of_init);
  76. void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)
  77. {
  78. irq_wb_chan[2] = irq_wb_chan2;
  79. irq_wb_chan[3] = irq_wb_chan3;
  80. mips_cpu_irq_init();
  81. }