mtk_iommu.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright (c) 2014 MediaTek Inc.
  3. * Author: YongWu <yong.wu@mediatek.com>
  4. * Honghui Zhang <honghui.zhang@mediatek.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. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/io.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/slab.h>
  19. #include <linux/clk.h>
  20. #include <linux/err.h>
  21. #include <linux/mm.h>
  22. #include <linux/iommu.h>
  23. #include <linux/errno.h>
  24. #include <asm/device.h>
  25. #include <linux/memblock.h>
  26. #include <asm/cacheflush.h>
  27. #include <linux/dma-mapping.h>
  28. #include <asm/dma-iommu.h>
  29. #include <asm/dma-mapping.h>
  30. #include <linux/of_address.h>
  31. #include <linux/of_irq.h>
  32. #include <linux/module.h>
  33. #include "mtk_iommu_platform.h"
  34. #include "mtk_iommu_reg_mt2701.h"
  35. static struct device *pimudev;
  36. static int mtk_iommu_domain_init(struct iommu_domain *domain)
  37. {
  38. struct mtk_iommu_domain *mtk_domain;
  39. mtk_domain = devm_kzalloc(pimudev, sizeof(*mtk_domain), GFP_KERNEL);
  40. if (!mtk_domain)
  41. return -ENOMEM;
  42. mtk_domain->pgtableva = dma_alloc_coherent(pimudev, MTK_IOMMU_PGT_SZ,
  43. &mtk_domain->pgtablepa, GFP_KERNEL);
  44. if (!mtk_domain->pgtableva) {
  45. dev_err(pimudev, "dma_alloc_coherent pagetable fail\n");
  46. return -ENOMEM;
  47. }
  48. if (!IS_ALIGNED(mtk_domain->pgtablepa, MTK_IOMMU_PGT_SZ)) {
  49. dev_err(pimudev, "pagetable not aligned pa 0x%x, va 0x%p align 0x%x\n",
  50. mtk_domain->pgtablepa, mtk_domain->pgtableva,
  51. MTK_IOMMU_PGT_SZ);
  52. dma_free_coherent(pimudev, MTK_IOMMU_PGT_SZ,
  53. mtk_domain->pgtableva, mtk_domain->pgtablepa);
  54. return -ENOMEM;
  55. }
  56. memset(mtk_domain->pgtableva, 0, MTK_IOMMU_PGT_SZ);
  57. spin_lock_init(&mtk_domain->pgtlock);
  58. spin_lock_init(&mtk_domain->portlock);
  59. domain->priv = mtk_domain;
  60. mtk_domain->domain = domain;
  61. return 0;
  62. }
  63. static void mtk_iommu_domain_destroy(struct iommu_domain *domain)
  64. {
  65. struct mtk_iommu_domain *mtk_domain = domain->priv;
  66. dma_free_coherent(mtk_domain->piommuinfo->dev, MTK_IOMMU_PGT_SZ,
  67. mtk_domain->pgtableva, mtk_domain->pgtablepa);
  68. devm_kfree(mtk_domain->piommuinfo->dev, mtk_domain);
  69. domain->priv = NULL;
  70. }
  71. static int mtk_iommu_dev_enable_iommu(struct mtk_iommu_info *imuinfo,
  72. struct device *dev, bool enable)
  73. {
  74. struct of_phandle_args out_args = {0};
  75. struct device *imudev = imuinfo->dev;
  76. int i = 0, ret = 0;
  77. while (!of_parse_phandle_with_args(dev->of_node, "iommus",
  78. "#iommu-cells", i++, &out_args)) {
  79. if (out_args.np != imudev->of_node)
  80. continue;
  81. if (out_args.args_count != 1) {
  82. dev_err(imudev, "invalid #iommu-cells property for IOMMU\n");
  83. return -EINVAL;
  84. }
  85. dev_dbg(imudev, "%s iommu @ port:%d\n",
  86. enable ? "enable" : "disable", out_args.args[0]);
  87. ret = imuinfo->imucfg->config_port(imuinfo,
  88. out_args.args[0], enable);
  89. if (ret) {
  90. dev_err(imudev, "iommu config port error %d\n", ret);
  91. return ret;
  92. }
  93. }
  94. return ret;
  95. }
  96. static int mtk_iommu_attach_device(struct iommu_domain *domain,
  97. struct device *dev)
  98. {
  99. struct mtk_iommu_domain *mtk_domain = domain->priv;
  100. return mtk_iommu_dev_enable_iommu(mtk_domain->piommuinfo, dev, true);
  101. }
  102. static void mtk_iommu_detach_device(struct iommu_domain *domain,
  103. struct device *dev)
  104. {
  105. struct mtk_iommu_domain *mtk_domain = domain->priv;
  106. mtk_iommu_dev_enable_iommu(mtk_domain->piommuinfo, dev, false);
  107. }
  108. /* will parse the dt in probe, this will do nothing */
  109. static int mtk_iommu_add_device(struct device *dev)
  110. {
  111. return 0;
  112. }
  113. static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
  114. phys_addr_t paddr, size_t size, int prot)
  115. {
  116. struct mtk_iommu_domain *priv = domain->priv;
  117. unsigned long flags;
  118. spin_lock_irqsave(&priv->pgtlock, flags);
  119. priv->piommuinfo->imucfg->map(priv, (unsigned int)iova, paddr, size);
  120. spin_unlock_irqrestore(&priv->pgtlock, flags);
  121. return 0;
  122. }
  123. static size_t mtk_iommu_unmap(struct iommu_domain *domain,
  124. unsigned long iova, size_t size)
  125. {
  126. struct mtk_iommu_domain *priv = domain->priv;
  127. unsigned long flags;
  128. int unmapped_size;
  129. spin_lock_irqsave(&priv->pgtlock, flags);
  130. unmapped_size = priv->piommuinfo->imucfg->unmap(priv,
  131. (unsigned int)iova, size);
  132. spin_unlock_irqrestore(&priv->pgtlock, flags);
  133. return unmapped_size;
  134. }
  135. static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
  136. dma_addr_t iova)
  137. {
  138. struct mtk_iommu_domain *priv = domain->priv;
  139. unsigned long flags;
  140. phys_addr_t phys;
  141. spin_lock_irqsave(&priv->pgtlock, flags);
  142. phys = priv->piommuinfo->imucfg->iova_to_phys(priv,
  143. (unsigned int)iova);
  144. spin_unlock_irqrestore(&priv->pgtlock, flags);
  145. return phys;
  146. }
  147. const struct iommu_ops mtk_iommu_ops = {
  148. .domain_init = mtk_iommu_domain_init,
  149. .domain_destroy = mtk_iommu_domain_destroy,
  150. .attach_dev = mtk_iommu_attach_device,
  151. .detach_dev = mtk_iommu_detach_device,
  152. .add_device = mtk_iommu_add_device,
  153. .map = mtk_iommu_map,
  154. .unmap = mtk_iommu_unmap,
  155. .iova_to_phys = mtk_iommu_iova_to_phys,
  156. .pgsize_bitmap = PAGE_SIZE,
  157. };
  158. static const struct of_device_id mtk_iommu_of_ids[] = {
  159. {
  160. .compatible = "mediatek,mt2701-m4u",
  161. .data = &mtk_iommu_mt2701_cfg,
  162. },
  163. { }
  164. };
  165. static int mtk_iommu_probe(struct platform_device *pdev)
  166. {
  167. int ret;
  168. struct dma_iommu_mapping *mtk_mapping;
  169. struct mtk_iommu_info *piommu;
  170. struct iommu_domain *domain;
  171. struct mtk_iommu_domain *mtk_domain;
  172. const struct of_device_id *of_id;
  173. void *protect_va;
  174. piommu = devm_kzalloc(&pdev->dev, sizeof(*piommu), GFP_KERNEL);
  175. if (!piommu)
  176. return -ENOMEM;
  177. of_id = of_match_node(mtk_iommu_of_ids, pdev->dev.of_node);
  178. if (!of_id)
  179. return -ENODEV;
  180. piommu->imucfg = of_id->data;
  181. piommu->dev = &pdev->dev;
  182. ret = piommu->imucfg->dt_parse(pdev, piommu);
  183. if (ret)
  184. return ret;
  185. protect_va = devm_kzalloc(&pdev->dev, MTK_PROTECT_PA_ALIGN*2,
  186. GFP_KERNEL);
  187. if (!protect_va)
  188. return -ENOMEM;
  189. piommu->protect_va = protect_va;
  190. piommu->protect_base = virt_to_phys(piommu->protect_va);
  191. piommu->iova_base = 0;
  192. piommu->iova_size = (MTK_IOMMU_PGT_SZ / sizeof(int))
  193. * MT2701_IOMMU_PAGE_SIZE;
  194. /*
  195. * create mapping will call domain_init, which will use pimudev,
  196. * so this need to be set before calling arm_iommu_create_mapping.
  197. */
  198. pimudev = &pdev->dev;
  199. mtk_mapping = arm_iommu_create_mapping(&platform_bus_type,
  200. piommu->iova_base,
  201. piommu->iova_size);
  202. if (IS_ERR(mtk_mapping))
  203. return PTR_ERR(mtk_mapping);
  204. domain = mtk_mapping->domain;
  205. mtk_domain = domain->priv;
  206. mtk_domain->piommuinfo = piommu;
  207. piommu->pgt_basepa = mtk_domain->pgtablepa;
  208. ret = piommu->imucfg->hw_init(piommu);
  209. if (ret) {
  210. dev_err(piommu->dev, "IOMMU HW init failed\n");
  211. goto err_release_mapping;
  212. }
  213. piommu->dev->archdata.iommu = mtk_mapping;
  214. ret = devm_request_irq(piommu->dev, piommu->irq,
  215. piommu->imucfg->iommu_isr, IRQF_TRIGGER_NONE,
  216. dev_name(piommu->dev), (void *)mtk_domain);
  217. if (ret) {
  218. dev_err(piommu->dev, "IRQ request %d failed\n",
  219. piommu->irq);
  220. goto err_release_mapping;
  221. }
  222. dev_set_drvdata(piommu->dev, piommu);
  223. dev_info(piommu->dev, "iommu probe suc\n");
  224. return 0;
  225. err_release_mapping:
  226. piommu->dev->archdata.iommu = NULL;
  227. arm_iommu_release_mapping(mtk_mapping);
  228. piommu->imucfg->hw_deinit(piommu);
  229. pimudev = NULL;
  230. return ret;
  231. }
  232. static int mtk_iommu_remove(struct platform_device *pdev)
  233. {
  234. struct dma_iommu_mapping *mtk_mapping;
  235. struct mtk_iommu_info *piommu = dev_get_drvdata(&pdev->dev);
  236. dev_info(piommu->dev, "iommu_remove\n");
  237. mtk_mapping = to_dma_iommu_mapping(&pdev->dev);
  238. arm_iommu_release_mapping(mtk_mapping);
  239. return 0;
  240. }
  241. static struct platform_driver mtk_iommu_driver = {
  242. .probe = mtk_iommu_probe,
  243. .remove = mtk_iommu_remove,
  244. .driver = {
  245. .name = "mtk-iommu",
  246. .of_match_table = mtk_iommu_of_ids,
  247. }
  248. };
  249. static int __init mtk_iommu_init(void)
  250. {
  251. int ret;
  252. ret = bus_set_iommu(&platform_bus_type, &mtk_iommu_ops);
  253. if (ret)
  254. return ret;
  255. ret = platform_driver_register(&mtk_iommu_driver);
  256. if (ret)
  257. bus_set_iommu(&platform_bus_type, NULL);
  258. return ret;
  259. }
  260. subsys_initcall(mtk_iommu_init);
  261. MODULE_AUTHOR("Yong Wu <yong.wu@mediatek.com>");
  262. MODULE_AUTHOR("Honghui Zhang <honghui.zhang@mediatek.com>");
  263. MODULE_DESCRIPTION("IOMMU API for MTK architected implementations");
  264. MODULE_LICENSE("GPL v2");