mtk-gic-extend.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2015 MediaTek Inc.
  3. * Author: Maoguang.Meng <maoguang.meng@mediatek.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/device.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/module.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/module.h>
  20. #include <linux/uaccess.h>
  21. #include <linux/slab.h>
  22. #include <linux/cpu.h>
  23. #include <linux/smp.h>
  24. #include <linux/types.h>
  25. #include <linux/irqchip/arm-gic.h>
  26. #include <linux/of.h>
  27. #include <linux/of_address.h>
  28. #include <linux/of_irq.h>
  29. #include <linux/irqchip/mtk-gic-extend.h>
  30. void __iomem *GIC_DIST_BASE;
  31. void __iomem *INT_POL_CTL0;
  32. /*
  33. * mt_irq_mask_all: disable all interrupts
  34. * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
  35. * Return 0 for success; return negative values for failure.
  36. * (This is ONLY used for the idle current measurement by the factory mode.)
  37. */
  38. int mt_irq_mask_all(struct mtk_irq_mask *mask)
  39. {
  40. void __iomem *dist_base;
  41. dist_base = GIC_DIST_BASE;
  42. if (mask) {
  43. /*
  44. #if defined(CONFIG_FIQ_GLUE)
  45. local_fiq_disable();
  46. #endif
  47. */
  48. mask->mask0 = readl((dist_base + GIC_DIST_ENABLE_SET));
  49. mask->mask1 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x4));
  50. mask->mask2 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x8));
  51. mask->mask3 = readl((dist_base + GIC_DIST_ENABLE_SET + 0xC));
  52. mask->mask4 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x10));
  53. mask->mask5 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x14));
  54. mask->mask6 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x18));
  55. mask->mask7 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x1C));
  56. mask->mask8 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x20));
  57. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR));
  58. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x4));
  59. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x8));
  60. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0xC));
  61. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x10));
  62. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x14));
  63. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x18));
  64. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x1C));
  65. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x20));
  66. mb();
  67. /*
  68. #if defined(CONFIG_FIQ_GLUE)
  69. local_fiq_enable();
  70. #endif
  71. */
  72. mask->header = IRQ_MASK_HEADER;
  73. mask->footer = IRQ_MASK_FOOTER;
  74. return 0;
  75. } else {
  76. return -1;
  77. }
  78. }
  79. /*
  80. * mt_irq_mask_restore: restore all interrupts
  81. * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
  82. * Return 0 for success; return negative values for failure.
  83. * (This is ONLY used for the idle current measurement by the factory mode.)
  84. */
  85. int mt_irq_mask_restore(struct mtk_irq_mask *mask)
  86. {
  87. void __iomem *dist_base;
  88. dist_base = GIC_DIST_BASE;
  89. if (!mask)
  90. return -1;
  91. if (mask->header != IRQ_MASK_HEADER)
  92. return -1;
  93. if (mask->footer != IRQ_MASK_FOOTER)
  94. return -1;
  95. /*
  96. #if defined(CONFIG_FIQ_GLUE)
  97. local_fiq_disable();
  98. #endif
  99. */
  100. writel(mask->mask0, (dist_base + GIC_DIST_ENABLE_SET));
  101. writel(mask->mask1, (dist_base + GIC_DIST_ENABLE_SET + 0x4));
  102. writel(mask->mask2, (dist_base + GIC_DIST_ENABLE_SET + 0x8));
  103. writel(mask->mask3, (dist_base + GIC_DIST_ENABLE_SET + 0xC));
  104. writel(mask->mask4, (dist_base + GIC_DIST_ENABLE_SET + 0x10));
  105. writel(mask->mask5, (dist_base + GIC_DIST_ENABLE_SET + 0x14));
  106. writel(mask->mask6, (dist_base + GIC_DIST_ENABLE_SET + 0x18));
  107. writel(mask->mask7, (dist_base + GIC_DIST_ENABLE_SET + 0x1C));
  108. writel(mask->mask8, (dist_base + GIC_DIST_ENABLE_SET + 0x20));
  109. mb();
  110. /*
  111. #if defined(CONFIG_FIQ_GLUE)
  112. local_fiq_enable();
  113. #endif
  114. */
  115. return 0;
  116. }
  117. /*
  118. * mt_irq_set_pending_for_sleep: pending an interrupt for the sleep manager's use
  119. * @irq: interrupt id
  120. * (THIS IS ONLY FOR SLEEP FUNCTION USE. DO NOT USE IT YOURSELF!)
  121. */
  122. void mt_irq_set_pending_for_sleep(unsigned int irq)
  123. {
  124. void __iomem *dist_base;
  125. u32 mask = 1 << (irq % 32);
  126. dist_base = GIC_DIST_BASE;
  127. if (irq < 16) {
  128. pr_err("Fail to set a pending on interrupt %d\n", irq);
  129. return;
  130. }
  131. writel(mask, dist_base + GIC_DIST_PENDING_SET + irq / 32 * 4);
  132. pr_debug("irq:%d, 0x%p=0x%x\n", irq,
  133. dist_base + GIC_DIST_PENDING_SET + irq / 32 * 4, mask);
  134. mb();
  135. }
  136. u32 mt_irq_get_pending(unsigned int irq)
  137. {
  138. void __iomem *dist_base;
  139. u32 bit = 1 << (irq % 32);
  140. dist_base = GIC_DIST_BASE;
  141. return (readl_relaxed(dist_base + GIC_DIST_PENDING_SET + irq / 32 * 4) & bit) ? 1 : 0;
  142. }
  143. void mt_irq_set_pending(unsigned int irq)
  144. {
  145. void __iomem *dist_base;
  146. u32 bit = 1 << (irq % 32);
  147. dist_base = GIC_DIST_BASE;
  148. writel(bit, dist_base + GIC_DIST_PENDING_SET + irq / 32 * 4);
  149. }
  150. /*
  151. * mt_irq_unmask_for_sleep: enable an interrupt for the sleep manager's use
  152. * @irq: interrupt id
  153. * (THIS IS ONLY FOR SLEEP FUNCTION USE. DO NOT USE IT YOURSELF!)
  154. */
  155. void mt_irq_unmask_for_sleep(unsigned int irq)
  156. {
  157. void __iomem *dist_base;
  158. u32 mask = 1 << (irq % 32);
  159. dist_base = GIC_DIST_BASE;
  160. if (irq < 16) {
  161. pr_err("Fail to enable interrupt %d\n", irq);
  162. return;
  163. }
  164. writel(mask, dist_base + GIC_DIST_ENABLE_SET + irq / 32 * 4);
  165. mb();
  166. }
  167. /*
  168. * mt_irq_mask_for_sleep: disable an interrupt for the sleep manager's use
  169. * @irq: interrupt id
  170. * (THIS IS ONLY FOR SLEEP FUNCTION USE. DO NOT USE IT YOURSELF!)
  171. */
  172. void mt_irq_mask_for_sleep(unsigned int irq)
  173. {
  174. void __iomem *dist_base;
  175. u32 mask = 1 << (irq % 32);
  176. dist_base = GIC_DIST_BASE;
  177. if (irq < 16) {
  178. pr_err("Fail to enable interrupt %d\n", irq);
  179. return;
  180. }
  181. writel(mask, dist_base + GIC_DIST_ENABLE_CLEAR + irq / 32 * 4);
  182. mb();
  183. }
  184. static int __init mtk_gic_ext_init(void)
  185. {
  186. struct device_node *node;
  187. node = of_find_compatible_node(NULL, NULL, "arm,gic-400");
  188. if (!node) {
  189. pr_err("[gic_ext] find arm,gic-400 node failed\n");
  190. return -EINVAL;
  191. }
  192. GIC_DIST_BASE = of_iomap(node, 0);
  193. if (IS_ERR(GIC_DIST_BASE))
  194. return -EINVAL;
  195. node = of_find_compatible_node(NULL, NULL, "mediatek,mt6577-sysirq");
  196. if (!node) {
  197. pr_err("[gic_ext] find arm,gic-400 node failed\n");
  198. return -EINVAL;
  199. }
  200. INT_POL_CTL0 = of_iomap(node, 0);
  201. if (IS_ERR(INT_POL_CTL0))
  202. return -EINVAL;
  203. return 0;
  204. }
  205. module_init(mtk_gic_ext_init);
  206. MODULE_LICENSE("GPL v2");
  207. MODULE_DESCRIPTION("MediaTek gic extend Driver");
  208. MODULE_AUTHOR("Maoguang Meng <maoguang.meng@mediatek.com>");