mtk-gic-v3-extend.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * Copyright (c) 2015 MediaTek Inc.
  3. * Author: Mars.Cheng <mars.cheng@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/sizes.h>
  30. #include <linux/irqchip/mtk-gic-extend.h>
  31. /* for cirq use */
  32. void __iomem *GIC_DIST_BASE;
  33. void __iomem *INT_POL_CTL0;
  34. void __iomem *INT_POL_CTL1;
  35. static void __iomem *GIC_REDIST_BASE;
  36. static int gic_populate_rdist(void __iomem **rdist_base)
  37. {
  38. int cpu = smp_processor_id();
  39. *rdist_base = GIC_REDIST_BASE + cpu*SZ_64K*2;
  40. return 0;
  41. }
  42. u32 mt_irq_get_pol(u32 irq)
  43. {
  44. u32 reg_index = 0;
  45. reg_index = (irq - 32) >> 5;
  46. /* FIXME: need to use more flexible way to
  47. * get non-continuous POL registers */
  48. if (reg_index >= 8) {
  49. reg_index -= 8;
  50. reg_index += 0x70/4;
  51. }
  52. return readl(INT_POL_CTL0 + reg_index*4);
  53. }
  54. /*
  55. * mt_irq_mask_all: disable all interrupts
  56. * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
  57. * Return 0 for success; return negative values for failure.
  58. * (This is ONLY used for the idle current measurement by the factory mode.)
  59. */
  60. int mt_irq_mask_all(struct mtk_irq_mask *mask)
  61. {
  62. void __iomem *dist_base;
  63. void __iomem *redist_base;
  64. dist_base = GIC_DIST_BASE;
  65. gic_populate_rdist(&redist_base);
  66. redist_base += SZ_64K;
  67. if (mask) {
  68. /* for SGI & PPI */
  69. mask->mask0 = readl((redist_base + GIC_DIST_ENABLE_SET));
  70. /* for SPI */
  71. mask->mask1 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x4));
  72. mask->mask2 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x8));
  73. mask->mask3 = readl((dist_base + GIC_DIST_ENABLE_SET + 0xc));
  74. mask->mask4 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x10));
  75. mask->mask5 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x14));
  76. mask->mask6 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x18));
  77. mask->mask7 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x1c));
  78. mask->mask8 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x20));
  79. mask->mask9 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x24));
  80. mask->mask10 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x28));
  81. mask->mask11 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x2c));
  82. mask->mask12 = readl((dist_base + GIC_DIST_ENABLE_SET + 0x30));
  83. /* for SGI & PPI */
  84. writel(0xFFFFFFFF, (redist_base + GIC_DIST_ENABLE_CLEAR));
  85. /* for SPI */
  86. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x4));
  87. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x8));
  88. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0xC));
  89. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x10));
  90. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x14));
  91. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x18));
  92. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x1C));
  93. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x20));
  94. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x24));
  95. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x28));
  96. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x2c));
  97. writel(0xFFFFFFFF, (dist_base + GIC_DIST_ENABLE_CLEAR + 0x30));
  98. mb();
  99. mask->header = IRQ_MASK_HEADER;
  100. mask->footer = IRQ_MASK_FOOTER;
  101. return 0;
  102. } else {
  103. return -1;
  104. }
  105. }
  106. /*
  107. * mt_irq_mask_restore: restore all interrupts
  108. * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
  109. * Return 0 for success; return negative values for failure.
  110. * (This is ONLY used for the idle current measurement by the factory mode.)
  111. */
  112. int mt_irq_mask_restore(struct mtk_irq_mask *mask)
  113. {
  114. void __iomem *dist_base;
  115. void __iomem *redist_base;
  116. dist_base = GIC_DIST_BASE;
  117. gic_populate_rdist(&redist_base);
  118. redist_base += SZ_64K;
  119. if (!mask)
  120. return -1;
  121. if (mask->header != IRQ_MASK_HEADER)
  122. return -1;
  123. if (mask->footer != IRQ_MASK_FOOTER)
  124. return -1;
  125. writel(mask->mask0, (redist_base + GIC_DIST_ENABLE_SET));
  126. writel(mask->mask1, (dist_base + GIC_DIST_ENABLE_SET + 0x4));
  127. writel(mask->mask2, (dist_base + GIC_DIST_ENABLE_SET + 0x8));
  128. writel(mask->mask3, (dist_base + GIC_DIST_ENABLE_SET + 0xc));
  129. writel(mask->mask4, (dist_base + GIC_DIST_ENABLE_SET + 0x10));
  130. writel(mask->mask5, (dist_base + GIC_DIST_ENABLE_SET + 0x14));
  131. writel(mask->mask6, (dist_base + GIC_DIST_ENABLE_SET + 0x18));
  132. writel(mask->mask7, (dist_base + GIC_DIST_ENABLE_SET + 0x1c));
  133. writel(mask->mask8, (dist_base + GIC_DIST_ENABLE_SET + 0x20));
  134. writel(mask->mask9, (dist_base + GIC_DIST_ENABLE_SET + 0x24));
  135. writel(mask->mask10, (dist_base + GIC_DIST_ENABLE_SET + 0x28));
  136. writel(mask->mask11, (dist_base + GIC_DIST_ENABLE_SET + 0x2c));
  137. writel(mask->mask12, (dist_base + GIC_DIST_ENABLE_SET + 0x30));
  138. mb();
  139. return 0;
  140. }
  141. u32 mt_irq_get_pending(unsigned int irq)
  142. {
  143. void __iomem *base;
  144. u32 bit = 1 << (irq % 32);
  145. if (irq >= 32) {
  146. base = GIC_DIST_BASE;
  147. } else {
  148. gic_populate_rdist(&base);
  149. base += SZ_64K;
  150. }
  151. return (readl_relaxed(base + GIC_DIST_PENDING_SET + (irq/32)*4)&bit) ?
  152. 1 : 0;
  153. }
  154. void mt_irq_set_pending(unsigned int irq)
  155. {
  156. void __iomem *base;
  157. u32 bit = 1 << (irq % 32);
  158. if (irq >= 32) {
  159. base = GIC_DIST_BASE;
  160. } else {
  161. gic_populate_rdist(&base);
  162. base += SZ_64K;
  163. }
  164. writel(bit, base + GIC_DIST_PENDING_SET + (irq/32)*4);
  165. }
  166. /*
  167. * mt_irq_unmask_for_sleep: enable an interrupt for the sleep manager's use
  168. * @irq: interrupt id
  169. * (THIS IS ONLY FOR SLEEP FUNCTION USE. DO NOT USE IT YOURSELF!)
  170. */
  171. void mt_irq_unmask_for_sleep(unsigned int irq)
  172. {
  173. void __iomem *dist_base;
  174. u32 mask = 1 << (irq % 32);
  175. dist_base = GIC_DIST_BASE;
  176. if (irq < 16) {
  177. pr_err("Fail to enable interrupt %d\n", irq);
  178. return;
  179. }
  180. writel(mask, dist_base + GIC_DIST_ENABLE_SET + irq / 32 * 4);
  181. mb();
  182. }
  183. /*
  184. * mt_irq_mask_for_sleep: disable an interrupt for the sleep manager's use
  185. * @irq: interrupt id
  186. * (THIS IS ONLY FOR SLEEP FUNCTION USE. DO NOT USE IT YOURSELF!)
  187. */
  188. void mt_irq_mask_for_sleep(unsigned int irq)
  189. {
  190. void __iomem *dist_base;
  191. u32 mask = 1 << (irq % 32);
  192. dist_base = GIC_DIST_BASE;
  193. if (irq < 16) {
  194. pr_err("Fail to enable interrupt %d\n", irq);
  195. return;
  196. }
  197. writel(mask, dist_base + GIC_DIST_ENABLE_CLEAR + irq / 32 * 4);
  198. mb();
  199. }
  200. static int __init mt_gic_ext_init(void)
  201. {
  202. struct device_node *node;
  203. node = of_find_compatible_node(NULL, NULL, "arm,gic-v3");
  204. if (!node) {
  205. pr_err("[gic_ext] find arm,gic-v3 node failed\n");
  206. return -EINVAL;
  207. }
  208. GIC_DIST_BASE = of_iomap(node, 0);
  209. if (IS_ERR(GIC_DIST_BASE))
  210. return -EINVAL;
  211. GIC_REDIST_BASE = of_iomap(node, 1);
  212. if (IS_ERR(GIC_REDIST_BASE))
  213. return -EINVAL;
  214. INT_POL_CTL0 = of_iomap(node, 2);
  215. if (IS_ERR(INT_POL_CTL0))
  216. return -EINVAL;
  217. /* if INT_POL_CTL1 get NULL,
  218. * only means no extra polarity register,
  219. * INT_POL_CTL0 is enough */
  220. INT_POL_CTL1 = of_iomap(node, 3);
  221. pr_warn("### gic-v3 init done. ###\n");
  222. return 0;
  223. }
  224. module_init(mt_gic_ext_init);
  225. MODULE_LICENSE("GPL v2");
  226. MODULE_DESCRIPTION("MediaTek gicv3 extend Driver");