sysmmu.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /* linux/arch/arm/plat-s5p/sysmmu.c
  2. *
  3. * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  4. * http://www.samsung.com
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/io.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/platform_device.h>
  13. #include <mach/map.h>
  14. #include <mach/regs-sysmmu.h>
  15. #include <mach/sysmmu.h>
  16. struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
  17. void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
  18. {
  19. unsigned int reg_mmu_ctrl;
  20. unsigned int reg_mmu_status;
  21. unsigned int reg_pt_base_addr;
  22. unsigned int reg_int_status;
  23. unsigned int reg_page_ft_addr;
  24. reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
  25. reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
  26. reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
  27. reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
  28. reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
  29. printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
  30. printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
  31. printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
  32. printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
  33. switch (reg_int_status & 0xFF) {
  34. case 0x1:
  35. printk(KERN_INFO "%s: Page fault\n", __func__);
  36. printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
  37. break;
  38. case 0x2:
  39. printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
  40. break;
  41. case 0x4:
  42. printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
  43. break;
  44. case 0x8:
  45. printk(KERN_INFO "%s: Bus error\n", __func__);
  46. break;
  47. case 0x10:
  48. printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
  49. break;
  50. case 0x20:
  51. printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
  52. break;
  53. case 0x40:
  54. printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
  55. break;
  56. case 0x80:
  57. printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
  58. break;
  59. }
  60. }
  61. static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
  62. {
  63. unsigned int i;
  64. unsigned int reg_int_status;
  65. struct sysmmu_controller *sysmmuconp;
  66. for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
  67. sysmmuconp = &s5p_sysmmu_cntlrs[i];
  68. if (sysmmuconp->enable == true) {
  69. reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
  70. if (reg_int_status & 0xFF)
  71. s5p_sysmmu_register(sysmmuconp);
  72. }
  73. }
  74. return IRQ_HANDLED;
  75. }
  76. int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
  77. {
  78. struct sysmmu_controller *sysmmuconp = NULL;
  79. sysmmuconp = &s5p_sysmmu_cntlrs[ips];
  80. if (sysmmuconp == NULL) {
  81. printk(KERN_ERR "failed to get ip's sysmmu info\n");
  82. return 1;
  83. }
  84. /* Set sysmmu page table base address */
  85. __raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
  86. if (s5p_sysmmu_tlb_invalidate(ips) != 0)
  87. printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
  88. return 0;
  89. }
  90. static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
  91. {
  92. unsigned int pg;
  93. struct sysmmu_controller *sysmmuconp;
  94. sysmmuconp = &s5p_sysmmu_cntlrs[ips];
  95. if (sysmmuconp == NULL) {
  96. printk(KERN_ERR "failed to get ip's sysmmu info\n");
  97. return 1;
  98. }
  99. __asm__("mrc p15, 0, %0, c2, c0, 0" \
  100. : "=r" (pg) : : "cc"); \
  101. pg &= ~0x3fff;
  102. printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
  103. /* Set sysmmu page table base address */
  104. __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
  105. return 0;
  106. }
  107. int s5p_sysmmu_enable(sysmmu_ips ips)
  108. {
  109. unsigned int reg;
  110. struct sysmmu_controller *sysmmuconp;
  111. sysmmuconp = &s5p_sysmmu_cntlrs[ips];
  112. if (sysmmuconp == NULL) {
  113. printk(KERN_ERR "failed to get ip's sysmmu info\n");
  114. return 1;
  115. }
  116. s5p_sysmmu_set_tablebase(ips);
  117. /* replacement policy : LRU */
  118. reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
  119. reg |= 0x1;
  120. __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
  121. /* Enable interrupt, Enable MMU */
  122. reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
  123. reg |= (0x1 << 2) | (0x1 << 0);
  124. __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
  125. sysmmuconp->enable = true;
  126. return 0;
  127. }
  128. int s5p_sysmmu_disable(sysmmu_ips ips)
  129. {
  130. unsigned int reg;
  131. struct sysmmu_controller *sysmmuconp = NULL;
  132. if (ips > S5P_SYSMMU_TOTAL_IPNUM)
  133. printk(KERN_ERR "failed to get ips parameter\n");
  134. sysmmuconp = &s5p_sysmmu_cntlrs[ips];
  135. if (sysmmuconp == NULL) {
  136. printk(KERN_ERR "failed to get ip's sysmmu info\n");
  137. return 1;
  138. }
  139. reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
  140. /* replacement policy : LRU */
  141. reg |= 0x1;
  142. __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
  143. reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
  144. /* Disable MMU */
  145. reg &= ~0x1;
  146. __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
  147. sysmmuconp->enable = false;
  148. return 0;
  149. }
  150. int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
  151. {
  152. unsigned int reg;
  153. struct sysmmu_controller *sysmmuconp = NULL;
  154. sysmmuconp = &s5p_sysmmu_cntlrs[ips];
  155. if (sysmmuconp == NULL) {
  156. printk(KERN_ERR "failed to get ip's sysmmu info\n");
  157. return 1;
  158. }
  159. /* set Block MMU for flush TLB */
  160. reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
  161. reg |= 0x1 << 1;
  162. __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
  163. /* flush all TLB entry */
  164. __raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH);
  165. /* set Un-block MMU after flush TLB */
  166. reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
  167. reg &= ~(0x1 << 1);
  168. __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
  169. return 0;
  170. }
  171. static int s5p_sysmmu_probe(struct platform_device *pdev)
  172. {
  173. int i;
  174. int ret;
  175. struct resource *res;
  176. struct sysmmu_controller *sysmmuconp;
  177. sysmmu_ips ips;
  178. for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
  179. sysmmuconp = &s5p_sysmmu_cntlrs[i];
  180. if (sysmmuconp == NULL) {
  181. printk(KERN_ERR "failed to get ip's sysmmu info\n");
  182. ret = -ENOENT;
  183. goto err_res;
  184. }
  185. sysmmuconp->name = sysmmu_ips_name[i];
  186. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  187. if (!res) {
  188. printk(KERN_ERR "failed to get sysmmu resource\n");
  189. ret = -ENODEV;
  190. goto err_res;
  191. }
  192. sysmmuconp->mem = request_mem_region(res->start,
  193. ((res->end) - (res->start)) + 1, pdev->name);
  194. if (!sysmmuconp->mem) {
  195. pr_err("failed to request sysmmu memory region\n");
  196. ret = -EBUSY;
  197. goto err_res;
  198. }
  199. sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1);
  200. if (!sysmmuconp->regs) {
  201. pr_err("failed to sysmmu ioremap\n");
  202. ret = -ENXIO;
  203. goto err_reg;
  204. }
  205. sysmmuconp->irq = platform_get_irq(pdev, i);
  206. if (sysmmuconp->irq <= 0) {
  207. pr_err("failed to get sysmmu irq resource\n");
  208. ret = -ENOENT;
  209. goto err_map;
  210. }
  211. ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp);
  212. if (ret) {
  213. pr_err("failed to request irq\n");
  214. ret = -ENOENT;
  215. goto err_map;
  216. }
  217. ips = (sysmmu_ips)i;
  218. sysmmuconp->ips = ips;
  219. }
  220. return 0;
  221. err_reg:
  222. release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
  223. err_map:
  224. iounmap(sysmmuconp->regs);
  225. err_res:
  226. return ret;
  227. }
  228. static int s5p_sysmmu_remove(struct platform_device *pdev)
  229. {
  230. return 0;
  231. }
  232. int s5p_sysmmu_runtime_suspend(struct device *dev)
  233. {
  234. return 0;
  235. }
  236. int s5p_sysmmu_runtime_resume(struct device *dev)
  237. {
  238. return 0;
  239. }
  240. const struct dev_pm_ops s5p_sysmmu_pm_ops = {
  241. .runtime_suspend = s5p_sysmmu_runtime_suspend,
  242. .runtime_resume = s5p_sysmmu_runtime_resume,
  243. };
  244. static struct platform_driver s5p_sysmmu_driver = {
  245. .probe = s5p_sysmmu_probe,
  246. .remove = s5p_sysmmu_remove,
  247. .driver = {
  248. .owner = THIS_MODULE,
  249. .name = "s5p-sysmmu",
  250. .pm = &s5p_sysmmu_pm_ops,
  251. }
  252. };
  253. static int __init s5p_sysmmu_init(void)
  254. {
  255. return platform_driver_register(&s5p_sysmmu_driver);
  256. }
  257. arch_initcall(s5p_sysmmu_init);