irq-goldfish-pic.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * Driver for MIPS Goldfish Programmable Interrupt Controller.
  3. *
  4. * Author: Miodrag Dinic <miodrag.dinic@mips.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version.
  10. */
  11. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12. #include <linux/interrupt.h>
  13. #include <linux/irq.h>
  14. #include <linux/irqchip.h>
  15. #include <linux/irqchip/chained_irq.h>
  16. #include <linux/irqdomain.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of_irq.h>
  19. #define GFPIC_NR_IRQS 32
  20. /* 8..39 Cascaded Goldfish PIC interrupts */
  21. #define GFPIC_IRQ_BASE 8
  22. #define GFPIC_REG_IRQ_PENDING 0x04
  23. #define GFPIC_REG_IRQ_DISABLE_ALL 0x08
  24. #define GFPIC_REG_IRQ_DISABLE 0x0c
  25. #define GFPIC_REG_IRQ_ENABLE 0x10
  26. struct goldfish_pic_data {
  27. void __iomem *base;
  28. struct irq_domain *irq_domain;
  29. };
  30. static void goldfish_pic_cascade(struct irq_desc *desc)
  31. {
  32. struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc);
  33. struct irq_chip *host_chip = irq_desc_get_chip(desc);
  34. u32 pending, hwirq, virq;
  35. chained_irq_enter(host_chip, desc);
  36. pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING);
  37. while (pending) {
  38. hwirq = __fls(pending);
  39. virq = irq_linear_revmap(gfpic->irq_domain, hwirq);
  40. generic_handle_irq(virq);
  41. pending &= ~(1 << hwirq);
  42. }
  43. chained_irq_exit(host_chip, desc);
  44. }
  45. static const struct irq_domain_ops goldfish_irq_domain_ops = {
  46. .xlate = irq_domain_xlate_onecell,
  47. };
  48. static int __init goldfish_pic_of_init(struct device_node *of_node,
  49. struct device_node *parent)
  50. {
  51. struct goldfish_pic_data *gfpic;
  52. struct irq_chip_generic *gc;
  53. struct irq_chip_type *ct;
  54. unsigned int parent_irq;
  55. int ret = 0;
  56. gfpic = kzalloc(sizeof(*gfpic), GFP_KERNEL);
  57. if (!gfpic) {
  58. ret = -ENOMEM;
  59. goto out_err;
  60. }
  61. parent_irq = irq_of_parse_and_map(of_node, 0);
  62. if (!parent_irq) {
  63. pr_err("Failed to map parent IRQ!\n");
  64. ret = -EINVAL;
  65. goto out_free;
  66. }
  67. gfpic->base = of_iomap(of_node, 0);
  68. if (!gfpic->base) {
  69. pr_err("Failed to map base address!\n");
  70. ret = -ENOMEM;
  71. goto out_unmap_irq;
  72. }
  73. /* Mask interrupts. */
  74. writel(1, gfpic->base + GFPIC_REG_IRQ_DISABLE_ALL);
  75. gc = irq_alloc_generic_chip("GFPIC", 1, GFPIC_IRQ_BASE, gfpic->base,
  76. handle_level_irq);
  77. if (!gc) {
  78. pr_err("Failed to allocate chip structures!\n");
  79. ret = -ENOMEM;
  80. goto out_iounmap;
  81. }
  82. ct = gc->chip_types;
  83. ct->regs.enable = GFPIC_REG_IRQ_ENABLE;
  84. ct->regs.disable = GFPIC_REG_IRQ_DISABLE;
  85. ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
  86. ct->chip.irq_mask = irq_gc_mask_disable_reg;
  87. irq_setup_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), 0,
  88. IRQ_NOPROBE | IRQ_LEVEL, 0);
  89. gfpic->irq_domain = irq_domain_add_legacy(of_node, GFPIC_NR_IRQS,
  90. GFPIC_IRQ_BASE, 0,
  91. &goldfish_irq_domain_ops,
  92. NULL);
  93. if (!gfpic->irq_domain) {
  94. pr_err("Failed to add irqdomain!\n");
  95. ret = -ENOMEM;
  96. goto out_destroy_generic_chip;
  97. }
  98. irq_set_chained_handler_and_data(parent_irq,
  99. goldfish_pic_cascade, gfpic);
  100. pr_info("Successfully registered.\n");
  101. return 0;
  102. out_destroy_generic_chip:
  103. irq_destroy_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS),
  104. IRQ_NOPROBE | IRQ_LEVEL, 0);
  105. out_iounmap:
  106. iounmap(gfpic->base);
  107. out_unmap_irq:
  108. irq_dispose_mapping(parent_irq);
  109. out_free:
  110. kfree(gfpic);
  111. out_err:
  112. pr_err("Failed to initialize! (errno = %d)\n", ret);
  113. return ret;
  114. }
  115. IRQCHIP_DECLARE(google_gf_pic, "google,goldfish-pic", goldfish_pic_of_init);