mbox series

[v5,0/8] Add power domain driver for corners on msm8996/sdm845

Message ID 20181204052119.806-1-rnayak@codeaurora.org
Headers show
Series Add power domain driver for corners on msm8996/sdm845 | expand

Message

Rajendra Nayak Dec. 4, 2018, 5:21 a.m. UTC
Hi Rob,

This series is mainly pending your review/ack for the DT parts.
Rest of the genpd parts are reviewed and acked by both Viresh
and Ulf.

Changes in v5:
* First 6 patches are unchanged
* Patch 7/8 adds the DT node for rpmh power-controller on sdm845 and the
corresponding OPP tables for it to describe the performance states
* Patch 8/8 adds a parent/child relationship across mx/cx and mx_ao/cx_ao
as needed on sdm845 platform. This patch is dependent on the series from
Viresh [1] which adds support to propogate performance states across the
power domain hierarchy which is still being reviewed

Changes in v4:
* Included the patch to add qcom-opp bindings (dropped accidentally in v3)
* merged the patches to add bindings for rpm and rpmh, added consumer binding example
* Made the drivers built in, removed .remove
* Added better description in changelog for PATCH 6/6
* Updated rpmhpd_aggregate_corner() based on Davids feedback
* rpmhpd_set_performance_state() returns max corner, in cases where its called
with an INT_MAX
* Dropped the patch to max vote on all corners at init, the patch did not
work anyway, and it shouldn't be needed now

Changes in v3:
* Bindings split into seperate patches
* Bindings updated to remove duplicate OPP table phandles
* DT headers defining macros for Power domain indexes and OPP levels
* Optimisations to use rpmh_write_async() whereever applicable
* Fixed up handling of ACTIVE_ONLY/WAKE_ONLY/SLEEP voting for RPMh
* Fixed the vlvl to hlvl conversions in set_performance
* Other minor fixes based on review of v2
* TODO: This series does not handle the case where all VDD_MX votes
should be higher than VDD_CX from APPs, as pointed out
by David Collins in v2. This needs support at genpd to propogate performance
state up the parents, if we model these as Parent/Child to handle the
interdependency.

Changes in v2:
* added a power domain driver for sdm845 which supports communicating to RPMh
* dropped the changes to sdhc driver to move over to using OPP
as there is active discussion on using OPP as the interface vs
handling all of it in clock drivers
* Other minor binding updates based on review of v1

With performance state support for genpd/OPP merged, this is an effort
to model a power domain driver to communicate corner/level
values for qualcomm platforms to RPM (Remote Power Manager) and RPMh.

[1] https://lkml.org/lkml/2018/11/26/333

Rajendra Nayak (8):
  dt-bindings: opp: Introduce qcom-opp bindings
  dt-bindings: power: Add qcom rpm power domain driver bindings
  soc: qcom: rpmpd: Add a Power domain driver to model corners
  soc: qcom: rpmpd: Add support for get/set performance state
  arm64: dts: msm8996: Add rpmpd device node
  soc: qcom: rpmhpd: Add RPMh Power domain driver
  arm64: dts: sdm845: Add rpmh powercontroller node
  soc: qcom: rpmhpd: Mark mx as a parent for cx

 .../devicetree/bindings/opp/qcom-opp.txt      |  25 +
 .../devicetree/bindings/power/qcom,rpmpd.txt  | 146 ++++++
 arch/arm64/boot/dts/qcom/msm8996.dtsi         |  34 ++
 arch/arm64/boot/dts/qcom/sdm845.dtsi          |  51 ++
 drivers/soc/qcom/Kconfig                      |  18 +
 drivers/soc/qcom/Makefile                     |   2 +
 drivers/soc/qcom/rpmhpd.c                     | 442 ++++++++++++++++++
 drivers/soc/qcom/rpmpd.c                      | 340 ++++++++++++++
 include/dt-bindings/power/qcom-rpmpd.h        |  39 ++
 9 files changed, 1097 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/opp/qcom-opp.txt
 create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmpd.txt
 create mode 100644 drivers/soc/qcom/rpmhpd.c
 create mode 100644 drivers/soc/qcom/rpmpd.c
 create mode 100644 include/dt-bindings/power/qcom-rpmpd.h

