From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/iommu/mtk_iommu_v1.c | 181 ++++++++++++++++++++++----------------------- 1 files changed, 89 insertions(+), 92 deletions(-) diff --git a/kernel/drivers/iommu/mtk_iommu_v1.c b/kernel/drivers/iommu/mtk_iommu_v1.c index 676c029..2abbdd7 100644 --- a/kernel/drivers/iommu/mtk_iommu_v1.c +++ b/kernel/drivers/iommu/mtk_iommu_v1.c @@ -1,19 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only /* + * IOMMU API for MTK architected m4u v1 implementations + * * Copyright (c) 2015-2016 MediaTek Inc. * Author: Honghui Zhang <honghui.zhang@mediatek.com> * * Based on driver/iommu/mtk_iommu.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <linux/bootmem.h> +#include <linux/memblock.h> #include <linux/bug.h> #include <linux/clk.h> #include <linux/component.h> @@ -35,7 +29,7 @@ #include <linux/spinlock.h> #include <asm/barrier.h> #include <asm/dma-iommu.h> -#include <linux/module.h> +#include <linux/init.h> #include <dt-bindings/memory/mt2701-larb-port.h> #include <soc/mediatek/smi.h> #include "mtk_iommu.h" @@ -206,13 +200,13 @@ { struct mtk_smi_larb_iommu *larb_mmu; unsigned int larbid, portid; - struct iommu_fwspec *fwspec = dev->iommu_fwspec; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); int i; for (i = 0; i < fwspec->num_ids; ++i) { larbid = mt2701_m4u_to_larb(fwspec->ids[i]); portid = mt2701_m4u_to_port(fwspec->ids[i]); - larb_mmu = &data->smi_imu.larb_imu[larbid]; + larb_mmu = &data->larb_imu[larbid]; dev_dbg(dev, "%s iommu port: %d\n", enable ? "enable" : "disable", portid); @@ -230,9 +224,8 @@ spin_lock_init(&dom->pgtlock); - dom->pgt_va = dma_zalloc_coherent(data->dev, - M2701_IOMMU_PGT_SIZE, - &dom->pgt_pa, GFP_KERNEL); + dom->pgt_va = dma_alloc_coherent(data->dev, M2701_IOMMU_PGT_SIZE, + &dom->pgt_pa, GFP_KERNEL); if (!dom->pgt_va) return -ENOMEM; @@ -270,12 +263,15 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { + struct mtk_iommu_data *data = dev_iommu_priv_get(dev); struct mtk_iommu_domain *dom = to_mtk_domain(domain); - struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; + struct dma_iommu_mapping *mtk_mapping; int ret; - if (!data) - return -ENODEV; + /* Only allow the domain created internally. */ + mtk_mapping = data->mapping; + if (mtk_mapping->domain != domain) + return 0; if (!data->m4u_dom) { data->m4u_dom = dom; @@ -293,16 +289,13 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; - - if (!data) - return; + struct mtk_iommu_data *data = dev_iommu_priv_get(dev); mtk_iommu_config(data, dev, false); } static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, - phys_addr_t paddr, size_t size, int prot) + phys_addr_t paddr, size_t size, int prot, gfp_t gfp) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); unsigned int page_num = size >> MT2701_IOMMU_PAGE_SHIFT; @@ -331,7 +324,8 @@ } static size_t mtk_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long iova, size_t size, + struct iommu_iotlb_gather *gather) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); unsigned long flags; @@ -362,7 +356,7 @@ return pa; } -static struct iommu_ops mtk_iommu_ops; +static const struct iommu_ops mtk_iommu_ops; /* * MTK generation one iommu HW only support one iommu domain, and all the client @@ -371,10 +365,10 @@ static int mtk_iommu_create_mapping(struct device *dev, struct of_phandle_args *args) { + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); struct mtk_iommu_data *data; struct platform_device *m4updev; struct dma_iommu_mapping *mtk_mapping; - struct device *m4udev; int ret; if (args->args_count != 1) { @@ -383,30 +377,30 @@ return -EINVAL; } - if (!dev->iommu_fwspec) { + if (!fwspec) { ret = iommu_fwspec_init(dev, &args->np->fwnode, &mtk_iommu_ops); if (ret) return ret; - } else if (dev->iommu_fwspec->ops != &mtk_iommu_ops) { + fwspec = dev_iommu_fwspec_get(dev); + } else if (dev_iommu_fwspec_get(dev)->ops != &mtk_iommu_ops) { return -EINVAL; } - if (!dev->iommu_fwspec->iommu_priv) { + if (!dev_iommu_priv_get(dev)) { /* Get the m4u device */ m4updev = of_find_device_by_node(args->np); if (WARN_ON(!m4updev)) return -EINVAL; - dev->iommu_fwspec->iommu_priv = platform_get_drvdata(m4updev); + dev_iommu_priv_set(dev, platform_get_drvdata(m4updev)); } ret = iommu_fwspec_add_ids(dev, args->args, 1); if (ret) return ret; - data = dev->iommu_fwspec->iommu_priv; - m4udev = data->dev; - mtk_mapping = m4udev->archdata.iommu; + data = dev_iommu_priv_get(dev); + mtk_mapping = data->mapping; if (!mtk_mapping) { /* MTK iommu support 4GB iova address space. */ mtk_mapping = arm_iommu_create_mapping(&platform_bus_type, @@ -414,72 +408,69 @@ if (IS_ERR(mtk_mapping)) return PTR_ERR(mtk_mapping); - m4udev->archdata.iommu = mtk_mapping; + data->mapping = mtk_mapping; } return 0; } -static int mtk_iommu_add_device(struct device *dev) +static int mtk_iommu_def_domain_type(struct device *dev) { - struct dma_iommu_mapping *mtk_mapping; + return IOMMU_DOMAIN_UNMANAGED; +} + +static struct iommu_device *mtk_iommu_probe_device(struct device *dev) +{ + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); struct of_phandle_args iommu_spec; struct of_phandle_iterator it; struct mtk_iommu_data *data; - struct iommu_group *group; int err; of_for_each_phandle(&it, err, dev->of_node, "iommus", - "#iommu-cells", 0) { + "#iommu-cells", -1) { int count = of_phandle_iterator_args(&it, iommu_spec.args, MAX_PHANDLE_ARGS); iommu_spec.np = of_node_get(it.node); iommu_spec.args_count = count; mtk_iommu_create_mapping(dev, &iommu_spec); + + /* dev->iommu_fwspec might have changed */ + fwspec = dev_iommu_fwspec_get(dev); + of_node_put(iommu_spec.np); } - if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) - return -ENODEV; /* Not a iommu client device */ + if (!fwspec || fwspec->ops != &mtk_iommu_ops) + return ERR_PTR(-ENODEV); /* Not a iommu client device */ - /* - * This is a short-term bodge because the ARM DMA code doesn't - * understand multi-device groups, but we have to call into it - * successfully (and not just rely on a normal IOMMU API attach - * here) in order to set the correct DMA API ops on @dev. - */ - group = iommu_group_alloc(); - if (IS_ERR(group)) - return PTR_ERR(group); + data = dev_iommu_priv_get(dev); - err = iommu_group_add_device(group, dev); - iommu_group_put(group); - if (err) - return err; - - data = dev->iommu_fwspec->iommu_priv; - mtk_mapping = data->dev->archdata.iommu; - err = arm_iommu_attach_device(dev, mtk_mapping); - if (err) { - iommu_group_remove_device(dev); - return err; - } - - return iommu_device_link(&data->iommu, dev);; + return &data->iommu; } -static void mtk_iommu_remove_device(struct device *dev) +static void mtk_iommu_probe_finalize(struct device *dev) { + struct dma_iommu_mapping *mtk_mapping; struct mtk_iommu_data *data; + int err; - if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) + data = dev_iommu_priv_get(dev); + mtk_mapping = data->mapping; + + err = arm_iommu_attach_device(dev, mtk_mapping); + if (err) + dev_err(dev, "Can't create IOMMU mapping - DMA-OPS will not work\n"); +} + +static void mtk_iommu_release_device(struct device *dev) +{ + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + + if (!fwspec || fwspec->ops != &mtk_iommu_ops) return; - data = dev->iommu_fwspec->iommu_priv; - iommu_device_unlink(&data->iommu, dev); - - iommu_group_remove_device(dev); iommu_fwspec_free(dev); } @@ -524,7 +515,7 @@ return 0; } -static struct iommu_ops mtk_iommu_ops = { +static const struct iommu_ops mtk_iommu_ops = { .domain_alloc = mtk_iommu_domain_alloc, .domain_free = mtk_iommu_domain_free, .attach_dev = mtk_iommu_attach_device, @@ -532,8 +523,11 @@ .map = mtk_iommu_map, .unmap = mtk_iommu_unmap, .iova_to_phys = mtk_iommu_iova_to_phys, - .add_device = mtk_iommu_add_device, - .remove_device = mtk_iommu_remove_device, + .probe_device = mtk_iommu_probe_device, + .probe_finalize = mtk_iommu_probe_finalize, + .release_device = mtk_iommu_release_device, + .def_domain_type = mtk_iommu_def_domain_type, + .device_group = generic_device_group, .pgsize_bitmap = ~0UL << MT2701_IOMMU_PAGE_SHIFT, }; @@ -609,13 +603,11 @@ } } - data->smi_imu.larb_imu[larb_nr].dev = &plarbdev->dev; + data->larb_imu[larb_nr].dev = &plarbdev->dev; component_match_add_release(dev, &match, release_of, compare_of, larb_spec.np); larb_nr++; } - - data->smi_imu.larb_nr = larb_nr; platform_set_drvdata(pdev, data); @@ -626,18 +618,34 @@ ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, dev_name(&pdev->dev)); if (ret) - return ret; + goto out_clk_unprepare; iommu_device_set_ops(&data->iommu, &mtk_iommu_ops); ret = iommu_device_register(&data->iommu); if (ret) - return ret; + goto out_sysfs_remove; - if (!iommu_present(&platform_bus_type)) - bus_set_iommu(&platform_bus_type, &mtk_iommu_ops); + if (!iommu_present(&platform_bus_type)) { + ret = bus_set_iommu(&platform_bus_type, &mtk_iommu_ops); + if (ret) + goto out_dev_unreg; + } - return component_master_add_with_match(dev, &mtk_iommu_com_ops, match); + ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, match); + if (ret) + goto out_bus_set_null; + return ret; + +out_bus_set_null: + bus_set_iommu(&platform_bus_type, NULL); +out_dev_unreg: + iommu_device_unregister(&data->iommu); +out_sysfs_remove: + iommu_device_sysfs_remove(&data->iommu); +out_clk_unprepare: + clk_disable_unprepare(data->bclk); + return ret; } static int mtk_iommu_remove(struct platform_device *pdev) @@ -704,15 +712,4 @@ { return platform_driver_register(&mtk_iommu_driver); } - -static void __exit m4u_exit(void) -{ - return platform_driver_unregister(&mtk_iommu_driver); -} - subsys_initcall(m4u_init); -module_exit(m4u_exit); - -MODULE_DESCRIPTION("IOMMU API for MTK architected m4u v1 implementations"); -MODULE_AUTHOR("Honghui Zhang <honghui.zhang@mediatek.com>"); -MODULE_LICENSE("GPL v2"); -- Gitblit v1.6.2