in rockchip-iommu.c [1203:1329]
static int rk_iommu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rk_iommu *iommu;
struct resource *res;
const struct rk_iommu_ops *ops;
int num_res = pdev->num_resources;
int err, i;
iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL);
if (!iommu)
return -ENOMEM;
platform_set_drvdata(pdev, iommu);
iommu->dev = dev;
iommu->num_mmu = 0;
ops = of_device_get_match_data(dev);
if (!rk_ops)
rk_ops = ops;
/*
* That should not happen unless different versions of the
* hardware block are embedded the same SoC
*/
if (WARN_ON(rk_ops != ops))
return -EINVAL;
iommu->bases = devm_kcalloc(dev, num_res, sizeof(*iommu->bases),
GFP_KERNEL);
if (!iommu->bases)
return -ENOMEM;
for (i = 0; i < num_res; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
continue;
iommu->bases[i] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(iommu->bases[i]))
continue;
iommu->num_mmu++;
}
if (iommu->num_mmu == 0)
return PTR_ERR(iommu->bases[0]);
iommu->num_irq = platform_irq_count(pdev);
if (iommu->num_irq < 0)
return iommu->num_irq;
iommu->reset_disabled = device_property_read_bool(dev,
"rockchip,disable-mmu-reset");
iommu->num_clocks = ARRAY_SIZE(rk_iommu_clocks);
iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
sizeof(*iommu->clocks), GFP_KERNEL);
if (!iommu->clocks)
return -ENOMEM;
for (i = 0; i < iommu->num_clocks; ++i)
iommu->clocks[i].id = rk_iommu_clocks[i];
/*
* iommu clocks should be present for all new devices and devicetrees
* but there are older devicetrees without clocks out in the wild.
* So clocks as optional for the time being.
*/
err = devm_clk_bulk_get(iommu->dev, iommu->num_clocks, iommu->clocks);
if (err == -ENOENT)
iommu->num_clocks = 0;
else if (err)
return err;
err = clk_bulk_prepare(iommu->num_clocks, iommu->clocks);
if (err)
return err;
iommu->group = iommu_group_alloc();
if (IS_ERR(iommu->group)) {
err = PTR_ERR(iommu->group);
goto err_unprepare_clocks;
}
err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
if (err)
goto err_put_group;
err = iommu_device_register(&iommu->iommu, &rk_iommu_ops, dev);
if (err)
goto err_remove_sysfs;
/*
* Use the first registered IOMMU device for domain to use with DMA
* API, since a domain might not physically correspond to a single
* IOMMU device..
*/
if (!dma_dev)
dma_dev = &pdev->dev;
bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
pm_runtime_enable(dev);
for (i = 0; i < iommu->num_irq; i++) {
int irq = platform_get_irq(pdev, i);
if (irq < 0)
return irq;
err = devm_request_irq(iommu->dev, irq, rk_iommu_irq,
IRQF_SHARED, dev_name(dev), iommu);
if (err) {
pm_runtime_disable(dev);
goto err_remove_sysfs;
}
}
dma_set_mask_and_coherent(dev, rk_ops->dma_bit_mask);
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
err_put_group:
iommu_group_put(iommu->group);
err_unprepare_clocks:
clk_bulk_unprepare(iommu->num_clocks, iommu->clocks);
return err;
}