Comments

Viresh Kumar Dec. 4, 2018, 5:25 a.m. UTC | #1
On 04-12-18, 10:51, Rajendra Nayak wrote:
> Add the DT node for the rpmhpd powercontroller.
> 
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
>  arch/arm64/boot/dts/qcom/sdm845.dtsi | 51 ++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Viresh Kumar Dec. 4, 2018, 5:26 a.m. UTC | #2
On 04-12-18, 10:51, Rajendra Nayak wrote:
> Specify the active + sleep and active-only MX power domains as
> the parents of the corresponding CX power domains. This will ensure that
> performance state requests on CX automatically generate equivalent requests
> on MX power domains.
> 
> This is used to enforce a requirement that exists for various
> hardware blocks on SDM845 that MX performance state >= CX performance
> state for a given operating frequency.
> 
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
> This patch is dependent on the series from
> Viresh [1] which adds support to propogate performance states across the
> power domain hierarchy which is still being reviewed.
> 
> [1] https://lkml.org/lkml/2018/11/26/333
> 
>  drivers/soc/qcom/rpmhpd.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Stephen Boyd Dec. 4, 2018, 11:12 p.m. UTC | #3
Overall looks good to me, just some nitpicks around modules and
includes.

Quoting Rajendra Nayak (2018-12-03 21:21:14)
> The Power domains for corners just pass the performance state set by the
> consumers to the RPM (Remote Power manager) which then takes care
> of setting the appropriate voltage on the corresponding rails to
> meet the performance needs.
> 
> We add all Power domain data needed on msm8996 here. This driver can easily
> be extended by adding data for other qualcomm SoCs as well.
> 

Why is "Power" capitalized in power domain?

> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index f25b54cd6cf8..f1b25fdcf2ad 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -21,3 +21,4 @@ obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
>  obj-$(CONFIG_QCOM_APR) += apr.o
>  obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
>  obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
> +obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
> diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
> new file mode 100644
> index 000000000000..a0b9f122d793
> --- /dev/null
> +++ b/drivers/soc/qcom/rpmpd.c
> @@ -0,0 +1,294 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
> +
> +#include <linux/err.h>
> +#include <linux/export.h>

And what is exported?

> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>

Is it a module? It's only bool so I don't think so.

