in arm/arm-smmu/qcom_iommu.c [758:855]
static int qcom_iommu_device_probe(struct platform_device *pdev)
{
struct device_node *child;
struct qcom_iommu_dev *qcom_iommu;
struct device *dev = &pdev->dev;
struct resource *res;
struct clk *clk;
int ret, max_asid = 0;
/* find the max asid (which is 1:1 to ctx bank idx), so we know how
* many child ctx devices we have:
*/
for_each_child_of_node(dev->of_node, child)
max_asid = max(max_asid, get_asid(child));
qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid),
GFP_KERNEL);
if (!qcom_iommu)
return -ENOMEM;
qcom_iommu->num_ctxs = max_asid;
qcom_iommu->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
qcom_iommu->local_base = devm_ioremap_resource(dev, res);
if (IS_ERR(qcom_iommu->local_base))
return PTR_ERR(qcom_iommu->local_base);
}
clk = devm_clk_get(dev, "iface");
if (IS_ERR(clk)) {
dev_err(dev, "failed to get iface clock\n");
return PTR_ERR(clk);
}
qcom_iommu->clks[CLK_IFACE].clk = clk;
clk = devm_clk_get(dev, "bus");
if (IS_ERR(clk)) {
dev_err(dev, "failed to get bus clock\n");
return PTR_ERR(clk);
}
qcom_iommu->clks[CLK_BUS].clk = clk;
clk = devm_clk_get_optional(dev, "tbu");
if (IS_ERR(clk)) {
dev_err(dev, "failed to get tbu clock\n");
return PTR_ERR(clk);
}
qcom_iommu->clks[CLK_TBU].clk = clk;
if (of_property_read_u32(dev->of_node, "qcom,iommu-secure-id",
&qcom_iommu->sec_id)) {
dev_err(dev, "missing qcom,iommu-secure-id property\n");
return -ENODEV;
}
if (qcom_iommu_has_secure_context(qcom_iommu)) {
ret = qcom_iommu_sec_ptbl_init(dev);
if (ret) {
dev_err(dev, "cannot init secure pg table(%d)\n", ret);
return ret;
}
}
platform_set_drvdata(pdev, qcom_iommu);
pm_runtime_enable(dev);
/* register context bank devices, which are child nodes: */
ret = devm_of_platform_populate(dev);
if (ret) {
dev_err(dev, "Failed to populate iommu contexts\n");
return ret;
}
ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL,
dev_name(dev));
if (ret) {
dev_err(dev, "Failed to register iommu in sysfs\n");
return ret;
}
ret = iommu_device_register(&qcom_iommu->iommu, &qcom_iommu_ops, dev);
if (ret) {
dev_err(dev, "Failed to register iommu\n");
return ret;
}
bus_set_iommu(&platform_bus_type, &qcom_iommu_ops);
if (qcom_iommu->local_base) {
pm_runtime_get_sync(dev);
writel_relaxed(0xffffffff, qcom_iommu->local_base + SMMU_INTR_SEL_NS);
pm_runtime_put_sync(dev);
}
return 0;
}