From 10f058a6e20e3aa0146be8ba39432c68abb398e2 Mon Sep 17 00:00:00 2001 From: Pratik Patel Date: Mon, 16 Jan 2017 12:44:48 -0800 Subject: [PATCH] iommu: arm-smmu: Move to using bus bandwidth voting for bus clocks Bus clocks are managed via bus apis and hence move to using them for enabling bus clocks. The previous method could enable a bus clock at a higher than required frequency, wasting power. The power on sequence is regulator on, bus vote, and then enable remaining clocks. Remove all clocks which are of RPM_SMD type (including mmssnoc_axi_clk) since these are managed by the bus driver. Using an active-only bus vote instead should save power when APPS is power collapsed. Keep the mmss_mnoc_ahb_clk because it is a branch clock type which is not managed by the bus driver. No active-only mode is available for this clock. Change-Id: I3b35d81098b8bd5299b27e85d27aa959e7cf415a Signed-off-by: Pratik Patel Signed-off-by: Patrick Daly --- .../devicetree/bindings/iommu/arm,smmu.txt | 4 +- arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi | 35 +++++++++---- drivers/iommu/arm-smmu.c | 52 ++++++++++--------- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index d00a5c1ce502..9e512d1ea763 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -139,8 +139,8 @@ conditions. time. This should be a list of 2-tuples of the format: . -- qcom,bus-master-id : The master ID of the bus, if a bus vote is needed. - See include/dt-bindings/msm/msm-bus-ids.h. +Optional bus bindings as defined in +Documentation/devicetree/bindings/arm/msm/msm_bus.txt may also be present. Example: diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi index 0ba86e81887f..ecfff13f9355 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,9 +29,14 @@ , , ; - clocks = <&clock_gcc clk_aggre1_noc_clk>; - clock-names = "smmu_aggre1_noc_clk"; - #clock-cells = <1>; + qcom,msm-bus,name = "smmu-bus-client-anoc1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + /* aggre1_noc_clk */ + qcom,msm-bus,vectors-KBps = + <84 10062 0 0>, + <84 10062 0 1000>; }; anoc2_smmu: arm,smmu-anoc2@16c0000 { @@ -52,9 +57,14 @@ , , ; - clocks = <&clock_gcc clk_aggre2_noc_clk>; - clock-names = "smmu_aggre2_noc_clk"; - #clock-cells = <1>; + qcom,msm-bus,name = "smmu-bus-client-anoc2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + /* aggre2_noc_clk */ + qcom,msm-bus,vectors-KBps = + <117 10065 0 0>, + <117 10065 0 1000>; }; lpass_q6_smmu: arm,smmu-lpass_q6@5100000 { @@ -116,15 +126,20 @@ ; vdd-supply = <&gdsc_bimc_smmu>; clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, - <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, <&clock_mmss clk_mmss_bimc_smmu_axi_clk>; clock-names = "mmss_mnoc_ahb_clk", - "mmssnoc_axi_clk", "mmss_bimc_smmu_ahb_clk", "mmss_bimc_smmu_axi_clk"; #clock-cells = <1>; - qcom,bus-master-id = ; + qcom,msm-bus,name = "smmu-bus-client-mmss"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + /* ahb_clk_src, mmssnoc_axi_clk */ + qcom,msm-bus,vectors-KBps = + <102 722 0 0>, <29 512 0 0>, + <102 722 0 1000>, <29 512 0 1000>; }; kgsl_smmu: arm,smmu-kgsl@5040000 { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index fbe2302c4037..ce15e150277e 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -410,8 +410,8 @@ struct arm_smmu_device { struct mutex power_lock; unsigned int power_count; - struct msm_bus_client_handle *bus_client; - char *bus_client_name; + u32 bus_client; + struct msm_bus_scale_pdata *bus_pdata; enum tz_smmu_device_id sec_id; }; @@ -912,14 +912,14 @@ static int arm_smmu_request_bus(struct arm_smmu_device *smmu) { if (!smmu->bus_client) return 0; - return msm_bus_scale_update_bw(smmu->bus_client, 0, 1000); + return msm_bus_scale_client_update_request(smmu->bus_client, 1); } static int arm_smmu_unrequest_bus(struct arm_smmu_device *smmu) { if (!smmu->bus_client) return 0; - return msm_bus_scale_update_bw(smmu->bus_client, 0, 0); + return msm_bus_scale_client_update_request(smmu->bus_client, 0); } static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu) @@ -3571,34 +3571,37 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) static int arm_smmu_init_bus_scaling(struct platform_device *pdev, struct arm_smmu_device *smmu) { - u32 master_id; - - if (of_property_read_u32(pdev->dev.of_node, "qcom,bus-master-id", - &master_id)) { - dev_dbg(smmu->dev, "No bus scaling info\n"); + if (!of_find_property(pdev->dev.of_node, "qcom,msm-bus,name", NULL)) { + dev_dbg(&pdev->dev, "No bus scaling info\n"); return 0; } - smmu->bus_client_name = devm_kasprintf( - smmu->dev, GFP_KERNEL, "smmu-bus-client-%s", - dev_name(smmu->dev)); + smmu->bus_pdata = msm_bus_cl_get_pdata(pdev); + if (!smmu->bus_pdata) { + dev_err(&pdev->dev, "Unable to read bus-scaling from DT\n"); + return -EINVAL; + } - if (!smmu->bus_client_name) - return -ENOMEM; - - smmu->bus_client = msm_bus_scale_register( - master_id, MSM_BUS_SLAVE_EBI_CH0, smmu->bus_client_name, true); - if (IS_ERR(&smmu->bus_client)) { - int ret = PTR_ERR(smmu->bus_client); - - if (ret != -EPROBE_DEFER) - dev_err(smmu->dev, "Bus client registration failed\n"); - return ret; + smmu->bus_client = msm_bus_scale_register_client(smmu->bus_pdata); + if (!smmu->bus_client) { + dev_err(&pdev->dev, "Bus client registration failed\n"); + return -EINVAL; } return 0; } +static void arm_smmu_exit_bus_scaling(struct arm_smmu_device *smmu) +{ + if (smmu->bus_client) + msm_bus_scale_unregister_client(smmu->bus_client); + if (smmu->bus_pdata) + msm_bus_cl_clear_pdata(smmu->bus_pdata); + + smmu->bus_client = 0; + smmu->bus_pdata = NULL; +} + static int arm_smmu_parse_impl_def_registers(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; @@ -4035,6 +4038,7 @@ out_free_irqs: free_irq(smmu->irqs[i], smmu); out_put_masters: + arm_smmu_exit_bus_scaling(smmu); for (node = rb_first(&smmu->masters); node; node = rb_next(node)) { struct arm_smmu_master *master = container_of(node, struct arm_smmu_master, node); @@ -4086,7 +4090,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev) arm_smmu_power_off(smmu); mutex_unlock(&smmu->attach_lock); - msm_bus_scale_unregister(smmu->bus_client); + arm_smmu_exit_bus_scaling(smmu); return 0; }