> +#include <linux/mutex.h>
> +#include <linux/pm_domain.h>
> +#include <linux/mfd/qcom_rpm.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/soc/qcom/smd-rpm.h>
> +
> +#include <dt-bindings/mfd/qcom-rpm.h>
> +#include <dt-bindings/power/qcom-rpmpd.h>
> +
> +#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
> +
> +/* Resource types */
> +#define RPMPD_SMPA 0x61706d73
> +#define RPMPD_LDOA 0x616f646c
> +
> +/* Operation Keys */
> +#define KEY_CORNER             0x6e726f63 /* corn */
> +#define KEY_ENABLE             0x6e657773 /* swen */
> +#define KEY_FLOOR_CORNER       0x636676   /* vfc */
> +
> +#define DEFINE_RPMPD_CORN_SMPA(_platform, _name, _active, r_id)                \
> +       static struct rpmpd _platform##_##_active;                      \
> +       static struct rpmpd _platform##_##_name = {                     \
> +               .pd = { .name = #_name, },                              \
> +               .peer = &_platform##_##_active,                         \
> +               .res_type = RPMPD_SMPA,                                 \
> +               .res_id = r_id,                                         \
> +               .key = KEY_CORNER,                                      \
> +       };                                                              \
> +       static struct rpmpd _platform##_##_active = {                   \
> +               .pd = { .name = #_active, },                            \
> +               .peer = &_platform##_##_name,                           \
> +               .active_only = true,                                    \
> +               .res_type = RPMPD_SMPA,                                 \
> +               .res_id = r_id,                                         \
> +               .key = KEY_CORNER,                                      \
> +       }
> +
> +#define DEFINE_RPMPD_CORN_LDOA(_platform, _name, r_id)                 \
> +       static struct rpmpd _platform##_##_name = {                     \
> +               .pd = { .name = #_name, },                              \
> +               .res_type = RPMPD_LDOA,                                 \
> +               .res_id = r_id,                                         \
> +               .key = KEY_CORNER,                                      \
> +       }
> +
> +#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type)               \
> +       static struct rpmpd _platform##_##_name = {                     \
> +               .pd = { .name = #_name, },                              \
> +               .res_type = r_type,                                     \
> +               .res_id = r_id,                                         \
> +               .key = KEY_FLOOR_CORNER,                                \
> +       }
> +
> +#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id)                  \
> +       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA)
> +
> +#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id)                  \
> +       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA)
> +
> +struct rpmpd_req {
> +       __le32 key;
> +       __le32 nbytes;
> +       __le32 value;
> +};
> +
> +struct rpmpd {
> +       struct generic_pm_domain pd;
> +       struct rpmpd *peer;
> +       const bool active_only;
> +       unsigned int corner;
> +       bool enabled;
> +       const char *res_name;
> +       const int res_type;
> +       const int res_id;
> +       struct qcom_smd_rpm *rpm;
> +       __le32 key;
> +};
> +
> +struct rpmpd_desc {
> +       struct rpmpd **rpmpds;
> +       size_t num_pds;
> +};
> +
> +static DEFINE_MUTEX(rpmpd_lock);
> +
> +/* msm8996 RPM Power domains */
> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddcx, vddcx_ao, 1);
> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddmx, vddmx_ao, 2);
> +DEFINE_RPMPD_CORN_LDOA(msm8996, vddsscx, 26);

Mmm.. CORN...

> +
> +DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1);
> +DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26);
> +
> +static struct rpmpd *msm8996_rpmpds[] = {
> +       [MSM8996_VDDCX] =       &msm8996_vddcx,
> +       [MSM8996_VDDCX_AO] =    &msm8996_vddcx_ao,
> +       [MSM8996_VDDCX_VFC] =   &msm8996_vddcx_vfc,
> +       [MSM8996_VDDMX] =       &msm8996_vddmx,
> +       [MSM8996_VDDMX_AO] =    &msm8996_vddmx_ao,
> +       [MSM8996_VDDSSCX] =     &msm8996_vddsscx,
> +       [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc,
> +};
> +
[...]
> +       }
> +
> +       return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
> +}
> +
> +static struct platform_driver rpmpd_driver = {
> +       .driver = {
> +               .name = "qcom-rpmpd",
> +               .of_match_table = rpmpd_match_table,

suppress bind attributes here?

> +       },
> +       .probe = rpmpd_probe,

Because there isn't a remove function to tear down the genpds.

> +};
> +
> +static int __init rpmpd_init(void)
> +{
> +       return platform_driver_register(&rpmpd_driver);
> +}
> +core_initcall(rpmpd_init);
> +
> +static void __exit rpmpd_exit(void)
> +{
> +       platform_driver_unregister(&rpmpd_driver);
> +}
> +module_exit(rpmpd_exit);
> +
> +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:qcom-rpmpd");

