diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt index e9fb1a2399c7..f5a2590e52aa 100644 --- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt +++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt @@ -16,6 +16,10 @@ Required properties: - qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block - vdd-supply : vdd-supply: phandle to GDSC regulator controlling this IOMMU. +Optional properties: +- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for + access to the IOMMU configuration registers + Example: qcom,iommu@fda64000 { diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h index 28c53dbc92bf..b14f145ed261 100644 --- a/arch/arm/mach-msm/include/mach/iommu.h +++ b/arch/arm/mach-msm/include/mach/iommu.h @@ -72,6 +72,7 @@ struct msm_iommu_ctx_dev { * @irq: Interrupt number * @clk: The bus clock for this IOMMU hardware instance * @pclk: The clock for the IOMMU bus interconnect + * @aclk: Alternate clock for this IOMMU core, if any * @name: Human-readable name of this IOMMU device * @gdsc: Regulator needed to power this HW block (v2 only) * @nsmr: Size of the SMT on this HW block (v2 only) @@ -85,6 +86,7 @@ struct msm_iommu_drvdata { int ttbr_split; struct clk *clk; struct clk *pclk; + struct clk *aclk; const char *name; struct regulator *gdsc; unsigned int nsmr; diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c index 48edf96ccae3..28ad0ffe2d32 100644 --- a/drivers/iommu/msm_iommu-v2.c +++ b/drivers/iommu/msm_iommu-v2.c @@ -51,10 +51,16 @@ static int __enable_clocks(struct msm_iommu_drvdata *drvdata) if (ret) goto fail; - if (drvdata->clk) { - ret = clk_prepare_enable(drvdata->clk); - if (ret) + ret = clk_prepare_enable(drvdata->clk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + if (drvdata->aclk) { + ret = clk_prepare_enable(drvdata->aclk); + if (ret) { + clk_disable_unprepare(drvdata->clk); clk_disable_unprepare(drvdata->pclk); + } } fail: return ret; @@ -62,8 +68,9 @@ fail: static void __disable_clocks(struct msm_iommu_drvdata *drvdata) { - if (drvdata->clk) - clk_disable_unprepare(drvdata->clk); + if (drvdata->aclk) + clk_disable_unprepare(drvdata->aclk); + clk_disable_unprepare(drvdata->clk); clk_disable_unprepare(drvdata->pclk); } diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c index 14ed5d9fdf49..8c26f956bb54 100644 --- a/drivers/iommu/msm_iommu_dev-v2.c +++ b/drivers/iommu/msm_iommu_dev-v2.c @@ -69,7 +69,7 @@ static int __devinit msm_iommu_probe(struct platform_device *pdev) { struct msm_iommu_drvdata *drvdata; struct resource *r; - int ret; + int ret, needs_alt_core_clk; if (msm_iommu_root_dev == pdev) return 0; @@ -93,55 +93,42 @@ static int __devinit msm_iommu_probe(struct platform_device *pdev) if (IS_ERR(drvdata->gdsc)) return -EINVAL; - drvdata->pclk = clk_get(&pdev->dev, "iface_clk"); + drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk"); if (IS_ERR(drvdata->pclk)) return PTR_ERR(drvdata->pclk); - ret = clk_prepare_enable(drvdata->pclk); - if (ret) - goto fail_enable; + drvdata->clk = devm_clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(drvdata->clk)) + return PTR_ERR(drvdata->clk); - drvdata->clk = clk_get(&pdev->dev, "core_clk"); - if (!IS_ERR(drvdata->clk)) { - if (clk_get_rate(drvdata->clk) == 0) { - ret = clk_round_rate(drvdata->clk, 1); - clk_set_rate(drvdata->clk, ret); - } + needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node, + "qcom,needs-alt-core-clk"); + if (needs_alt_core_clk) { + drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk"); + if (IS_ERR(drvdata->aclk)) + return PTR_ERR(drvdata->aclk); + } - ret = clk_prepare_enable(drvdata->clk); - if (ret) { - clk_put(drvdata->clk); - goto fail_pclk; - } - } else - drvdata->clk = NULL; + if (clk_get_rate(drvdata->clk) == 0) { + ret = clk_round_rate(drvdata->clk, 1); + clk_set_rate(drvdata->clk, ret); + } + + if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) { + ret = clk_round_rate(drvdata->aclk, 1); + clk_set_rate(drvdata->aclk, ret); + } ret = msm_iommu_parse_dt(pdev, drvdata); if (ret) - goto fail_clk; + return ret; pr_info("device %s mapped at %p, with %d ctx banks\n", drvdata->name, drvdata->base, drvdata->ncb); platform_set_drvdata(pdev, drvdata); - if (drvdata->clk) - clk_disable_unprepare(drvdata->clk); - - clk_disable_unprepare(drvdata->pclk); - return 0; - -fail_clk: - if (drvdata->clk) { - clk_disable_unprepare(drvdata->clk); - clk_put(drvdata->clk); - } -fail_pclk: - clk_disable_unprepare(drvdata->pclk); -fail_enable: - clk_put(drvdata->pclk); - return ret; } static int __devexit msm_iommu_remove(struct platform_device *pdev)