msm: iommu: Support alternate core clocks

Refactor the IOMMU clock control code to always require a
core clock as well as an interface clock. Add support for
an optional alternate core clock and update device tree
bindings accordingly. Clean up the probe function to remove
needless enabling / disabling of clocks.

Change-Id: I4d744ffabc1e6fb123bacfda324f64408257cb25
Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
This commit is contained in:
Stepan Moskovchenko 2012-07-24 19:24:14 -07:00 committed by Stephen Boyd
parent 8627019a66
commit 22c9f71a24
4 changed files with 40 additions and 40 deletions

View file

@ -16,6 +16,10 @@ Required properties:
- qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block - 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. - 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: Example:
qcom,iommu@fda64000 { qcom,iommu@fda64000 {

View file

@ -72,6 +72,7 @@ struct msm_iommu_ctx_dev {
* @irq: Interrupt number * @irq: Interrupt number
* @clk: The bus clock for this IOMMU hardware instance * @clk: The bus clock for this IOMMU hardware instance
* @pclk: The clock for the IOMMU bus interconnect * @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 * @name: Human-readable name of this IOMMU device
* @gdsc: Regulator needed to power this HW block (v2 only) * @gdsc: Regulator needed to power this HW block (v2 only)
* @nsmr: Size of the SMT on 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; int ttbr_split;
struct clk *clk; struct clk *clk;
struct clk *pclk; struct clk *pclk;
struct clk *aclk;
const char *name; const char *name;
struct regulator *gdsc; struct regulator *gdsc;
unsigned int nsmr; unsigned int nsmr;

View file

@ -51,10 +51,16 @@ static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
if (ret) if (ret)
goto fail; goto fail;
if (drvdata->clk) { ret = clk_prepare_enable(drvdata->clk);
ret = clk_prepare_enable(drvdata->clk); if (ret)
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); clk_disable_unprepare(drvdata->pclk);
}
} }
fail: fail:
return ret; return ret;
@ -62,8 +68,9 @@ fail:
static void __disable_clocks(struct msm_iommu_drvdata *drvdata) static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
{ {
if (drvdata->clk) if (drvdata->aclk)
clk_disable_unprepare(drvdata->clk); clk_disable_unprepare(drvdata->aclk);
clk_disable_unprepare(drvdata->clk);
clk_disable_unprepare(drvdata->pclk); clk_disable_unprepare(drvdata->pclk);
} }

View file

@ -69,7 +69,7 @@ static int __devinit msm_iommu_probe(struct platform_device *pdev)
{ {
struct msm_iommu_drvdata *drvdata; struct msm_iommu_drvdata *drvdata;
struct resource *r; struct resource *r;
int ret; int ret, needs_alt_core_clk;
if (msm_iommu_root_dev == pdev) if (msm_iommu_root_dev == pdev)
return 0; return 0;
@ -93,55 +93,42 @@ static int __devinit msm_iommu_probe(struct platform_device *pdev)
if (IS_ERR(drvdata->gdsc)) if (IS_ERR(drvdata->gdsc))
return -EINVAL; return -EINVAL;
drvdata->pclk = clk_get(&pdev->dev, "iface_clk"); drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(drvdata->pclk)) if (IS_ERR(drvdata->pclk))
return PTR_ERR(drvdata->pclk); return PTR_ERR(drvdata->pclk);
ret = clk_prepare_enable(drvdata->pclk); drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
if (ret) if (IS_ERR(drvdata->clk))
goto fail_enable; return PTR_ERR(drvdata->clk);
drvdata->clk = clk_get(&pdev->dev, "core_clk"); needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
if (!IS_ERR(drvdata->clk)) { "qcom,needs-alt-core-clk");
if (clk_get_rate(drvdata->clk) == 0) { if (needs_alt_core_clk) {
ret = clk_round_rate(drvdata->clk, 1); drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
clk_set_rate(drvdata->clk, ret); if (IS_ERR(drvdata->aclk))
} return PTR_ERR(drvdata->aclk);
}
ret = clk_prepare_enable(drvdata->clk); if (clk_get_rate(drvdata->clk) == 0) {
if (ret) { ret = clk_round_rate(drvdata->clk, 1);
clk_put(drvdata->clk); clk_set_rate(drvdata->clk, ret);
goto fail_pclk; }
}
} else if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
drvdata->clk = NULL; ret = clk_round_rate(drvdata->aclk, 1);
clk_set_rate(drvdata->aclk, ret);
}
ret = msm_iommu_parse_dt(pdev, drvdata); ret = msm_iommu_parse_dt(pdev, drvdata);
if (ret) if (ret)
goto fail_clk; return ret;
pr_info("device %s mapped at %p, with %d ctx banks\n", pr_info("device %s mapped at %p, with %d ctx banks\n",
drvdata->name, drvdata->base, drvdata->ncb); drvdata->name, drvdata->base, drvdata->ncb);
platform_set_drvdata(pdev, drvdata); platform_set_drvdata(pdev, drvdata);
if (drvdata->clk)
clk_disable_unprepare(drvdata->clk);
clk_disable_unprepare(drvdata->pclk);
return 0; 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) static int __devexit msm_iommu_remove(struct platform_device *pdev)