Is this MODULE_ALIAS required? I thought this wasn't useful because it's
auto-generated or something like that. Also, this is bool so these can
all go away unless it becomes tristate.
Stephen Boyd Dec. 4, 2018, 11:14 p.m. UTC | #4
Quoting Rajendra Nayak (2018-12-03 21:21:15)
> @@ -221,6 +224,47 @@ static int rpmpd_power_off(struct generic_pm_domain *domain)
>         return ret;
>  }
>  
> +static int rpmpd_set_performance(struct generic_pm_domain *domain,
> +                                unsigned int state)
> +{
> +       int ret = 0;
> +       struct rpmpd *pd = domain_to_rpmpd(domain);
> +
> +       mutex_lock(&rpmpd_lock);
> +
> +       if (state > MAX_RPMPD_STATE)
> +               goto out;

Does this need to be under the mutex lock? Doesn't look like it.

> +
> +       pd->corner = state;
> +
> +       if (!pd->enabled && (pd->key != KEY_FLOOR_CORNER))

Please drop useless parenthesis.

> +               goto out;
> +
> +       ret = rpmpd_aggregate_corner(pd);
> +
> +out:
> +       mutex_unlock(&rpmpd_lock);
> +
> +       return ret;
> +}
> +
> +static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd,
> +                                         struct dev_pm_opp *opp)
> +{
> +       struct device_node *np;
> +       unsigned int corner = 0;
> +
> +       np = dev_pm_opp_get_of_node(opp);
> +       if (of_property_read_u32(np, "qcom,level", &corner)) {
> +               pr_err("%s: missing 'qcom,level' property\n", __func__);

We leak np reference here, assuming dev_pm_opp_get_of_node() returns an
of_node_get() pointer to the caller.

> +               return 0;
> +       }
> +
> +       of_node_put(np);

This same code exists twice. Perhaps a helper needs to exist for
qcom_rpm_get_performance() to pull the number out of the DT.

> +
> +       return corner;
> +}
Stephen Boyd Dec. 4, 2018, 11:16 p.m. UTC | #5
Quoting Rajendra Nayak (2018-12-03 21:21:18)
> diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> index b72bdb0a31a5..a6d0cd8d17b0 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> @@ -1324,6 +1325,56 @@
>                                 compatible = "qcom,sdm845-rpmh-clk";
>                                 #clock-cells = <1>;
>                         };
> +
> +                       rpmhpd: power-controller {
> +                               compatible = "qcom,sdm845-rpmhpd";
> +                               #power-domain-cells = <1>;
> +                               operating-points-v2 = <&rpmhpd_opp_table>;
> +                       };
> +
> +                       rpmhpd_opp_table: opp-table {

This table should go somewhere else? I don't understand why it's in the
rpmh node because it's not an rpmh device. Does it go to the root? Or
does it go under rpmhpd itself? I'm not sure.
Rajendra Nayak Dec. 5, 2018, 7:01 a.m. UTC | #6
On 12/5/2018 4:42 AM, Stephen Boyd wrote:
> Overall looks good to me, just some nitpicks around modules and
> includes.

Thanks for the review, I will fix up all your concerns below and respin soon.

> 
> Quoting Rajendra Nayak (2018-12-03 21:21:14)
>> The Power domains for corners just pass the performance state set by the
>> consumers to the RPM (Remote Power manager) which then takes care
>> of setting the appropriate voltage on the corresponding rails to
>> meet the performance needs.
>>
>> We add all Power domain data needed on msm8996 here. This driver can easily
>> be extended by adding data for other qualcomm SoCs as well.
>>
> 
> Why is "Power" capitalized in power domain?
> 
>> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
>> index f25b54cd6cf8..f1b25fdcf2ad 100644
>> --- a/drivers/soc/qcom/Makefile
>> +++ b/drivers/soc/qcom/Makefile
>> @@ -21,3 +21,4 @@ obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
>>   obj-$(CONFIG_QCOM_APR) += apr.o
>>   obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
>>   obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
>> +obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
>> diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
>> new file mode 100644
>> index 000000000000..a0b9f122d793
>> --- /dev/null
>> +++ b/drivers/soc/qcom/rpmpd.c
>> @@ -0,0 +1,294 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
>> +
>> +#include <linux/err.h>
>> +#include <linux/export.h>
> 
> And what is exported?
> 
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
> 
> Is it a module? It's only bool so I don't think so.
> 
>> +#include <linux/mutex.h>
>> +#include <linux/pm_domain.h>
>> +#include <linux/mfd/qcom_rpm.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/soc/qcom/smd-rpm.h>
>> +
>> +#include <dt-bindings/mfd/qcom-rpm.h>
>> +#include <dt-bindings/power/qcom-rpmpd.h>
>> +
>> +#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
>> +
>> +/* Resource types */
>> +#define RPMPD_SMPA 0x61706d73
>> +#define RPMPD_LDOA 0x616f646c
>> +
>> +/* Operation Keys */
>> +#define KEY_CORNER             0x6e726f63 /* corn */
>> +#define KEY_ENABLE             0x6e657773 /* swen */
>> +#define KEY_FLOOR_CORNER       0x636676   /* vfc */
>> +
>> +#define DEFINE_RPMPD_CORN_SMPA(_platform, _name, _active, r_id)                \
>> +       static struct rpmpd _platform##_##_active;                      \
>> +       static struct rpmpd _platform##_##_name = {                     \
>> +               .pd = { .name = #_name, },                              \
>> +               .peer = &_platform##_##_active,                         \
>> +               .res_type = RPMPD_SMPA,                                 \
>> +               .res_id = r_id,                                         \
>> +               .key = KEY_CORNER,                                      \
>> +       };                                                              \
>> +       static struct rpmpd _platform##_##_active = {                   \
>> +               .pd = { .name = #_active, },                            \
>> +               .peer = &_platform##_##_name,                           \
>> +               .active_only = true,                                    \
>> +               .res_type = RPMPD_SMPA,                                 \
>> +               .res_id = r_id,                                         \
>> +               .key = KEY_CORNER,                                      \
>> +       }
>> +
>> +#define DEFINE_RPMPD_CORN_LDOA(_platform, _name, r_id)                 \
>> +       static struct rpmpd _platform##_##_name = {                     \
>> +               .pd = { .name = #_name, },                              \
>> +               .res_type = RPMPD_LDOA,                                 \
>> +               .res_id = r_id,                                         \
>> +               .key = KEY_CORNER,                                      \
>> +       }
>> +
>> +#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type)               \
>> +       static struct rpmpd _platform##_##_name = {                     \
>> +               .pd = { .name = #_name, },                              \
>> +               .res_type = r_type,                                     \
>> +               .res_id = r_id,                                         \
>> +               .key = KEY_FLOOR_CORNER,                                \
>> +       }
>> +
>> +#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id)                  \
>> +       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA)
>> +
>> +#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id)                  \
>> +       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA)
>> +
>> +struct rpmpd_req {
>> +       __le32 key;
>> +       __le32 nbytes;
>> +       __le32 value;
>> +};
>> +
>> +struct rpmpd {
>> +       struct generic_pm_domain pd;
>> +       struct rpmpd *peer;
>> +       const bool active_only;
>> +       unsigned int corner;
>> +       bool enabled;
>> +       const char *res_name;
>> +       const int res_type;
>> +       const int res_id;
>> +       struct qcom_smd_rpm *rpm;
>> +       __le32 key;
>> +};
>> +
>> +struct rpmpd_desc {
>> +       struct rpmpd **rpmpds;
>> +       size_t num_pds;
>> +};
>> +
>> +static DEFINE_MUTEX(rpmpd_lock);
>> +
>> +/* msm8996 RPM Power domains */
>> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddcx, vddcx_ao, 1);
>> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddmx, vddmx_ao, 2);
>> +DEFINE_RPMPD_CORN_LDOA(msm8996, vddsscx, 26);
> 
> Mmm.. CORN...
> 
>> +
>> +DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1);
>> +DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26);
>> +
>> +static struct rpmpd *msm8996_rpmpds[] = {
>> +       [MSM8996_VDDCX] =       &msm8996_vddcx,
>> +       [MSM8996_VDDCX_AO] =    &msm8996_vddcx_ao,
>> +       [MSM8996_VDDCX_VFC] =   &msm8996_vddcx_vfc,
>> +       [MSM8996_VDDMX] =       &msm8996_vddmx,
>> +       [MSM8996_VDDMX_AO] =    &msm8996_vddmx_ao,
>> +       [MSM8996_VDDSSCX] =     &msm8996_vddsscx,
>> +       [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc,
>> +};
>> +
> [...]
>> +       }
>> +
>> +       return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
>> +}
>> +
>> +static struct platform_driver rpmpd_driver = {
>> +       .driver = {
>> +               .name = "qcom-rpmpd",
>> +               .of_match_table = rpmpd_match_table,
> 
> suppress bind attributes here?
> 
>> +       },
>> +       .probe = rpmpd_probe,
> 
> Because there isn't a remove function to tear down the genpds.
> 
>> +};
>> +
>> +static int __init rpmpd_init(void)
>> +{
>> +       return platform_driver_register(&rpmpd_driver);
>> +}
>> +core_initcall(rpmpd_init);
>> +
>> +static void __exit rpmpd_exit(void)
>> +{
>> +       platform_driver_unregister(&rpmpd_driver);
>> +}
>> +module_exit(rpmpd_exit);
>> +
>> +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("platform:qcom-rpmpd");
> 
> Is this MODULE_ALIAS required? I thought this wasn't useful because it's
> auto-generated or something like that. Also, this is bool so these can
> all go away unless it becomes tristate.
>
Rajendra Nayak Dec. 5, 2018, 7:03 a.m. UTC | #7
On 12/5/2018 4:44 AM, Stephen Boyd wrote:
> Quoting Rajendra Nayak (2018-12-03 21:21:15)
>> @@ -221,6 +224,47 @@ static int rpmpd_power_off(struct generic_pm_domain *domain)
>>          return ret;
>>   }
>>   
>> +static int rpmpd_set_performance(struct generic_pm_domain *domain,
>> +                                unsigned int state)
>> +{
>> +       int ret = 0;
>> +       struct rpmpd *pd = domain_to_rpmpd(domain);
>> +
>> +       mutex_lock(&rpmpd_lock);
>> +
>> +       if (state > MAX_RPMPD_STATE)
>> +               goto out;
> 
> Does this need to be under the mutex lock? Doesn't look like it.

Nope, will move it out.

> 
>> +
>> +       pd->corner = state;
>> +
>> +       if (!pd->enabled && (pd->key != KEY_FLOOR_CORNER))
> 
> Please drop useless parenthesis.

sure

> 
>> +               goto out;
>> +
>> +       ret = rpmpd_aggregate_corner(pd);
>> +
>> +out:
>> +       mutex_unlock(&rpmpd_lock);
>> +
>> +       return ret;
>> +}
>> +
>> +static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd,
>> +                                         struct dev_pm_opp *opp)
>> +{
>> +       struct device_node *np;
>> +       unsigned int corner = 0;
>> +
>> +       np = dev_pm_opp_get_of_node(opp);
>> +       if (of_property_read_u32(np, "qcom,level", &corner)) {
>> +               pr_err("%s: missing 'qcom,level' property\n", __func__);
> 
> We leak np reference here, assuming dev_pm_opp_get_of_node() returns an
> of_node_get() pointer to the caller.

good catch, will fix.

> 
>> +               return 0;
>> +       }
>> +
>> +       of_node_put(np);
> 
> This same code exists twice. Perhaps a helper needs to exist for
> qcom_rpm_get_performance() to pull the number out of the DT.

Sure I can make both drivers use a common helper instead of duplicating it.

> 
>> +
>> +       return corner;
>> +}
Rajendra Nayak Dec. 5, 2018, 7:07 a.m. UTC | #8
On 12/5/2018 4:46 AM, Stephen Boyd wrote:
> Quoting Rajendra Nayak (2018-12-03 21:21:18)
>> diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
>> index b72bdb0a31a5..a6d0cd8d17b0 100644
>> --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
>> +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
>> @@ -1324,6 +1325,56 @@
>>                                  compatible = "qcom,sdm845-rpmh-clk";
>>                                  #clock-cells = <1>;
>>                          };
>> +
>> +                       rpmhpd: power-controller {
>> +                               compatible = "qcom,sdm845-rpmhpd";
>> +                               #power-domain-cells = <1>;
>> +                               operating-points-v2 = <&rpmhpd_opp_table>;
>> +                       };
>> +
>> +                       rpmhpd_opp_table: opp-table {
> 
> This table should go somewhere else? I don't understand why it's in the
> rpmh node because it's not an rpmh device. Does it go to the root? Or
> does it go under rpmhpd itself? I'm not sure.

I could move it to root perhaps, we seem to do that atleast in the case of
GPU. The power domain bindings (Documentation/devicetree/bindings/power/power_domain.txt)
seem to suggest it can't be under the power-controller node itself.
Rajendra Nayak Dec. 5, 2018, 10:11 a.m. UTC | #9
On 12/5/2018 12:33 PM, Rajendra Nayak wrote:
>>
>>> +               return 0;
>>> +       }
>>> +
>>> +       of_node_put(np);
>>
>> This same code exists twice. Perhaps a helper needs to exist for
>> qcom_rpm_get_performance() to pull the number out of the DT.
> 
> Sure I can make both drivers use a common helper instead of duplicating it.

