Newer platforms vote for necessary power domains through the power domain subsystem. For historical reasons older platforms like MSM8916 or MSM8974 still control these as regulators. This patch series adds the power domain definitions for MSM8916 to the rpmpd driver. Then, qcom_q6v5_mss and qcom_wcnss are updated to use power domains for MSM8916/MSM8974. For compatibility with old device trees (and for MSM8974) we still need to support using the power domains through the regulator interface. This is implemented by falling back to the regulators if requesting the power domains fails. Finally, we remove the regulators that provide the power domains (s1 and l3) entirely from the MSM8916 device tree: They should only be used through the power domain subsystem from now on. Stephan Gerhold (10): soc: qcom: rpmpd: Rename MAX_8996_RPMPD_STATE to MAX_CORNER_RPMPD_STATE dt-bindings: power: rpmpd: Add MSM8916 RPM power domains soc: qcom: rpmpd: Add MSM8916 power domains arm64: dts: qcom: msm8916: Add RPM power domains dt-bindings: remoteproc: qcom,q6v5: Deprecate regulators for PDs remoteproc: qcom_q6v5_mss: Allow replacing regulators with power domains dt-bindings: remoteproc: qcom,wcnss: Deprecate regulators for PDs remoteproc: qcom_wcnss: Allow replacing regulators with power domains arm64: dts: qcom: msm8916: Use power domains for MSS/WCNSS remoteprocs arm64: dts: qcom: msm8916-pm8916: Stop using s1/l3 as regulators .../devicetree/bindings/power/qcom,rpmpd.yaml | 1 + .../bindings/remoteproc/qcom,q6v5.txt | 12 +- .../bindings/remoteproc/qcom,wcnss-pil.txt | 20 +++- arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi | 10 -- .../boot/dts/qcom/msm8916-longcheer-l8150.dts | 10 -- arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi | 7 +- .../qcom/msm8916-samsung-a2015-common.dtsi | 10 -- arch/arm64/boot/dts/qcom/msm8916.dtsi | 38 ++++++ drivers/remoteproc/qcom_q6v5_mss.c | 68 +++++++++-- drivers/remoteproc/qcom_wcnss.c | 109 +++++++++++++++--- drivers/soc/qcom/rpmpd.c | 25 +++- include/dt-bindings/power/qcom-rpmpd.h | 7 ++ 12 files changed, 242 insertions(+), 75 deletions(-) -- 2.28.0
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~postmarketos/upstreaming/patches/13946/mbox | git am -3Learn more about email & git
Older SoCs like MSM8916, MSM8939, MSM8974, MSM8996, ... use "voltage corners" instead of "voltage levels". It seems like they all use exactly the same set of corner values, a value from 0-6 where 6 is the maximum corner (super turbo). In preparation to add the power domains for MSM8916, rename MAX_8996_RPMPD_STATE to MAX_CORNER_RPMPD_STATE to make it clear that this is the max_state to be used for all SoCs using corners. - Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- drivers/soc/qcom/rpmpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index f2168e4259b2..88eb458b13d0 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -35,7 +35,7 @@ #define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */ #define KEY_LEVEL 0x6c766c76 /* vlvl */ -#define MAX_8996_RPMPD_STATE 6 +#define MAX_CORNER_RPMPD_STATE 6 #define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \ r_id) \ @@ -159,7 +159,7 @@ static struct rpmpd *msm8996_rpmpds[] = { static const struct rpmpd_desc msm8996_desc = { .rpmpds = msm8996_rpmpds, .num_pds = ARRAY_SIZE(msm8996_rpmpds), - .max_state = MAX_8996_RPMPD_STATE, + .max_state = MAX_CORNER_RPMPD_STATE, }; /* msm8998 RPM Power domains */ -- 2.28.0
MSM8916 has two RPM power domains: VDDCX and VDDMX. Add the device tree bindings to manage them through rpmpd. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 1 + include/dt-bindings/power/qcom-rpmpd.h | 7 +++++++ 2 files changed, 8 insertions(+)
Rob HerringReviewed-by: Rob Herring <robh@kernel.org>
diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 8058955fb3b9..f136d06b7fc8 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,msm8916-rpmpd - qcom,msm8976-rpmpd - qcom,msm8996-rpmpd - qcom,msm8998-rpmpd diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index 5e61eaf73bdd..83dae2cabb60 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -64,6 +64,13 @@ #define RPMH_REGULATOR_LEVEL_TURBO 384 #define RPMH_REGULATOR_LEVEL_TURBO_L1 416 +/* MSM8916 Power Domain Indexes */ +#define MSM8916_VDDCX 0 +#define MSM8916_VDDCX_AO 1 +#define MSM8916_VDDCX_VFC 2 +#define MSM8916_VDDMX 3 +#define MSM8916_VDDMX_AO 4 + /* MSM8976 Power Domain Indexes */ #define MSM8976_VDDCX 0 #define MSM8976_VDDCX_AO 1 -- 2.28.0
MSM8916 has two RPM power domains: VDDCX and VDDMX. Add the necessary definitions to manage them with rpmpd. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- drivers/soc/qcom/rpmpd.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 88eb458b13d0..daeea119d48a 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -116,6 +116,26 @@ struct rpmpd_desc { static DEFINE_MUTEX(rpmpd_lock); +/* msm8916 RPM Power Domains */ +DEFINE_RPMPD_PAIR(msm8916, vddcx, vddcx_ao, SMPA, CORNER, 1); +DEFINE_RPMPD_PAIR(msm8916, vddmx, vddmx_ao, LDOA, CORNER, 3); + +DEFINE_RPMPD_VFC(msm8916, vddcx_vfc, SMPA, 1); + +static struct rpmpd *msm8916_rpmpds[] = { + [MSM8916_VDDCX] = &msm8916_vddcx, + [MSM8916_VDDCX_AO] = &msm8916_vddcx_ao, + [MSM8916_VDDCX_VFC] = &msm8916_vddcx_vfc, + [MSM8916_VDDMX] = &msm8916_vddmx, + [MSM8916_VDDMX_AO] = &msm8916_vddmx_ao, +}; + +static const struct rpmpd_desc msm8916_desc = { + .rpmpds = msm8916_rpmpds, + .num_pds = ARRAY_SIZE(msm8916_rpmpds), + .max_state = MAX_CORNER_RPMPD_STATE, +}; + /* msm8976 RPM Power Domains */ DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2); DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6); @@ -221,6 +241,7 @@ static const struct rpmpd_desc qcs404_desc = { }; static const struct of_device_id rpmpd_match_table[] = { + { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, -- 2.28.0
MSM8916 has two RPM power domains: VDDCX and VDDMX. So far we have been managing them by voting for raw voltages through the regulator subsystem, but it's better to manage them with corners as actual power domains. Add the device tree node for rpmpd so we can manage them as real power domains instead of using the regulators. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index aaa21899f1a6..117804f94c35 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -289,6 +289,35 @@ rpmcc: clock-controller { compatible = "qcom,rpmcc-msm8916"; #clock-cells = <1>; }; + + rpmpd: power-controller { + compatible = "qcom,msm8916-rpmpd"; + #power-domain-cells = <1>; + operating-points-v2 = <&rpmpd_opp_table>; + + rpmpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmpd_opp_ret: opp1 { + opp-level = <1>; + }; + rpmpd_opp_svs_krait: opp2 { + opp-level = <2>; + }; + rpmpd_opp_svs_soc: opp3 { + opp-level = <3>; + }; + rpmpd_opp_nom: opp4 { + opp-level = <4>; + }; + rpmpd_opp_turbo: opp5 { + opp-level = <5>; + }; + rpmpd_opp_super_turbo: opp6 { + opp-level = <6>; + }; + }; + }; }; }; }; -- 2.28.0
Newer platforms vote for necessary power domains through the power domain subsystem. For historical reasons older platforms like MSM8916 or MSM8974 still control these as regulators.
Rob HerringDo you plan to change these platforms? If not then I wouldn't really call this deprecated.
Managing them as power domains is preferred since that allows us to vote for corners instead of raw voltages. Document that those should be specified as power domains and deprecate using them through the regulator interface. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- .../devicetree/bindings/remoteproc/qcom,q6v5.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt index 1f9a62e13ebe..7ccd5534b0ae 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt @@ -113,8 +113,8 @@ should be referenced as follows: For the compatible strings below the following supplies are required: "qcom,q6v5-pil" "qcom,msm8916-mss-pil", -- cx-supply: -- mx-supply: +- cx-supply: (deprecated, use power domain instead) +- mx-supply: (deprecated, use power domain instead) - pll-supply: Usage: required Value type: <phandle> @@ -123,9 +123,9 @@ For the compatible strings below the following supplies are required: For the compatible string below the following supplies are required: "qcom,msm8974-mss-pil" -- cx-supply: +- cx-supply: (deprecated, use power domain instead) - mss-supply: -- mx-supply: +- mx-supply: (deprecated, use power domain instead) - pll-supply: Usage: required Value type: <phandle> @@ -149,11 +149,11 @@ For the compatible string below the following supplies are required: Usage: required Value type: <stringlist> Definition: The power-domains needed depend on the compatible string: - qcom,q6v5-pil: qcom,ipq8074-wcss-pil: + no power-domain names required + qcom,q6v5-pil: qcom,msm8916-mss-pil: qcom,msm8974-mss-pil: - no power-domain names required qcom,msm8996-mss-pil: qcom,msm8998-mss-pil: must be "cx", "mx" -- 2.28.0
Newer platforms vote for necessary power domains through the power domain subsystem. For historical reasons older platforms like MSM8916 or MSM8974 still control these as regulators. Managing them as power domains is preferred since that allows us to vote for corners instead of raw voltages. Make it possible for MSM8916 and MSM8974 to manage these as power domains. For compatibility with old device trees we still need to support falling back to the regulators when necessary. The way this is implemented here is that the deprecated regulators are defined as "fallback_proxy_supply". Only if attaching the power domains fails because they are not specified (-ENODATA) we request and manage the fallback regulators instead. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- drivers/remoteproc/qcom_q6v5_mss.c | 68 ++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index c401bcc263fa..98bf4230d8f4 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -132,6 +132,7 @@ struct qcom_mss_reg_res { struct rproc_hexagon_res { const char *hexagon_mba_image; struct qcom_mss_reg_res *proxy_supply; + struct qcom_mss_reg_res *fallback_proxy_supply; struct qcom_mss_reg_res *active_supply; char **proxy_clk_names; char **reset_clk_names; @@ -177,9 +178,11 @@ struct q6v5 { int proxy_pd_count; struct reg_info active_regs[1]; - struct reg_info proxy_regs[3]; + struct reg_info proxy_regs[1]; + struct reg_info fallback_proxy_regs[2]; int active_reg_count; int proxy_reg_count; + int fallback_proxy_reg_count; bool dump_mba_loaded; size_t current_dump_size; @@ -890,11 +893,18 @@ static int q6v5_mba_load(struct q6v5 *qproc) goto disable_active_pds; } + ret = q6v5_regulator_enable(qproc, qproc->fallback_proxy_regs, + qproc->fallback_proxy_reg_count); + if (ret) { + dev_err(qproc->dev, "failed to enable fallback proxy supplies\n"); + goto disable_proxy_pds; + } + ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, qproc->proxy_reg_count); if (ret) { dev_err(qproc->dev, "failed to enable proxy supplies\n"); - goto disable_proxy_pds; + goto disable_fallback_proxy_reg; } ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks, @@ -997,6 +1007,9 @@ static int q6v5_mba_load(struct q6v5 *qproc) disable_proxy_reg: q6v5_regulator_disable(qproc, qproc->proxy_regs, qproc->proxy_reg_count); +disable_fallback_proxy_reg: + q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs, + qproc->fallback_proxy_reg_count); disable_proxy_pds: q6v5_pds_disable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); disable_active_pds: @@ -1052,6 +1065,8 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc) qproc->proxy_pd_count); q6v5_clk_disable(qproc->dev, qproc->proxy_clks, qproc->proxy_clk_count); + q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs, + qproc->fallback_proxy_reg_count); q6v5_regulator_disable(qproc, qproc->proxy_regs, qproc->proxy_reg_count); } @@ -1413,6 +1428,8 @@ static void qcom_msa_handover(struct qcom_q6v5 *q6v5) qproc->proxy_clk_count); q6v5_regulator_disable(qproc, qproc->proxy_regs, qproc->proxy_reg_count); + q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs, + qproc->fallback_proxy_reg_count); q6v5_pds_disable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); } @@ -1707,11 +1724,22 @@ static int q6v5_probe(struct platform_device *pdev) ret = q6v5_pds_attach(&pdev->dev, qproc->proxy_pds, desc->proxy_pd_names); - if (ret < 0) { + /* Fallback to regulators for old device trees */ + if (ret == -ENODATA && desc->fallback_proxy_supply) { + ret = q6v5_regulator_init(&pdev->dev, + qproc->fallback_proxy_regs, + desc->fallback_proxy_supply); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get fallback proxy regulators.\n"); + goto detach_active_pds; + } + qproc->fallback_proxy_reg_count = ret; + } else if (ret < 0) { dev_err(&pdev->dev, "Failed to init power domains\n"); goto detach_active_pds; + } else { + qproc->proxy_pd_count = ret; } - qproc->proxy_pd_count = ret; qproc->has_alt_reset = desc->has_alt_reset; ret = q6v5_init_reset(qproc); @@ -1912,6 +1940,13 @@ static const struct rproc_hexagon_res msm8996_mss = { static const struct rproc_hexagon_res msm8916_mss = { .hexagon_mba_image = "mba.mbn", .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "pll", + .uA = 100000, + }, + {} + }, + .fallback_proxy_supply = (struct qcom_mss_reg_res[]) { { .supply = "mx", .uV = 1050000, @@ -1920,10 +1955,6 @@ static const struct rproc_hexagon_res msm8916_mss = { .supply = "cx", .uA = 100000, }, - { - .supply = "pll", - .uA = 100000, - }, {} }, .proxy_clk_names = (char*[]){ @@ -1936,6 +1967,11 @@ static const struct rproc_hexagon_res msm8916_mss = { "mem", NULL }, + .proxy_pd_names = (char*[]){ + "mx", + "cx", + NULL + }, .need_mem_protection = false, .has_alt_reset = false, .has_mba_logs = false, @@ -1946,6 +1982,13 @@ static const struct rproc_hexagon_res msm8916_mss = { static const struct rproc_hexagon_res msm8974_mss = { .hexagon_mba_image = "mba.b00", .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "pll", + .uA = 100000, + }, + {} + }, + .fallback_proxy_supply = (struct qcom_mss_reg_res[]) { { .supply = "mx", .uV = 1050000, @@ -1954,10 +1997,6 @@ static const struct rproc_hexagon_res msm8974_mss = { .supply = "cx", .uA = 100000, }, - { - .supply = "pll", - .uA = 100000, - }, {} }, .active_supply = (struct qcom_mss_reg_res[]) { @@ -1978,6 +2017,11 @@ static const struct rproc_hexagon_res msm8974_mss = { "mem", NULL }, + .proxy_pd_names = (char*[]){ + "mx", + "cx", + NULL + }, .need_mem_protection = false, .has_alt_reset = false, .has_mba_logs = false, -- 2.28.0
So far we have been doing all proxy votes by voting for raw voltages/load through the regulator interface. But actually VDDCX and VDDMX represent power domains that should be preferably managed using corner votes through the power domain interface. Document that those should be specified as power domains for qcom,pronto-v1/2-pil and deprecate using them through the regulator interface. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- .../bindings/remoteproc/qcom,wcnss-pil.txt | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt index d420f84ddfb0..cc0b7fc1c29b 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt @@ -34,14 +34,25 @@ on the Qualcomm WCNSS core. Definition: should be "wdog", "fatal", optionally followed by "ready", "handover", "stop-ack" -- vddmx-supply: -- vddcx-supply: +- vddmx-supply: (deprecated for qcom,pronto-v1/2-pil) +- vddcx-supply: (deprecated for qcom,pronto-v1/2-pil) - vddpx-supply: Usage: required Value type: <phandle> Definition: reference to the regulators to be held on behalf of the booting of the WCNSS core +- power-domains: + Usage: required (for qcom,pronto-v1/2-pil) + Value type: <phandle> + Definition: reference to the power domains to be held on behalf of the + booting of the WCNSS core + +- power-domain-names: + Usage: required (for qcom,pronto-v1/2-pil) + Value type: <stringlist> + Definition: must be "cx", "mx" + - qcom,smem-states: Usage: optional Value type: <prop-encoded-array> @@ -111,8 +122,9 @@ pronto@fb204000 { <&wcnss_smp2p_slave 3 0>; interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack"; - vddmx-supply = <&pm8841_s1>; - vddcx-supply = <&pm8841_s2>; + power-domains = <&rpmpd MSM8974_VDDCX>, <&rpmpd MSM8974_VDDMX>; + power-domain-names = "cx", "mx"; + vddpx-supply = <&pm8941_s3>; qcom,smem-states = <&wcnss_smp2p_out 0>; -- 2.28.0
So far we have been doing all proxy votes by voting for raw voltages/load through the regulator interface. But actually VDDCX and VDDMX represent power domains that should be preferably managed using corner votes through the power domain interface. Looking closer the code was actually never doing the proxy votes correctly: The vddcx regulator is specified as: { "vddcx", .super_turbo = true }, which is supposed to say that we should vote for the maximum corner of the VDDCX power domain. But actually "super_turbo" is unused so all we did so far is to enable the power domain. We did not vote for it to scale to the maximum performance state. Using them through the power domain interface allows voting for the maximum performance state. However, we still need to support using them through the regulator interface for old device trees. The way this is implemented here is that we check if attaching the two power domain succeeds. If yes, we skip the first "num_pd_vregs" regulators in the "vregs" list and only request the remaining ones. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- drivers/remoteproc/qcom_wcnss.c | 109 +++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index e2573f79a137..f95854255c70 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -17,6 +17,8 @@ #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/qcom_scm.h> #include <linux/regulator/consumer.h> #include <linux/remoteproc.h> @@ -51,12 +53,15 @@ #define WCNSS_PMU_XO_MODE_19p2 0 #define WCNSS_PMU_XO_MODE_48 3 +#define WCNSS_MAX_PDS 2 + struct wcnss_data { size_t pmu_offset; size_t spare_offset; + const char *pd_names[WCNSS_MAX_PDS]; const struct wcnss_vreg_info *vregs; - size_t num_vregs; + size_t num_vregs, num_pd_vregs; }; struct qcom_wcnss { @@ -80,6 +85,8 @@ struct qcom_wcnss { struct mutex iris_lock; struct qcom_iris *iris; + struct device *pds[WCNSS_MAX_PDS]; + size_t num_pds; struct regulator_bulk_data *vregs; size_t num_vregs; @@ -111,24 +118,28 @@ static const struct wcnss_data pronto_v1_data = { .pmu_offset = 0x1004, .spare_offset = 0x1088, + .pd_names = { "mx", "cx" }, .vregs = (struct wcnss_vreg_info[]) { { "vddmx", 950000, 1150000, 0 }, { "vddcx", .super_turbo = true}, { "vddpx", 1800000, 1800000, 0 }, }, - .num_vregs = 3, + .num_pd_vregs = 2, + .num_vregs = 1, }; static const struct wcnss_data pronto_v2_data = { .pmu_offset = 0x1004, .spare_offset = 0x1088, + .pd_names = { "mx", "cx" }, .vregs = (struct wcnss_vreg_info[]) { { "vddmx", 1287500, 1287500, 0 }, { "vddcx", .super_turbo = true }, { "vddpx", 1800000, 1800000, 0 }, }, - .num_vregs = 3, + .num_pd_vregs = 2, + .num_vregs = 1, }; void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, @@ -219,7 +230,7 @@ static void wcnss_configure_iris(struct qcom_wcnss *wcnss) static int wcnss_start(struct rproc *rproc) { struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; - int ret; + int ret, i; mutex_lock(&wcnss->iris_lock); if (!wcnss->iris) { @@ -228,9 +239,18 @@ static int wcnss_start(struct rproc *rproc) goto release_iris_lock; } + for (i = 0; i < wcnss->num_pds; i++) { + dev_pm_genpd_set_performance_state(wcnss->pds[i], INT_MAX); + ret = pm_runtime_get_sync(wcnss->pds[i]); + if (ret < 0) { + pm_runtime_put_noidle(wcnss->pds[i]); + goto disable_pds; + } + } + ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs); if (ret) - goto release_iris_lock; + goto disable_pds; ret = qcom_iris_enable(wcnss->iris); if (ret) @@ -262,6 +282,11 @@ static int wcnss_start(struct rproc *rproc) qcom_iris_disable(wcnss->iris); disable_regulators: regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs); +disable_pds: + for (i--; i >= 0; i--) { + pm_runtime_put(wcnss->pds[i]); + dev_pm_genpd_set_performance_state(wcnss->pds[i], 0); + } release_iris_lock: mutex_unlock(&wcnss->iris_lock); @@ -371,14 +396,54 @@ static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev) return IRQ_HANDLED; } +static int wcnss_init_pds(struct qcom_wcnss *wcnss, + const char * const pd_names[WCNSS_MAX_PDS]) +{ + int i, ret; + + for (i = 0; i < WCNSS_MAX_PDS; i++) { + if (!pd_names[i]) + break; + + wcnss->pds[i] = dev_pm_domain_attach_by_name(wcnss->dev, pd_names[i]); + if (IS_ERR_OR_NULL(wcnss->pds[i])) { + ret = PTR_ERR(wcnss->pds[i]) ? : -ENODATA; + for (i--; i >= 0; i--) + dev_pm_domain_detach(wcnss->pds[i], false); + return ret; + } + } + wcnss->num_pds = i; + + return 0; +} + +static void wcnss_release_pds(struct qcom_wcnss *wcnss) +{ + int i; + + for (i = 0; i < wcnss->num_pds; i++) + dev_pm_domain_detach(wcnss->pds[i], false); +} + static int wcnss_init_regulators(struct qcom_wcnss *wcnss, const struct wcnss_vreg_info *info, - int num_vregs) + int num_vregs, int num_pd_vregs) { struct regulator_bulk_data *bulk; int ret; int i; + /* + * If attaching the power domains suceeded we can skip requesting + * the regulators for the power domains. For old device trees we need to + * reserve extra space to manage them through the regulator interface. + */ + if (wcnss->num_pds) + info += num_pd_vregs; + else + num_vregs += num_pd_vregs; + bulk = devm_kcalloc(wcnss->dev, num_vregs, sizeof(struct regulator_bulk_data), GFP_KERNEL); @@ -514,33 +579,42 @@ static int wcnss_probe(struct platform_device *pdev) wcnss->pmu_cfg = mmio + data->pmu_offset; wcnss->spare_out = mmio + data->spare_offset; - ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs); - if (ret) + /* + * We might need to fallback to regulators instead of power domains + * for old device trees. Don't report an error in that case. + */ + ret = wcnss_init_pds(wcnss, data->pd_names); + if (ret && (ret != -ENODATA || !data->num_pd_vregs)) goto free_rproc; + ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs, + data->num_pd_vregs); + if (ret) + goto detach_pds; + ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt); if (ret < 0) - goto free_rproc; + goto detach_pds; wcnss->wdog_irq = ret; ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt); if (ret < 0) - goto free_rproc; + goto detach_pds; wcnss->fatal_irq = ret; ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt); if (ret < 0) - goto free_rproc; + goto detach_pds; wcnss->ready_irq = ret; ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt); if (ret < 0) - goto free_rproc; + goto detach_pds; wcnss->handover_irq = ret; ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt); if (ret < 0) - goto free_rproc; + goto detach_pds; wcnss->stop_ack_irq = ret; if (wcnss->stop_ack_irq) { @@ -548,7 +622,7 @@ static int wcnss_probe(struct platform_device *pdev) &wcnss->stop_bit); if (IS_ERR(wcnss->state)) { ret = PTR_ERR(wcnss->state); - goto free_rproc; + goto detach_pds; } } @@ -556,15 +630,17 @@ static int wcnss_probe(struct platform_device *pdev) wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID); if (IS_ERR(wcnss->sysmon)) { ret = PTR_ERR(wcnss->sysmon); - goto free_rproc; + goto detach_pds; } ret = rproc_add(rproc); if (ret) - goto free_rproc; + goto detach_pds; return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); +detach_pds: + wcnss_release_pds(wcnss); free_rproc: rproc_free(rproc); @@ -582,6 +658,7 @@ static int wcnss_remove(struct platform_device *pdev) qcom_remove_sysmon_subdev(wcnss->sysmon); qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev); + wcnss_release_pds(wcnss); rproc_free(wcnss->rproc); return 0; -- 2.28.0
So far we have been making proxy votes for the remote processors through the regulator interface. Now that we have rpmpd it's better to vote for performance states through the power domain interface. This also allows us to move these supplies back to msm8916.dtsi because the device tree binding for RPMPD is independent of the underlying regulator/PMIC. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi | 3 --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi index cd626e7db599..513e433aa5f3 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi @@ -17,13 +17,10 @@ &dsi_phy0 { }; &mpss { - cx-supply = <&pm8916_s1>; - mx-supply = <&pm8916_l3>; pll-supply = <&pm8916_l7>; }; &pronto { - vddmx-supply = <&pm8916_l3>; vddpx-supply = <&pm8916_l7>; iris { diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 117804f94c35..74aa50f3db10 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/interconnect/qcom,msm8916.h> #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/power/qcom-rpmpd.h> #include <dt-bindings/reset/qcom,gcc-msm8916.h> #include <dt-bindings/thermal/thermal.h> @@ -1292,6 +1293,10 @@ mpss: remoteproc@4080000 { interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack"; + power-domains = <&rpmpd MSM8916_VDDCX>, + <&rpmpd MSM8916_VDDMX>; + power-domain-names = "cx", "mx"; + clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, <&gcc GCC_BOOT_ROM_AHB_CLK>, @@ -1689,6 +1694,10 @@ pronto: remoteproc@a21b000 { <&wcnss_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack"; + power-domains = <&rpmpd MSM8916_VDDCX>, + <&rpmpd MSM8916_VDDMX>; + power-domain-names = "cx", "mx"; + qcom,state = <&wcnss_smp2p_out 0>; qcom,state-names = "stop"; -- 2.28.0
s1 (VDDCX) and l3 (VDDMX) are now managed by rpmpd as power domains. This allows us to vote for voltage corners instead of voting for raw voltages. But we cannot manage these as regulator and power domain at the same time: The votes by rpmpd would conflict with the ones from the regulator driver. All users of these regulators have been converted to power domains. Make sure that no new users are added by removing s1 and l3 from the regulator definitions. This also allows us to remove the arbitrary voltage constraints we have been using for these regulators. Not all of the voltages listed there would actually have been safe for the boards. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> --- arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi | 10 ---------- arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts | 10 ---------- arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi | 4 ++-- .../boot/dts/qcom/msm8916-samsung-a2015-common.dtsi | 10 ---------- 4 files changed, 2 insertions(+), 32 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi index 3c7f97539390..3a9538e1ec97 100644 --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi @@ -417,11 +417,6 @@ &smd_rpm_regulators { vdd_l4_l5_l6-supply = <&pm8916_s4>; vdd_l7-supply = <&pm8916_s4>; - s1 { - regulator-min-microvolt = <375000>; - regulator-max-microvolt = <1562000>; - }; - s3 { regulator-min-microvolt = <375000>; regulator-max-microvolt = <1562000>; @@ -445,11 +440,6 @@ l2 { regulator-max-microvolt = <1200000>; }; - l3 { - regulator-min-microvolt = <375000>; - regulator-max-microvolt = <1525000>; - }; - l4 { regulator-min-microvolt = <1750000>; regulator-max-microvolt = <3337000>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts index b9d3c5d98dd0..2c204d535d66 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts @@ -98,11 +98,6 @@ &smd_rpm_regulators { vdd_l4_l5_l6-supply = <&pm8916_s4>; vdd_l7-supply = <&pm8916_s4>; - s1 { - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1300000>; - }; - s3 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1300000>; @@ -123,11 +118,6 @@ l2 { regulator-max-microvolt = <1200000>; }; - l3 { - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1287500>; - }; - l4 { regulator-min-microvolt = <2050000>; regulator-max-microvolt = <2050000>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi index 513e433aa5f3..539823b2c36e 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi @@ -50,13 +50,13 @@ &rpm_requests { smd_rpm_regulators: pm8916-regulators { compatible = "qcom,rpm-pm8916-regulators"; - pm8916_s1: s1 {}; + /* pm8916_s1 is managed by rpmpd (MSM8916_VDDCX) */ pm8916_s3: s3 {}; pm8916_s4: s4 {}; pm8916_l1: l1 {}; pm8916_l2: l2 {}; - pm8916_l3: l3 {}; + /* pm8916_l3 is managed by rpmpd (MSM8916_VDDMX) */ pm8916_l4: l4 {}; pm8916_l5: l5 {}; pm8916_l6: l6 {}; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi index b18d21e42f59..0b0dfd3059de 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi @@ -164,11 +164,6 @@ &smd_rpm_regulators { vdd_l4_l5_l6-supply = <&pm8916_s4>; vdd_l7-supply = <&pm8916_s4>; - s1 { - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1300000>; - }; - s3 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1300000>; @@ -189,11 +184,6 @@ l2 { regulator-max-microvolt = <1200000>; }; - l3 { - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1287500>; - }; - l4 { regulator-min-microvolt = <2050000>; regulator-max-microvolt = <2050000>; -- 2.28.0