iommu: msm: Add bus voting to IOMMU driver
Add framework to enable IOMMU driver to vote for bus bandwidth. This
is required for some IOMMUs to allow certain clocks to turn on.
Bus voting will only be enabled if the corresponding IOMMU device
tree node has the appropriate bus bandwidth information specified.
Change-Id: If34e3f806e4b7674bf68e3fcc975e1d589450cc1
Signed-off-by: Olav Haugan <ohaugan@codeaurora.org>
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index dc5e644..4fca473 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -30,6 +30,7 @@
#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
+#include <mach/msm_bus.h>
static DEFINE_MUTEX(iommu_list_lock);
static LIST_HEAD(iommu_list);
@@ -131,6 +132,38 @@
}
#ifdef CONFIG_OF_DEVICE
+
+static int __get_bus_vote_client(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ int ret = 0;
+ struct msm_bus_scale_pdata *bs_table;
+ const char *dummy;
+
+ /* Check whether bus scaling has been specified for this node */
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+ &dummy);
+ if (ret)
+ return 0;
+
+ bs_table = msm_bus_cl_get_pdata(pdev);
+
+ if (bs_table) {
+ drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+ if (IS_ERR(&drvdata->bus_client)) {
+ pr_err("%s(): Bus client register failed.\n", __func__);
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+ msm_bus_scale_unregister_client(drvdata->bus_client);
+ drvdata->bus_client = 0;
+}
+
static int msm_iommu_parse_dt(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata,
int *needs_alt_core_clk)
@@ -138,17 +171,24 @@
struct device_node *child;
struct resource *r;
u32 glb_offset = 0;
- int ret;
+ int ret = 0;
+
+ ret = __get_bus_vote_client(pdev, drvdata);
+
+ if (ret)
+ goto fail;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
pr_err("%s: Missing property reg\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail;
}
drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (!drvdata->base) {
pr_err("%s: Unable to ioremap %pr\n", __func__, r);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
drvdata->glb_base = drvdata->base;
@@ -157,7 +197,8 @@
drvdata->glb_base += glb_offset;
} else {
pr_err("%s: Missing property qcom,glb-offset\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail;
}
for_each_child_of_node(pdev->dev.of_node, child)
@@ -167,7 +208,8 @@
&drvdata->name);
if (ret) {
pr_err("%s: Missing property label\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail;
}
*needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
@@ -179,10 +221,16 @@
ret = of_platform_populate(pdev->dev.of_node,
msm_iommu_v0_ctx_match_table,
NULL, &pdev->dev);
- if (ret)
+ if (ret) {
pr_err("Failed to create iommu context device\n");
+ goto fail;
+ }
return ret;
+
+fail:
+ __put_bus_vote_client(drvdata);
+ return ret;
}
#else
@@ -192,6 +240,13 @@
{
return 0;
}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+
+}
+
+
#endif
static int __get_clocks(struct platform_device *pdev,
@@ -342,7 +397,7 @@
if (!drvdata) {
ret = -ENOMEM;
- goto fail;
+ goto fail_mem;
}
if (pdev->dev.of_node) {
@@ -444,6 +499,8 @@
iommu_access_ops_v0.iommu_clk_off(drvdata);
__put_clocks(drvdata);
fail:
+ __put_bus_vote_client(drvdata);
+fail_mem:
return ret;
}
@@ -453,6 +510,7 @@
drv = platform_get_drvdata(pdev);
if (drv) {
+ __put_bus_vote_client(drv);
msm_iommu_remove_drv(drv);
if (drv->clk)
clk_put(drv->clk);