which would mean I will need to create a new file just to define the
common helper. Does that seem like an overkill?
Stephen Boyd Dec. 5, 2018, 8:46 p.m. UTC | #10
Quoting Rajendra Nayak (2018-12-05 02:11:22)
> 
> On 12/5/2018 12:33 PM, Rajendra Nayak wrote:
> >>
> >>> +               return 0;
> >>> +       }
> >>> +
> >>> +       of_node_put(np);
> >>
> >> This same code exists twice. Perhaps a helper needs to exist for
> >> qcom_rpm_get_performance() to pull the number out of the DT.
> > 
> > Sure I can make both drivers use a common helper instead of duplicating it.
> 
> which would mean I will need to create a new file just to define the
> common helper. Does that seem like an overkill?

Maybe put it in the genpd code and let it take a const char *name
argument that picks out the property that drivers want to look at? That
way other OPP properties can be picked out with a simple call to the
function but it's generic enough to be used in other places.
Rob Herring Dec. 7, 2018, 5:36 p.m. UTC | #11
On Wed, Dec 05, 2018 at 12:37:29PM +0530, Rajendra Nayak wrote:
> 
> 
> On 12/5/2018 4:46 AM, Stephen Boyd wrote:
> > Quoting Rajendra Nayak (2018-12-03 21:21:18)
> > > diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> > > index b72bdb0a31a5..a6d0cd8d17b0 100644
> > > --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
> > > +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> > > @@ -1324,6 +1325,56 @@
> > >                                  compatible = "qcom,sdm845-rpmh-clk";
> > >                                  #clock-cells = <1>;
> > >                          };
> > > +
> > > +                       rpmhpd: power-controller {
> > > +                               compatible = "qcom,sdm845-rpmhpd";
> > > +                               #power-domain-cells = <1>;
> > > +                               operating-points-v2 = <&rpmhpd_opp_table>;
> > > +                       };
> > > +
> > > +                       rpmhpd_opp_table: opp-table {
> > 
> > This table should go somewhere else? I don't understand why it's in the
> > rpmh node because it's not an rpmh device. Does it go to the root? Or
> > does it go under rpmhpd itself? I'm not sure.
> 
> I could move it to root perhaps, we seem to do that atleast in the case of
> GPU. The power domain bindings (Documentation/devicetree/bindings/power/power_domain.txt)
> seem to suggest it can't be under the power-controller node itself.

Why not? I don't see anything forbidding that like already having some 
other type of child nodes. It's a little weird to have 
operating-points-v2 point to a child node, but that will still work.

Rob