OPP: Add new configuration interface: dev_pm_opp_set_config()
Subsystems (19)
Viresh Kumar
maintainerv3 cover OPP: Add new configuration interface: dev_pm_opp_set_config()
Hello,
We have too many configuration specific APIs currently, six of them already, like dev_pm_opp_set_regulators(). This makes it complex/messy for both the OPP core and its users to manage. There is also code redundancy in these APIs, in the way they add/manage the OPP table specific stuff.
This patch series is an attempt to simplify these interfaces by adding a new interface, dev_pm_opp_set_config(), which is now used by all the existing ones. This series also migrates few users to the new API, where multiple configurations were required and rest are updated for API interface changes.
This is pushed here:
git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git opp/linux-next
This was earlier tested by various folks, I have tested it again on hikey board, it will get further tested on linux-next in the coming days. Build test is already done by Linaro's bot for enough platform though.
The entire patchset shall get merged via the OPP tree in 5.20-rc1, please do not merge individual patches.
V2->V3:
- Merged two patchsets:
[PATCH V2 00/30] OPP: Add new configuration interface: dev_pm_opp_set_config() [PATCH V2 0/5] OPP: Replace custom set_opp() with config_regulators()
- The existing APIs aren't removed anymore, but are made to use the new core API to set various configurations (Greg KH).
- clk-names and regulator-names are NULL terminated arrays now (Greg KH).
- New interface added: dev_pm_opp_set_config_regulators().
V1->V2:
- dev_pm_opp_set_config() doesn't return the OPP table anymore, but a token allocated with xa_alloc(). The same needs to be passed to clear-config API.
- Updated all users according to that as well.
- The clk_names interface is updated to allow multiple clocks.
- Converted few // comments to /* */.
- Added tags by few people.
- Dropped the last patch to rearrange stuff, not required anymore.
Thanks.
--
Viresh
Viresh Kumar (20):
OPP: Track if clock name is configured by platform
OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
OPP: Add dev_pm_opp_set_config() and friends
cpufreq: qcom-nvmem: Migrate to dev_pm_opp_set_config()
cpufreq: sti: Migrate to dev_pm_opp_set_config()
cpufreq: ti: Migrate to dev_pm_opp_set_config()
drm/lima: Migrate to dev_pm_opp_set_config()
soc/tegra: Add comment over devm_pm_opp_set_clkname() soc/tegra: Migrate to dev_pm_opp_set_config()
OPP: Migrate set-regulators API to use set-config helpers
OPP: Migrate set-supported-hw API to use set-config helpers
OPP: Migrate set-clk-name API to use set-config helpers
OPP: Migrate set-opp-helper API to use set-config helpers
OPP: Migrate attach-genpd API to use set-config helpers
OPP: Migrate set-prop-name helper API to use set-config helpers
OPP: Add support for config_regulators() helper
OPP: Make _generic_set_opp_regulator() a config_regulators() interface
OPP: Add dev_pm_opp_get_supplies()
OPP: ti: Migrate to dev_pm_opp_set_config_regulators()
OPP: Remove custom OPP helper support
drivers/cpufreq/cpufreq-dt.c | 19 +- drivers/cpufreq/imx-cpufreq-dt.c | 12 +- drivers/cpufreq/qcom-cpufreq-nvmem.c | 109 +-- drivers/cpufreq/sti-cpufreq.c | 27 +- drivers/cpufreq/sun50i-cpufreq-nvmem.c | 31 +- drivers/cpufreq/tegra20-cpufreq.c | 12 +- drivers/cpufreq/ti-cpufreq.c | 42 +- drivers/devfreq/exynos-bus.c | 21 +- drivers/gpu/drm/lima/lima_devfreq.c | 12 +- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 4 +- drivers/memory/tegra/tegra124-emc.c | 11 +- drivers/opp/core.c | 821 +++++++++----------- drivers/opp/opp.h | 32 +- drivers/opp/ti-opp-supply.c | 77 +- drivers/soc/tegra/common.c | 49 +- drivers/soc/tegra/pmc.c | 4 +- include/linux/pm_opp.h | 295 ++++--- 17 files changed, 750 insertions(+), 828 deletions(-)
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 1/20 OPP: Track if clock name is configured by platform
Track if the clock name is configured by the platform or not. This is a preparatory change and will be used by later commits. This also makes the behavior of the clkname API similar to other ones, which allow repeated calls to the same API for each CPU.
--- drivers/opp/core.c | 7 +++++++ drivers/opp/opp.h | 2 ++ 2 files changed, 9 insertions(+)
drivers/opp/core.c +7 -0
@@ -2277,6 +2277,10 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name) goto err; } +/* Another CPU that shares the OPP table has set the clkname ? */ +if (opp_table->clk_configured) +return opp_table; +/* clk shouldn't be initialized at this point */ if (WARN_ON (opp_table->clk)) { ret = -EBUSY ;
@@ -2291,6 +2295,8 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name) goto err; } + opp_table->clk_configured = true; +return opp_table; err:
@@ -2311,6 +2317,7 @@ void dev_pm_opp_put_clkname(struct opp_table *opp_table)clk_put (opp_table->clk); opp_table->clk =ERR_PTR (-EINVAL ); + opp_table->clk_configured = false;dev_pm_opp_put_opp_table (opp_table); }
drivers/opp/opp.h +2 -0
@@ -149,6 +149,7 @@ enum opp_table_access {* @supported_hw: Array of version number to support. * @supported_hw_count: Number of elements in supported_hw array. * @prop_name: A name to postfix to many DT properties, while parsing them. +* @clk_configured: Clock name is configured by the platform. * @clk: Device's clock handle * @regulators: Supply regulators * @regulator_count: Number of power supply regulators. Its value can be -1
@@ -200,6 +201,7 @@ struct opp_table {unsigned int *supported_hw;unsigned int supported_hw_count;const char *prop_name; +bool clk_configured;struct clk *clk;struct regulator **regulators;int regulator_count;
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 2/20 OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
In reply to Viresh KumarMake dev_pm_opp_set_regulators() accept a NULL terminated list of names instead of making the callers keep the two parameters in sync, which creates an opportunity for bugs to get in.
--- drivers/cpufreq/cpufreq-dt.c | 9 ++++----- drivers/cpufreq/ti-cpufreq.c | 7 +++---- drivers/devfreq/exynos-bus.c | 4 ++-- drivers/gpu/drm/lima/lima_devfreq.c | 3 ++- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 4 ++-- drivers/opp/core.c | 18 ++++++++++++------ drivers/soc/tegra/pmc.c | 4 ++-- include/linux/pm_opp.h | 9 ++++----- 8 files changed, 31 insertions(+), 27 deletions(-)
drivers/cpufreq/cpufreq-dt.c +4 -5
@@ -193,7 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)struct private_data *priv;struct device *cpu_dev;bool fallback = false; -const char *reg_name; +const char *reg_name[] = {NULL ,NULL };int ret;/* Check if this CPU is already covered by some other policy */
@@ -218,10 +218,9 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)* OPP layer will be taking care of regulators now, but it needs to know * the name of the regulator first. */ - reg_name =find_supply_name (cpu_dev); -if (reg_name) { - priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, ®_name, -1 ); + reg_name[0 ] =find_supply_name (cpu_dev); +if (reg_name[0 ]) { + priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, reg_name);if (IS_ERR (priv->opp_table)) { ret =PTR_ERR (priv->opp_table);if (ret != -EPROBE_DEFER )
drivers/cpufreq/ti-cpufreq.c +3 -4
@@ -173,7 +173,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {* seems to always read as 0). */ -static const char *const omap3_reg_names[] = {"cpu0" ,"vbb" }; +static const char *const omap3_reg_names[] = {"cpu0" ,"vbb" ,NULL };static struct ti_cpufreq_soc_data omap36xx_soc_data = { .reg_names = omap3_reg_names,
@@ -326,7 +326,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)const struct of_device_id *match;struct opp_table *ti_opp_table;struct ti_cpufreq_data *opp_data; -const char *const default_reg_names[] = {"vdd" ,"vbb" }; +const char *const default_reg_names[] = {"vdd" ,"vbb" ,NULL };int ret; match =dev_get_platdata (&pdev->dev);
@@ -387,8 +387,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)if (opp_data->soc_data->reg_names) reg_names = opp_data->soc_data->reg_names; ti_opp_table =dev_pm_opp_set_regulators (opp_data->cpu_dev, - reg_names, -ARRAY_SIZE (default_reg_names)); + reg_names);if (IS_ERR (ti_opp_table)) {dev_pm_opp_put_supported_hw (opp_data->opp_table); ret =PTR_ERR (ti_opp_table);
drivers/devfreq/exynos-bus.c +2 -2
@@ -180,10 +180,10 @@ static int exynos_bus_parent_parse_of(struct device_node *np, {struct device *dev = bus->dev;struct opp_table *opp_table; -const char *vdd ="vdd" ; +const char *supplies[] = {"vdd" ,NULL };int i, ret, count, size; - opp_table =dev_pm_opp_set_regulators (dev, &vdd,1 ); + opp_table =dev_pm_opp_set_regulators (dev, supplies);if (IS_ERR (opp_table)) { ret =PTR_ERR (opp_table);dev_err (dev,"failed to set regulators %d\n" , ret);
drivers/gpu/drm/lima/lima_devfreq.c +2 -1
@@ -111,6 +111,7 @@ int lima_devfreq_init(struct lima_device *ldev)struct dev_pm_opp *opp;unsigned long cur_freq;int ret; +const char *regulator_names[] = {"mali" ,NULL };if (!device_property_present (dev,"operating-points-v2" ))/* Optional, continue without devfreq */
@@ -122,7 +123,7 @@ int lima_devfreq_init(struct lima_device *ldev)if (ret)return ret; - ret =devm_pm_opp_set_regulators (dev, (const char *[]){"mali" },1 ); + ret =devm_pm_opp_set_regulators (dev, regulator_names);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV )
drivers/gpu/drm/panfrost/panfrost_devfreq.c +2 -2
@@ -91,6 +91,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)struct devfreq *devfreq;struct thermal_cooling_device *cooling;struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; +const char *supplies[] = { pfdev->comp->supply_names[0 ],NULL };if (pfdev->comp->num_supplies >1 ) {/*
@@ -101,8 +102,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)return 0 ; } - ret =devm_pm_opp_set_regulators (dev, pfdev->comp->supply_names, - pfdev->comp->num_supplies); + ret =devm_pm_opp_set_regulators (dev, supplies);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV ) {
drivers/opp/core.c +12 -6
@@ -2105,13 +2105,20 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);* This must be called before any OPPs are initialized for the device. */ struct opp_table *dev_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {struct dev_pm_opp_supply *supplies; +const char *const *temp = names;struct opp_table *opp_table;struct regulator *reg; -int ret, i; +int count =0 , ret, i; + +/* Count number of regulators */ +while (*temp++) + count++; + +if (!count) +return ERR_PTR (-EINVAL ); opp_table =_add_opp_table (dev, false);if (IS_ERR (opp_table))
@@ -2236,12 +2243,11 @@ static void devm_pm_opp_regulators_release(void *data)* Return: 0 on success and errorno otherwise. */ int devm_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {struct opp_table *opp_table; - opp_table =dev_pm_opp_set_regulators (dev, names, count); + opp_table =dev_pm_opp_set_regulators (dev, names);if (IS_ERR (opp_table))return PTR_ERR (opp_table);
drivers/soc/tegra/pmc.c +2 -2
@@ -1384,7 +1384,7 @@ tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,static int tegra_pmc_core_pd_add (struct tegra_pmc *pmc,struct device_node *np) {struct generic_pm_domain *genpd; -const char *rname ="core" ; +const char *rname[] = {"core" ,NULL };int err; genpd =devm_kzalloc (pmc->dev,sizeof (*genpd),GFP_KERNEL );
@@ -1395,7 +1395,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; - err =devm_pm_opp_set_regulators (pmc->dev, &rname,1 ); + err =devm_pm_opp_set_regulators (pmc->dev, rname);if (err)return dev_err_probe (pmc->dev, err,"failed to set core OPP regulator\n" );
include/linux/pm_opp.h +4 -5
@@ -159,9 +159,9 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);int devm_pm_opp_set_supported_hw (struct device *dev,const u32 *versions,unsigned int count);struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name);void dev_pm_opp_put_prop_name (struct opp_table *opp_table); -struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count); +struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[]);void dev_pm_opp_put_regulators (struct opp_table *opp_table); -int devm_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count); +int devm_pm_opp_set_regulators (struct device *dev,const char *const names[]);struct opp_table *dev_pm_opp_set_clkname (struct device *dev,const char *name);void dev_pm_opp_put_clkname (struct opp_table *opp_table);int devm_pm_opp_set_clkname (struct device *dev,const char *name);
@@ -379,7 +379,7 @@ static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, constatic inline void dev_pm_opp_put_prop_name (struct opp_table *opp_table) {} -static inline struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count) +static inline struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[]) {return ERR_PTR (-EOPNOTSUPP ); }
@@ -387,8 +387,7 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, costatic inline void dev_pm_opp_put_regulators (struct opp_table *opp_table) {}static inline int devm_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {return -EOPNOTSUPP ; }
Signature · 1 line
2.31.1.272.g89b43f80a514
Steven Price
maintainerRe: [PATCH V3 02/20] OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
Quoted 17 lines · Viresh Kumar
Make
dev_pm_opp_set_regulators()accept a NULL terminated list of names instead of making the callers keep the two parameters in sync, which creates an opportunity for bugs to get in.Suggested-by Greg Kroah-Hartman <[email protected]>Signed-off-by Viresh Kumar <[email protected]>--- drivers/cpufreq/cpufreq-dt.c | 9 ++++----- drivers/cpufreq/ti-cpufreq.c | 7 +++---- drivers/devfreq/exynos-bus.c | 4 ++-- drivers/gpu/drm/lima/lima_devfreq.c | 3 ++- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 4 ++-- drivers/opp/core.c | 18 ++++++++++++------ drivers/soc/tegra/pmc.c | 4 ++-- include/linux/pm_opp.h | 9 ++++----- 8 files changed, 31 insertions(+), 27 deletions(-)
[...]
Quoted 13 lines
drivers/gpu/drm/panfrost/panfrost_devfreq.c +1
-0@@ -91,6 +91,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)struct devfreq *devfreq;struct thermal_cooling_device *cooling;struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; +const char *supplies[] = { pfdev->comp->supply_names[0 ],NULL };if (pfdev->comp->num_supplies >1 ) {/*
drivers/gpu/drm/panfrost/panfrost_devfreq.c int panfrost_devfreq_init(struct panfrost_device *pfdev) · line 108
Quoted 9 lines
drivers/gpu/drm/panfrost/panfrost_devfreq.c +1
-2@@ -101,8 +102,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)return 0 ; } - ret =devm_pm_opp_set_regulators (dev, pfdev->comp->supply_names, - pfdev->comp->num_supplies); + ret =devm_pm_opp_set_regulators (dev, supplies);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV ) {
I have to say the 'new improved' list ending with NULL approach doesn't work out so well for Panfrost. We already have to have a separate 'num_supplies' variable for devm_regulator_bulk_get() / regulator_bulk_{en,dis}able(), so the keeping everything in sync argument is lost here.
I would suggest added the NULL on the end of the lists in panfrost_drv.c but then it would break the use of ARRAY_SIZE() to automagically keep the length correct...
For now the approach isn't too bad because Panfrost doesn't yet support enabling devfreq with more than one supply. But that array isn't going to work so nicely when that restriction is removed.
The only sane way I can see of handling this in Panfrost would be replicating the loop to count the supplies in the Panfrost code which would allow dropping num_supplies from struct panfrost_compatible and then supply_names in the same struct could be NULL terminated ready for devm_pm_opp_set_regulators().
Steve
Quoted 100 lines
drivers/opp/core.c +12
-6@@ -2105,13 +2105,20 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);* This must be called before any OPPs are initialized for the device. */ struct opp_table *dev_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {struct dev_pm_opp_supply *supplies; +const char *const *temp = names;struct opp_table *opp_table;struct regulator *reg; -int ret, i; +int count =0 , ret, i; + +/* Count number of regulators */ +while (*temp++) + count++; + +if (!count) +return ERR_PTR (-EINVAL ); opp_table =_add_opp_table (dev, false);if (IS_ERR (opp_table))@@ -2236,12 +2243,11 @@ static void devm_pm_opp_regulators_release(void *data)* Return: 0 on success and errorno otherwise. */ int devm_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {struct opp_table *opp_table; - opp_table =dev_pm_opp_set_regulators (dev, names, count); + opp_table =dev_pm_opp_set_regulators (dev, names);if (IS_ERR (opp_table))return PTR_ERR (opp_table);drivers/soc/tegra/pmc.c +2
-2@@ -1384,7 +1384,7 @@ tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,static int tegra_pmc_core_pd_add (struct tegra_pmc *pmc,struct device_node *np) {struct generic_pm_domain *genpd; -const char *rname ="core" ; +const char *rname[] = {"core" ,NULL };int err; genpd =devm_kzalloc (pmc->dev,sizeof (*genpd),GFP_KERNEL );@@ -1395,7 +1395,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; - err =devm_pm_opp_set_regulators (pmc->dev, &rname,1 ); + err =devm_pm_opp_set_regulators (pmc->dev, rname);if (err)return dev_err_probe (pmc->dev, err,"failed to set core OPP regulator\n" );include/linux/pm_opp.h +4
-5@@ -159,9 +159,9 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);int devm_pm_opp_set_supported_hw (struct device *dev,const u32 *versions,unsigned int count);struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name);void dev_pm_opp_put_prop_name (struct opp_table *opp_table); -struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count); +struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[]);void dev_pm_opp_put_regulators (struct opp_table *opp_table); -int devm_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count); +int devm_pm_opp_set_regulators (struct device *dev,const char *const names[]);struct opp_table *dev_pm_opp_set_clkname (struct device *dev,const char *name);void dev_pm_opp_put_clkname (struct opp_table *opp_table);int devm_pm_opp_set_clkname (struct device *dev,const char *name);@@ -379,7 +379,7 @@ static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, constatic inline void dev_pm_opp_put_prop_name (struct opp_table *opp_table) {} -static inline struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count) +static inline struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[]) {return ERR_PTR (-EOPNOTSUPP ); }@@ -387,8 +387,7 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, costatic inline void dev_pm_opp_put_regulators (struct opp_table *opp_table) {}static inline int devm_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {return -EOPNOTSUPP ; }
Viresh Kumar
maintainerRe: [PATCH V3 02/20] OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
Quoted 9 lines · Steven Price
I have to say the 'new improved' list ending with NULL approach doesn't work out so well for Panfrost. We already have to have a separate '
num_supplies' variable fordevm_regulator_bulk_get()/ regulator_bulk_{en,dis}able(), so the keeping everything in sync argument is lost here.I would suggest added the NULL on the end of the lists in
panfrost_drv.cbut then it would break the use ofARRAY_SIZE()to automagically keep the length correct...
Actually we can still make it work.
Quoted 9 lines
For now the approach isn't too bad because Panfrost doesn't yet support enabling devfreq with more than one supply. But that array isn't going to work so nicely when that restriction is removed.
The only sane way I can see of handling this in Panfrost would be replicating the loop to count the supplies in the Panfrost code which would allow dropping
num_suppliesfrom structpanfrost_compatibleand thensupply_namesin the same struct could be NULL terminated ready fordevm_pm_opp_set_regulators().
Or doing this, which will simplify both the cases.
drivers/gpu/drm/panfrost/panfrost_drv.c +10 -5
@@ -625,24 +625,29 @@ static int panfrost_remove(struct platform_device *pdev)return 0 ; } -static const char *const default_supplies[] = {"mali" }; +/* +* The OPP core wants the supply names to be NULL terminated, but we need the +* correct num_supplies value for regulator core. Hence, we NULL terminate here +* and then initialize num_supplies with ARRAY_SIZE - 1. +*/ +static const char *const default_supplies[] = {"mali" ,NULL };static const struct panfrost_compatible default_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .num_pm_domains =1 ,/* optional */ .pm_domain_names =NULL , };static const struct panfrost_compatible amlogic_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .vendor_quirk = panfrost_gpu_amlogic_quirk, }; -static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" }; +static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" ,NULL };static const char *const mediatek_mt8183_pm_domains[] = {"core0" ,"core1" ,"core2" };static const struct panfrost_compatible mediatek_mt8183_data = { - .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies), + .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies) -1 , .supply_names = mediatek_mt8183_supplies, .num_pm_domains =ARRAY_SIZE (mediatek_mt8183_pm_domains), .pm_domain_names = mediatek_mt8183_pm_domains,
Signature · 1 line
viresh
Steven Price
maintainerRe: [PATCH V3 02/20] OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
Quoted 17 lines · Viresh Kumar
Quoted 9 lines · Steven Price
I have to say the 'new improved' list ending with NULL approach doesn't work out so well for Panfrost. We already have to have a separate '
num_supplies' variable fordevm_regulator_bulk_get()/ regulator_bulk_{en,dis}able(), so the keeping everything in sync argument is lost here.I would suggest added the NULL on the end of the lists in
panfrost_drv.cbut then it would break the use ofARRAY_SIZE()to automagically keep the length correct...Actually we can still make it work.
Quoted 4 lines
For now the approach isn't too bad because Panfrost doesn't yet support enabling devfreq with more than one supply. But that array isn't going to work so nicely when that restriction is removed.
Quoted 7 lines
Quoted 5 lines
The only sane way I can see of handling this in Panfrost would be replicating the loop to count the supplies in the Panfrost code which would allow dropping
num_suppliesfrom structpanfrost_compatibleand thensupply_namesin the same struct could be NULL terminated ready fordevm_pm_opp_set_regulators().Or doing this, which will simplify both the cases.
Yes the below works, it's just a bit ugly having the "- 1", and potentially easy to forgot when adding another. However I don't suppose it would get far in that case so I think it would be spotted quickly when adding a new compatible.
It's probably the best solution at the moment.
Thanks,
Steve
Quoted 41 lines
drivers/gpu/drm/panfrost/panfrost_drv.c +10
-5@@ -625,24 +625,29 @@ static int panfrost_remove(struct platform_device *pdev)return 0 ; } -static const char *const default_supplies[] = {"mali" }; +/* +* The OPP core wants the supply names to be NULL terminated, but we need the +* correct num_supplies value for regulator core. Hence, we NULL terminate here +* and then initialize num_supplies with ARRAY_SIZE - 1. +*/ +static const char *const default_supplies[] = {"mali" ,NULL };static const struct panfrost_compatible default_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .num_pm_domains =1 ,/* optional */ .pm_domain_names =NULL , };static const struct panfrost_compatible amlogic_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .vendor_quirk = panfrost_gpu_amlogic_quirk, }; -static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" }; +static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" ,NULL };static const char *const mediatek_mt8183_pm_domains[] = {"core0" ,"core1" ,"core2" };static const struct panfrost_compatible mediatek_mt8183_data = { - .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies), + .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies) -1 , .supply_names = mediatek_mt8183_supplies, .num_pm_domains =ARRAY_SIZE (mediatek_mt8183_pm_domains), .pm_domain_names = mediatek_mt8183_pm_domains,
Viresh Kumar
maintainerPATCH v3 2/20 OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
In reply to Viresh KumarMake dev_pm_opp_set_regulators() accept a NULL terminated list of names instead of making the callers keep the two parameters in sync, which creates an opportunity for bugs to get in.
---
V3->V3.1:
- Update panfrost_drv.c to include the NULL element.
drivers/cpufreq/cpufreq-dt.c | 9 ++++----- drivers/cpufreq/ti-cpufreq.c | 7 +++---- drivers/devfreq/exynos-bus.c | 4 ++-- drivers/gpu/drm/lima/lima_devfreq.c | 3 ++- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 3 +-- drivers/gpu/drm/panfrost/panfrost_drv.c | 15 ++++++++++----- drivers/opp/core.c | 18 ++++++++++++------ drivers/soc/tegra/pmc.c | 4 ++-- include/linux/pm_opp.h | 9 ++++----- 9 files changed, 40 insertions(+), 32 deletions(-)
drivers/cpufreq/cpufreq-dt.c +4 -5
@@ -193,7 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)struct private_data *priv;struct device *cpu_dev;bool fallback = false; -const char *reg_name; +const char *reg_name[] = {NULL ,NULL };int ret;/* Check if this CPU is already covered by some other policy */
@@ -218,10 +218,9 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)* OPP layer will be taking care of regulators now, but it needs to know * the name of the regulator first. */ - reg_name =find_supply_name (cpu_dev); -if (reg_name) { - priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, ®_name, -1 ); + reg_name[0 ] =find_supply_name (cpu_dev); +if (reg_name[0 ]) { + priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, reg_name);if (IS_ERR (priv->opp_table)) { ret =PTR_ERR (priv->opp_table);if (ret != -EPROBE_DEFER )
drivers/cpufreq/ti-cpufreq.c +3 -4
@@ -173,7 +173,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {* seems to always read as 0). */ -static const char *const omap3_reg_names[] = {"cpu0" ,"vbb" }; +static const char *const omap3_reg_names[] = {"cpu0" ,"vbb" ,NULL };static struct ti_cpufreq_soc_data omap36xx_soc_data = { .reg_names = omap3_reg_names,
@@ -326,7 +326,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)const struct of_device_id *match;struct opp_table *ti_opp_table;struct ti_cpufreq_data *opp_data; -const char *const default_reg_names[] = {"vdd" ,"vbb" }; +const char *const default_reg_names[] = {"vdd" ,"vbb" ,NULL };int ret; match =dev_get_platdata (&pdev->dev);
@@ -387,8 +387,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)if (opp_data->soc_data->reg_names) reg_names = opp_data->soc_data->reg_names; ti_opp_table =dev_pm_opp_set_regulators (opp_data->cpu_dev, - reg_names, -ARRAY_SIZE (default_reg_names)); + reg_names);if (IS_ERR (ti_opp_table)) {dev_pm_opp_put_supported_hw (opp_data->opp_table); ret =PTR_ERR (ti_opp_table);
drivers/devfreq/exynos-bus.c +2 -2
@@ -180,10 +180,10 @@ static int exynos_bus_parent_parse_of(struct device_node *np, {struct device *dev = bus->dev;struct opp_table *opp_table; -const char *vdd ="vdd" ; +const char *supplies[] = {"vdd" ,NULL };int i, ret, count, size; - opp_table =dev_pm_opp_set_regulators (dev, &vdd,1 ); + opp_table =dev_pm_opp_set_regulators (dev, supplies);if (IS_ERR (opp_table)) { ret =PTR_ERR (opp_table);dev_err (dev,"failed to set regulators %d\n" , ret);
drivers/gpu/drm/lima/lima_devfreq.c +2 -1
@@ -111,6 +111,7 @@ int lima_devfreq_init(struct lima_device *ldev)struct dev_pm_opp *opp;unsigned long cur_freq;int ret; +const char *regulator_names[] = {"mali" ,NULL };if (!device_property_present (dev,"operating-points-v2" ))/* Optional, continue without devfreq */
@@ -122,7 +123,7 @@ int lima_devfreq_init(struct lima_device *ldev)if (ret)return ret; - ret =devm_pm_opp_set_regulators (dev, (const char *[]){"mali" },1 ); + ret =devm_pm_opp_set_regulators (dev, regulator_names);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV )
drivers/gpu/drm/panfrost/panfrost_devfreq.c +1 -2
@@ -101,8 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)return 0 ; } - ret =devm_pm_opp_set_regulators (dev, pfdev->comp->supply_names, - pfdev->comp->num_supplies); + ret =devm_pm_opp_set_regulators (dev, pfdev->comp->supply_names);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV ) {
drivers/gpu/drm/panfrost/panfrost_drv.c +10 -5
@@ -625,24 +625,29 @@ static int panfrost_remove(struct platform_device *pdev)return 0 ; } -static const char *const default_supplies[] = {"mali" }; +/* +* The OPP core wants the supply names to be NULL terminated, but we need the +* correct num_supplies value for regulator core. Hence, we NULL terminate here +* and then initialize num_supplies with ARRAY_SIZE - 1. +*/ +static const char *const default_supplies[] = {"mali" ,NULL };static const struct panfrost_compatible default_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .num_pm_domains =1 ,/* optional */ .pm_domain_names =NULL , };static const struct panfrost_compatible amlogic_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .vendor_quirk = panfrost_gpu_amlogic_quirk, }; -static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" }; +static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" ,NULL };static const char *const mediatek_mt8183_pm_domains[] = {"core0" ,"core1" ,"core2" };static const struct panfrost_compatible mediatek_mt8183_data = { - .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies), + .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies) -1 , .supply_names = mediatek_mt8183_supplies, .num_pm_domains =ARRAY_SIZE (mediatek_mt8183_pm_domains), .pm_domain_names = mediatek_mt8183_pm_domains,
drivers/opp/core.c +12 -6
@@ -2105,13 +2105,20 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);* This must be called before any OPPs are initialized for the device. */ struct opp_table *dev_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {struct dev_pm_opp_supply *supplies; +const char *const *temp = names;struct opp_table *opp_table;struct regulator *reg; -int ret, i; +int count =0 , ret, i; + +/* Count number of regulators */ +while (*temp++) + count++; + +if (!count) +return ERR_PTR (-EINVAL ); opp_table =_add_opp_table (dev, false);if (IS_ERR (opp_table))
@@ -2236,12 +2243,11 @@ static void devm_pm_opp_regulators_release(void *data)* Return: 0 on success and errorno otherwise. */ int devm_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {struct opp_table *opp_table; - opp_table =dev_pm_opp_set_regulators (dev, names, count); + opp_table =dev_pm_opp_set_regulators (dev, names);if (IS_ERR (opp_table))return PTR_ERR (opp_table);
drivers/soc/tegra/pmc.c +2 -2
@@ -1384,7 +1384,7 @@ tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,static int tegra_pmc_core_pd_add (struct tegra_pmc *pmc,struct device_node *np) {struct generic_pm_domain *genpd; -const char *rname ="core" ; +const char *rname[] = {"core" ,NULL };int err; genpd =devm_kzalloc (pmc->dev,sizeof (*genpd),GFP_KERNEL );
@@ -1395,7 +1395,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; - err =devm_pm_opp_set_regulators (pmc->dev, &rname,1 ); + err =devm_pm_opp_set_regulators (pmc->dev, rname);if (err)return dev_err_probe (pmc->dev, err,"failed to set core OPP regulator\n" );
include/linux/pm_opp.h +4 -5
@@ -159,9 +159,9 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);int devm_pm_opp_set_supported_hw (struct device *dev,const u32 *versions,unsigned int count);struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name);void dev_pm_opp_put_prop_name (struct opp_table *opp_table); -struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count); +struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[]);void dev_pm_opp_put_regulators (struct opp_table *opp_table); -int devm_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count); +int devm_pm_opp_set_regulators (struct device *dev,const char *const names[]);struct opp_table *dev_pm_opp_set_clkname (struct device *dev,const char *name);void dev_pm_opp_put_clkname (struct opp_table *opp_table);int devm_pm_opp_set_clkname (struct device *dev,const char *name);
@@ -379,7 +379,7 @@ static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, constatic inline void dev_pm_opp_put_prop_name (struct opp_table *opp_table) {} -static inline struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[],unsigned int count) +static inline struct opp_table *dev_pm_opp_set_regulators (struct device *dev,const char *const names[]) {return ERR_PTR (-EOPNOTSUPP ); }
@@ -387,8 +387,7 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, costatic inline void dev_pm_opp_put_regulators (struct opp_table *opp_table) {}static inline int devm_pm_opp_set_regulators (struct device *dev, -const char *const names[], -unsigned int count) +const char *const names[]) {return -EOPNOTSUPP ; }
Signature · 1 line
2.31.1.272.g89b43f80a514
Re: [PATCH V3.1 02/20] OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
Quoted 21 lines · Viresh Kumar
Make
dev_pm_opp_set_regulators()accept a NULL terminated list of names instead of making the callers keep the two parameters in sync, which creates an opportunity for bugs to get in.Suggested-by Greg Kroah-Hartman <[email protected]>Signed-off-by Viresh Kumar <[email protected]>---
V3->V3.1:
- Updatepanfrost_drv.cto include the NULL element.drivers/cpufreq/cpufreq-dt.c | 9 ++++----- drivers/cpufreq/ti-cpufreq.c | 7 +++---- drivers/devfreq/exynos-bus.c | 4 ++-- drivers/gpu/drm/lima/lima_devfreq.c | 3 ++- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 3 +-- drivers/gpu/drm/panfrost/panfrost_drv.c | 15 ++++++++++----- drivers/opp/core.c | 18 ++++++++++++------ drivers/soc/tegra/pmc.c | 4 ++-- include/linux/pm_opp.h | 9 ++++----- 9 files changed, 40 insertions(+), 32 deletions(-)
[...]
Quoted 43 lines
drivers/gpu/drm/panfrost/panfrost_devfreq.c +1
-2@@ -101,8 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)return 0 ; } - ret =devm_pm_opp_set_regulators (dev, pfdev->comp->supply_names, - pfdev->comp->num_supplies); + ret =devm_pm_opp_set_regulators (dev, pfdev->comp->supply_names);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV ) {drivers/gpu/drm/panfrost/panfrost_drv.c +8
-3@@ -625,24 +625,29 @@ static int panfrost_remove(struct platform_device *pdev)return 0 ; } -static const char *const default_supplies[] = {"mali" }; +/* +* The OPP core wants the supply names to be NULL terminated, but we need the +* correct num_supplies value for regulator core. Hence, we NULL terminate here +* and then initialize num_supplies with ARRAY_SIZE - 1. +*/ +static const char *const default_supplies[] = {"mali" ,NULL };static const struct panfrost_compatible default_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .num_pm_domains =1 ,/* optional */ .pm_domain_names =NULL , };static const struct panfrost_compatible amlogic_data = { - .num_supplies =ARRAY_SIZE (default_supplies), + .num_supplies =ARRAY_SIZE (default_supplies) -1 , .supply_names = default_supplies, .vendor_quirk = panfrost_gpu_amlogic_quirk, };
drivers/gpu/drm/panfrost/panfrost_drv.c static int panfrost_remove(struct platform_device *pdev) · line 653
Quoted 10 lines
drivers/gpu/drm/panfrost/panfrost_drv.c +2
-2-static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" }; +static const char *const mediatek_mt8183_supplies[] = {"mali" ,"sram" ,NULL };static const char *const mediatek_mt8183_pm_domains[] = {"core0" ,"core1" ,"core2" };static const struct panfrost_compatible mediatek_mt8183_data = { - .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies), + .num_supplies =ARRAY_SIZE (mediatek_mt8183_supplies) -1 , .supply_names = mediatek_mt8183_supplies, .num_pm_domains =ARRAY_SIZE (mediatek_mt8183_pm_domains), .pm_domain_names = mediatek_mt8183_pm_domains,
Thanks for the rework, much cleaner.
Steve
Re: [PATCH V3 02/20] OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
In reply to Viresh KumarQuoted 83 lines · Viresh Kumar
Make
dev_pm_opp_set_regulators()accept a NULL terminated list of names instead of making the callers keep the two parameters in sync, which creates an opportunity for bugs to get in.Suggested-by Greg Kroah-Hartman <[email protected]>Signed-off-by Viresh Kumar <[email protected]>--- drivers/cpufreq/cpufreq-dt.c | 9 ++++----- drivers/cpufreq/ti-cpufreq.c | 7 +++---- drivers/devfreq/exynos-bus.c | 4 ++-- drivers/gpu/drm/lima/lima_devfreq.c | 3 ++- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 4 ++-- drivers/opp/core.c | 18 ++++++++++++------ drivers/soc/tegra/pmc.c | 4 ++-- include/linux/pm_opp.h | 9 ++++----- 8 files changed, 31 insertions(+), 27 deletions(-)drivers/cpufreq/cpufreq-dt.c +4
-5@@ -193,7 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)struct private_data *priv;struct device *cpu_dev;bool fallback = false; -const char *reg_name; +const char *reg_name[] = {NULL ,NULL };int ret;/* Check if this CPU is already covered by some other policy */ @@ -218,10 +218,9 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)* OPP layer will be taking care of regulators now, but it needs to know * the name of the regulator first. */ - reg_name =find_supply_name (cpu_dev); -if (reg_name) { - priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, ®_name, -1 ); + reg_name[0 ] =find_supply_name (cpu_dev); +if (reg_name[0 ]) { + priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, reg_name);if (IS_ERR (priv->opp_table)) { ret =PTR_ERR (priv->opp_table);if (ret != -EPROBE_DEFER )drivers/cpufreq/ti-cpufreq.c +3
-4@@ -173,7 +173,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {* seems to always read as 0). */ -static const char *const omap3_reg_names[] = {"cpu0" ,"vbb" }; +static const char *const omap3_reg_names[] = {"cpu0" ,"vbb" ,NULL };static struct ti_cpufreq_soc_data omap36xx_soc_data = { .reg_names = omap3_reg_names,@@ -326,7 +326,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)const struct of_device_id *match;struct opp_table *ti_opp_table;struct ti_cpufreq_data *opp_data; -const char *const default_reg_names[] = {"vdd" ,"vbb" }; +const char *const default_reg_names[] = {"vdd" ,"vbb" ,NULL };int ret; match =dev_get_platdata (&pdev->dev);@@ -387,8 +387,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)if (opp_data->soc_data->reg_names) reg_names = opp_data->soc_data->reg_names; ti_opp_table =dev_pm_opp_set_regulators (opp_data->cpu_dev, - reg_names, -ARRAY_SIZE (default_reg_names)); + reg_names);if (IS_ERR (ti_opp_table)) {dev_pm_opp_put_supported_hw (opp_data->opp_table); ret =PTR_ERR (ti_opp_table);drivers/devfreq/exynos-bus.c +0
-0@@ -180,10 +180,10 @@ static int exynos_bus_parent_parse_of(struct device_node *np, {struct device *dev = bus->dev;
drivers/devfreq/exynos-bus.c static int exynos_bus_parent_parse_of(struct device_node *np, · line 189
Quoted 10 lines
drivers/devfreq/exynos-bus.c +2
-2struct opp_table *opp_table; -const char *vdd ="vdd" ; +const char *supplies[] = {"vdd" ,NULL };int i, ret, count, size; - opp_table =dev_pm_opp_set_regulators (dev, &vdd,1 ); + opp_table =dev_pm_opp_set_regulators (dev, supplies);if (IS_ERR (opp_table)) { ret =PTR_ERR (opp_table);dev_err (dev,"failed to set regulators %d\n" , ret);
(snip)
Signature · 3 lines
Best Regards, Samsung Electronics Chanwoo Choi
Viresh Kumar
maintainerPATCH v3 3/20 OPP: Add dev_pm_opp_set_config() and friends
In reply to Viresh KumarThe OPP core already have few configuration specific APIs and it is getting complex or messy for both the OPP core and its users.
Lets introduce a new set of API which will be used for all kind of different configurations, and shall eventually be used by all the existing ones.
The new API, returns a unique token instead of a pointer to the OPP table, which allows the OPP core to drop the resources selectively later on.
--- drivers/opp/core.c | 229 ++++++++++++++++++++++++++++++++++++++++- drivers/opp/opp.h | 21 ++++ include/linux/pm_opp.h | 42 ++++++++ 3 files changed, 291 insertions(+), 1 deletion(-)
drivers/opp/core.c +228 -1
@@ -13,11 +13,12 @@#include <linux/clk.h> #include <linux/errno.h> #include <linux/err.h> -#include <linux/slab.h> #include <linux/device.h> #include <linux/export.h> #include <linux/pm_domain.h> #include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/xarray.h> #include "opp.h"
@@ -36,6 +37,9 @@ DEFINE_MUTEX(opp_table_lock);/* Flag indicating that opp_tables list is being updated at the moment */ static bool opp_tables_busy; +/* OPP ID allocator */ +static DEFINE_XARRAY_ALLOC1 (opp_configs); +static bool _find_opp_dev (const struct device *dev,struct opp_table *opp_table) {struct opp_device *opp_dev;
@@ -2624,6 +2628,229 @@ int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names, }EXPORT_SYMBOL_GPL (devm_pm_opp_attach_genpd); +static void _opp_clear_config (struct opp_config_data *data) +{ +if (data->flags &OPP_CONFIG_GENPD ) +dev_pm_opp_detach_genpd (data->opp_table); +if (data->flags &OPP_CONFIG_REGULATOR ) +dev_pm_opp_put_regulators (data->opp_table); +if (data->flags &OPP_CONFIG_SUPPORTED_HW ) +dev_pm_opp_put_supported_hw (data->opp_table); +if (data->flags &OPP_CONFIG_REGULATOR_HELPER ) +dev_pm_opp_unregister_set_opp_helper (data->opp_table); +if (data->flags &OPP_CONFIG_PROP_NAME ) +dev_pm_opp_put_prop_name (data->opp_table); +if (data->flags &OPP_CONFIG_CLK ) +dev_pm_opp_put_clkname (data->opp_table); + +dev_pm_opp_put_opp_table (data->opp_table); +kfree (data); +} + +/** +* dev_pm_opp_set_config() - Set OPP configuration for the device. +* @dev: Device for which configuration is being set. +* @config: OPP configuration. +* +* This allows all device OPP configurations to be performed at once. +* +* This must be called before any OPPs are initialized for the device. This may +* be called multiple times for the same OPP table, for example once for each +* CPU that share the same table. This must be balanced by the same number of +* calls to dev_pm_opp_clear_config() in order to free the OPP table properly. +* +* This returns a token to the caller, which must be passed to +* dev_pm_opp_clear_config() to free the resources later. The value of the +* returned token will be >= 1 for success and negative for errors. The minimum +* value of 1 is chosen here to make it easy for callers to manage the resource. +*/ +int dev_pm_opp_set_config (struct device *dev,struct dev_pm_opp_config *config) +{ +struct opp_table *opp_table, *err; +struct opp_config_data *data; +unsigned int id; +int ret; + + data =kmalloc (sizeof (*data),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + opp_table =_add_opp_table (dev, false); +if (IS_ERR (opp_table)) { +kfree (data); +return PTR_ERR (opp_table); + } + + data->opp_table = opp_table; + data->flags =0 ; + +/* This should be called before OPPs are initialized */ +if (WARN_ON (!list_empty (&opp_table->opp_list))) { + ret = -EBUSY ; + goto err; + } + +/* Configure clocks */ +if (config->clk_names) { +const char *const *temp = config->clk_names; +int count =0 ; + +/* Count number of clks */ +while (*temp++) + count++; + +/* +* This is a special case where we have a single clock, whose +* connection id name is NULL, i.e. first two entries are NULL +* in the array. +*/ +if (!count && !config->clk_names[1 ]) + count =1 ; + +/* We support only one clock name for now */ +if (count !=1 ) { + ret = -EINVAL ; + goto err; + } + + err =dev_pm_opp_set_clkname (dev, config->clk_names[0 ]); +if (IS_ERR (err)) { + ret =PTR_ERR (err); + goto err; + } + + data->flags |=OPP_CONFIG_CLK ; + } + +/* Configure property names */ +if (config->prop_name) { + err =dev_pm_opp_set_prop_name (dev, config->prop_name); +if (IS_ERR (err)) { + ret =PTR_ERR (err); + goto err; + } + + data->flags |=OPP_CONFIG_PROP_NAME ; + } + +/* Configure opp helper */ +if (config->set_opp) { + err =dev_pm_opp_register_set_opp_helper (dev, config->set_opp); +if (IS_ERR (err)) { + ret =PTR_ERR (err); + goto err; + } + + data->flags |=OPP_CONFIG_REGULATOR_HELPER ; + } + +/* Configure supported hardware */ +if (config->supported_hw) { + err =dev_pm_opp_set_supported_hw (dev, config->supported_hw, + config->supported_hw_count); +if (IS_ERR (err)) { + ret =PTR_ERR (err); + goto err; + } + + data->flags |=OPP_CONFIG_SUPPORTED_HW ; + } + +/* Configure supplies */ +if (config->regulator_names) { + err =dev_pm_opp_set_regulators (dev, config->regulator_names); +if (IS_ERR (err)) { + ret =PTR_ERR (err); + goto err; + } + + data->flags |=OPP_CONFIG_REGULATOR ; + } + +/* Attach genpds */ +if (config->genpd_names) { + err =dev_pm_opp_attach_genpd (dev, config->genpd_names, + config->virt_devs); +if (IS_ERR (err)) { + ret =PTR_ERR (err); + goto err; + } + + data->flags |=OPP_CONFIG_GENPD ; + } + + ret =xa_alloc (&opp_configs, &id, data,XA_LIMIT (1 ,INT_MAX ), +GFP_KERNEL ); +if (ret) + goto err; + +return id; + +err: +_opp_clear_config (data); +return ret; +} +EXPORT_SYMBOL_GPL (dev_pm_opp_set_config); + +/** +* dev_pm_opp_clear_config() - Releases resources blocked for OPP configuration. +* @opp_table: OPP table returned from dev_pm_opp_set_config(). +* +* This allows all device OPP configurations to be cleared at once. This must be +* called once for each call made to dev_pm_opp_set_config(), in order to free +* the OPPs properly. +* +* Currently the first call itself ends up freeing all the OPP configurations, +* while the later ones only drop the OPP table reference. This works well for +* now as we would never want to use an half initialized OPP table and want to +* remove the configurations together. +*/ +void dev_pm_opp_clear_config (int token) +{ +struct opp_config_data *data; + +/* +* This lets the callers call this unconditionally and keep their code +* simple. +*/ +if (unlikely (token <=0 )) +return ; + + data =xa_erase (&opp_configs, token); +if (WARN_ON (!data)) +return ; + +_opp_clear_config (data); +} +EXPORT_SYMBOL_GPL (dev_pm_opp_clear_config); + +static void devm_pm_opp_config_release (void *token) +{ +dev_pm_opp_clear_config ((unsigned long )token); +} + +/** +* devm_pm_opp_set_config() - Set OPP configuration for the device. +* @dev: Device for which configuration is being set. +* @config: OPP configuration. +* +* This allows all device OPP configurations to be performed at once. +* This is a resource-managed variant of dev_pm_opp_set_config(). +* +* Return: 0 on success and errorno otherwise. +*/ +int devm_pm_opp_set_config (struct device *dev,struct dev_pm_opp_config *config) +{ +int token =dev_pm_opp_set_config (dev, config); + +if (token <0 ) +return token; + +return devm_add_action_or_reset (dev, devm_pm_opp_config_release, + (void *) ((unsigned long ) token)); +} +EXPORT_SYMBOL_GPL (devm_pm_opp_set_config); +/** * dev_pm_opp_xlate_required_opp() - Find required OPP for @src_table OPP. * @src_table: OPP table which has @dst_table as one of its required OPP table.
drivers/opp/opp.h +21 -0
@@ -28,6 +28,27 @@ extern struct mutex opp_table_lock;extern struct list_head opp_tables, lazy_opp_tables; +/* OPP Config flags */ +#define OPP_CONFIG_CLK BIT(0) +#define OPP_CONFIG_REGULATOR BIT(1) +#define OPP_CONFIG_REGULATOR_HELPER BIT(2) +#define OPP_CONFIG_PROP_NAME BIT(3) +#define OPP_CONFIG_SUPPORTED_HW BIT(4) +#define OPP_CONFIG_GENPD BIT(5) + +/** +* struct opp_config_data - data for set config operations +* @opp_table: OPP table +* @flags: OPP config flags +* +* This structure stores the OPP config information for each OPP table +* configuration by the callers. +*/ +struct opp_config_data { +struct opp_table *opp_table; +unsigned int flags; +}; +/* * Internal data structure organization with the OPP layer library is as * follows:
include/linux/pm_opp.h +42 -0
60 lines not on this page · raw message
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 4/20 cpufreq: qcom-nvmem: Migrate to dev_pm_opp_set_config()
In reply to Viresh KumarThe OPP core now provides a unified API for setting all configuration types, i.e. dev_pm_opp_set_config().
Lets start using it.
--- drivers/cpufreq/qcom-cpufreq-nvmem.c | 109 +++++++-------------------- 1 file changed, 28 insertions(+), 81 deletions(-)
drivers/cpufreq/qcom-cpufreq-nvmem.c +28 -81
@@ -55,9 +55,7 @@ struct qcom_cpufreq_match_data { };struct qcom_cpufreq_drv { -struct opp_table **names_opp_tables; -struct opp_table **hw_opp_tables; -struct opp_table **genpd_opp_tables; +int *opp_tokens;u32 versions;const struct qcom_cpufreq_match_data *data; };
@@ -315,72 +313,43 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) }of_node_put (np); - drv->names_opp_tables =kcalloc (num_possible_cpus (), -sizeof (*drv->names_opp_tables), + drv->opp_tokens =kcalloc (num_possible_cpus (),sizeof (*drv->opp_tokens),GFP_KERNEL ); -if (!drv->names_opp_tables) { +if (!drv->opp_tokens) { ret = -ENOMEM ; goto free_drv; } - drv->hw_opp_tables =kcalloc (num_possible_cpus (), -sizeof (*drv->hw_opp_tables), -GFP_KERNEL ); -if (!drv->hw_opp_tables) { - ret = -ENOMEM ; - goto free_opp_names; - } - - drv->genpd_opp_tables =kcalloc (num_possible_cpus (), -sizeof (*drv->genpd_opp_tables), -GFP_KERNEL ); -if (!drv->genpd_opp_tables) { - ret = -ENOMEM ; - goto free_opp; - }for_each_possible_cpu (cpu) { +struct dev_pm_opp_config config = { + .supported_hw =NULL , + }; + cpu_dev =get_cpu_device (cpu);if (NULL == cpu_dev) { ret = -ENODEV ; - goto free_genpd_opp; + goto free_opp; }if (drv->data->get_version) { + config.supported_hw = &drv->versions; + config.supported_hw_count =1 ; -if (pvs_name) { - drv->names_opp_tables[cpu] =dev_pm_opp_set_prop_name ( - cpu_dev, - pvs_name); -if (IS_ERR (drv->names_opp_tables[cpu])) { - ret =PTR_ERR (drv->names_opp_tables[cpu]); -dev_err (cpu_dev,"Failed to add OPP name %s\n" , - pvs_name); - goto free_opp; - } - } - - drv->hw_opp_tables[cpu] =dev_pm_opp_set_supported_hw ( - cpu_dev, &drv->versions,1 ); -if (IS_ERR (drv->hw_opp_tables[cpu])) { - ret =PTR_ERR (drv->hw_opp_tables[cpu]); -dev_err (cpu_dev, -"Failed to set supported hardware\n" ); - goto free_genpd_opp; - } +if (pvs_name) + config.prop_name = pvs_name; }if (drv->data->genpd_names) { - drv->genpd_opp_tables[cpu] = -dev_pm_opp_attach_genpd (cpu_dev, - drv->data->genpd_names, -NULL ); -if (IS_ERR (drv->genpd_opp_tables[cpu])) { - ret =PTR_ERR (drv->genpd_opp_tables[cpu]); -if (ret != -EPROBE_DEFER ) -dev_err (cpu_dev, -"Could not attach to pm_domain: %d\n" , - ret); - goto free_genpd_opp; + config.genpd_names = drv->data->genpd_names; + config.virt_devs =NULL ; + } + +if (config.supported_hw || config.genpd_names) { + drv->opp_tokens[cpu] =dev_pm_opp_set_config (cpu_dev, &config); +if (drv->opp_tokens[cpu] <0 ) { + ret = drv->opp_tokens[cpu]; +dev_err (cpu_dev,"Failed to set OPP config\n" ); + goto free_opp; } } }
@@ -395,27 +364,10 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) ret =PTR_ERR (cpufreq_dt_pdev);dev_err (cpu_dev,"Failed to register platform device\n" ); -free_genpd_opp: -for_each_possible_cpu (cpu) { -if (IS_ERR (drv->genpd_opp_tables[cpu])) -break ; -dev_pm_opp_detach_genpd (drv->genpd_opp_tables[cpu]); - } -kfree (drv->genpd_opp_tables); free_opp: -for_each_possible_cpu (cpu) { -if (IS_ERR (drv->names_opp_tables[cpu])) -break ; -dev_pm_opp_put_prop_name (drv->names_opp_tables[cpu]); - } -for_each_possible_cpu (cpu) { -if (IS_ERR (drv->hw_opp_tables[cpu])) -break ; -dev_pm_opp_put_supported_hw (drv->hw_opp_tables[cpu]); - } -kfree (drv->hw_opp_tables); -free_opp_names: -kfree (drv->names_opp_tables); +for_each_possible_cpu (cpu) +dev_pm_opp_clear_config (drv->opp_tokens[cpu]); +kfree (drv->opp_tokens); free_drv:kfree (drv);
@@ -429,15 +381,10 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)platform_device_unregister (cpufreq_dt_pdev); -for_each_possible_cpu (cpu) { -dev_pm_opp_put_supported_hw (drv->names_opp_tables[cpu]); -dev_pm_opp_put_supported_hw (drv->hw_opp_tables[cpu]); -dev_pm_opp_detach_genpd (drv->genpd_opp_tables[cpu]); - } +for_each_possible_cpu (cpu) +dev_pm_opp_clear_config (drv->opp_tokens[cpu]); -kfree (drv->names_opp_tables); -kfree (drv->hw_opp_tables); -kfree (drv->genpd_opp_tables); +kfree (drv->opp_tokens);kfree (drv);return 0 ;
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 5/20 cpufreq: sti: Migrate to dev_pm_opp_set_config()
In reply to Viresh KumarThe OPP core now provides a unified API for setting all configuration types, i.e. dev_pm_opp_set_config().
Lets start using it.
--- drivers/cpufreq/sti-cpufreq.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-)
drivers/cpufreq/sti-cpufreq.c +10 -17
@@ -156,9 +156,13 @@ static int sti_cpufreq_set_opp_info(void)unsigned int hw_info_offset;unsigned int version[VERSION_ELEMENTS ];int pcode, substrate, major, minor; -int ret; +int opp_token, ret;char name[MAX_PCODE_NAME_LEN ]; -struct opp_table *opp_table; +struct dev_pm_opp_config config = { + .supported_hw = version, + .supported_hw_count =ARRAY_SIZE (version), + .prop_name = name, + }; reg_fields =sti_cpufreq_match ();if (!reg_fields) {
@@ -210,21 +214,14 @@ static int sti_cpufreq_set_opp_info(void)snprintf (name,MAX_PCODE_NAME_LEN ,"pcode%d" , pcode); - opp_table =dev_pm_opp_set_prop_name (dev, name); -if (IS_ERR (opp_table)) { -dev_err (dev,"Failed to set prop name\n" ); -return PTR_ERR (opp_table); - } - version[0 ] =BIT (major); version[1 ] =BIT (minor); version[2 ] =BIT (substrate); - opp_table =dev_pm_opp_set_supported_hw (dev, version,VERSION_ELEMENTS ); -if (IS_ERR (opp_table)) { -dev_err (dev,"Failed to set supported hardware\n" ); - ret =PTR_ERR (opp_table); - goto err_put_prop_name; + opp_token =dev_pm_opp_set_config (dev, &config); +if (opp_token <0 ) { +dev_err (dev,"Failed to set OPP config\n" ); +return opp_token; } dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
@@ -233,10 +230,6 @@ static int sti_cpufreq_set_opp_info(void) version[0], version[1], version[2]);return 0 ; - -err_put_prop_name: -dev_pm_opp_put_prop_name (opp_table); -return ret; }static int sti_cpufreq_fetch_syscon_registers (void )
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 6/20 cpufreq: ti: Migrate to dev_pm_opp_set_config()
In reply to Viresh KumarThe OPP core now provides a unified API for setting all configuration types, i.e. dev_pm_opp_set_config().
Lets start using it.
--- drivers/cpufreq/ti-cpufreq.c | 37 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 23 deletions(-)
drivers/cpufreq/ti-cpufreq.c +14 -23
@@ -60,7 +60,6 @@ struct ti_cpufreq_data {struct device_node *opp_node;struct regmap *syscon;const struct ti_cpufreq_soc_data *soc_data; -struct opp_table *opp_table; }; static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
@@ -324,10 +323,13 @@ static int ti_cpufreq_probe(struct platform_device *pdev) {u32 version[VERSION_COUNT ];const struct of_device_id *match; -struct opp_table *ti_opp_table;struct ti_cpufreq_data *opp_data;const char *const default_reg_names[] = {"vdd" ,"vbb" ,NULL };int ret; +struct dev_pm_opp_config config = { + .supported_hw = version, + .supported_hw_count =ARRAY_SIZE (version), + }; match =dev_get_platdata (&pdev->dev);if (!match)
@@ -370,32 +372,21 @@ static int ti_cpufreq_probe(struct platform_device *pdev)if (ret) goto fail_put_node; - ti_opp_table =dev_pm_opp_set_supported_hw (opp_data->cpu_dev, - version,VERSION_COUNT ); -if (IS_ERR (ti_opp_table)) { -dev_err (opp_data->cpu_dev, -"Failed to set supported hardware\n" ); - ret =PTR_ERR (ti_opp_table); - goto fail_put_node; - } - - opp_data->opp_table = ti_opp_table; -if (opp_data->soc_data->multi_regulator) { -const char *const *reg_names = default_reg_names; -if (opp_data->soc_data->reg_names) - reg_names = opp_data->soc_data->reg_names; - ti_opp_table =dev_pm_opp_set_regulators (opp_data->cpu_dev, - reg_names); -if (IS_ERR (ti_opp_table)) { -dev_pm_opp_put_supported_hw (opp_data->opp_table); - ret =PTR_ERR (ti_opp_table); - goto fail_put_node; - } + config.regulator_names = opp_data->soc_data->reg_names; +else + config.regulator_names = default_reg_names; + } + + ret =dev_pm_opp_set_config (opp_data->cpu_dev, &config); +if (ret <0 ) { +dev_err (opp_data->cpu_dev,"Failed to set OPP config\n" ); + goto fail_put_node; }of_node_put (opp_data->opp_node); + register_cpufreq_dt:platform_device_register_simple ("cpufreq-dt" ,-1 ,NULL ,0 );
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 7/20 drm/lima: Migrate to dev_pm_opp_set_config()
In reply to Viresh KumarThe OPP core now provides a unified API for setting all configuration types, i.e. dev_pm_opp_set_config().
Lets start using it.
--- drivers/gpu/drm/lima/lima_devfreq.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/gpu/drm/lima/lima_devfreq.c +6 -5
@@ -112,6 +112,11 @@ int lima_devfreq_init(struct lima_device *ldev)unsigned long cur_freq;int ret;const char *regulator_names[] = {"mali" ,NULL }; +const char *clk_names[] = {"core" ,NULL }; +struct dev_pm_opp_config config = { + .regulator_names = regulator_names, + .clk_names = clk_names, + };if (!device_property_present (dev,"operating-points-v2" ))/* Optional, continue without devfreq */
@@ -119,11 +124,7 @@ int lima_devfreq_init(struct lima_device *ldev)spin_lock_init (&ldevfreq->lock); - ret =devm_pm_opp_set_clkname (dev,"core" ); -if (ret) -return ret; - - ret =devm_pm_opp_set_regulators (dev, regulator_names); + ret =devm_pm_opp_set_config (dev, &config);if (ret) {/* Continue if the optional regulator is missing */ if (ret != -ENODEV )
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 8/20 soc/tegra: Add comment over devm_pm_opp_set_clkname()
In reply to Viresh KumarExplain why special handling was required here, it isn't obvious at all.
--- drivers/soc/tegra/common.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/soc/tegra/common.c +7 -0
@@ -108,6 +108,13 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev,u32 hw_version;int err; +/* +* For some devices we don't have any OPP table in the DT, and in order +* to use the same code path for all the devices, we create a dummy OPP +* table for them via this call. The dummy OPP table is only capable of +* doing clk_set_rate() on invocation of dev_pm_opp_set_rate() and +* doesn't provide any other functionality. +*/ err =devm_pm_opp_set_clkname (dev,NULL );if (err) {dev_err (dev,"failed to set OPP clk: %d\n" , err);
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 9/20 soc/tegra: Migrate to dev_pm_opp_set_config()
In reply to Viresh KumarThe OPP core now provides a unified API for setting all configuration types, i.e. dev_pm_opp_set_config().
Lets start using it.
--- drivers/soc/tegra/common.c | 52 +++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-)
drivers/soc/tegra/common.c +31 -21
@@ -107,36 +107,46 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev, {u32 hw_version;int err; -/* -* For some devices we don't have any OPP table in the DT, and in order -* to use the same code path for all the devices, we create a dummy OPP -* table for them via this call. The dummy OPP table is only capable of -* doing clk_set_rate() on invocation of dev_pm_opp_set_rate() and -* doesn't provide any other functionality. +* The clk's connection id to set is NULL and this is a NULL terminated +* array, hence two NULL entries. */ - err =devm_pm_opp_set_clkname (dev,NULL ); -if (err) { -dev_err (dev,"failed to set OPP clk: %d\n" , err); -return err; - } - -/* Tegra114+ doesn't support OPP yet */ -if (!of_machine_is_compatible ("nvidia,tegra20" ) && - !of_machine_is_compatible ("nvidia,tegra30" )) -return -ENODEV ; - -if (of_machine_is_compatible ("nvidia,tegra20" )) +const char *clk_names[] = {NULL ,NULL }; +struct dev_pm_opp_config config = { +/* +* For some devices we don't have any OPP table in the DT, and +* in order to use the same code path for all the devices, we +* create a dummy OPP table for them via this. The dummy OPP +* table is only capable of doing clk_set_rate() on invocation +* of dev_pm_opp_set_rate() and doesn't provide any other +* functionality. +*/ + .clk_names = clk_names, + }; + +if (of_machine_is_compatible ("nvidia,tegra20" )) { hw_version =BIT (tegra_sku_info.soc_process_id); -else + config.supported_hw = &hw_version; + config.supported_hw_count =1 ; + }else if (of_machine_is_compatible ("nvidia,tegra30" )) { hw_version =BIT (tegra_sku_info.soc_speedo_id); + config.supported_hw = &hw_version; + config.supported_hw_count =1 ; + } - err =devm_pm_opp_set_supported_hw (dev, &hw_version,1 ); + err =devm_pm_opp_set_config (dev, &config);if (err) { -dev_err (dev,"failed to set OPP supported HW: %d\n" , err); +dev_err (dev,"failed to set OPP config: %d\n" , err);return err; } +/* +* Tegra114+ doesn't support OPP yet, return early for non tegra20/30 +* case. +*/ +if (!config.supported_hw) +return -ENODEV ; +/* * Older device-trees have an empty OPP table, we will get * -ENODEV from devm_pm_opp_of_add_table() in this case.
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 10/20 OPP: Migrate set-regulators API to use set-config helpers
In reply to Viresh KumarNow that we have a central API to handle all OPP table configurations, migrate the set-regulators family of helpers to use the new infrastructure.
The return type and parameter to the APIs change a bit due to this, update the current users as well in the same commit in order to avoid breaking builds.
--- drivers/cpufreq/cpufreq-dt.c | 12 ++--- drivers/devfreq/exynos-bus.c | 19 +++----- drivers/opp/core.c | 91 ++++++++---------------------------- include/linux/pm_opp.h | 44 ++++++++++------- 4 files changed, 60 insertions(+), 106 deletions(-)
drivers/cpufreq/cpufreq-dt.c +6 -6
@@ -29,9 +29,9 @@ struct private_data {cpumask_var_t cpus;struct device *cpu_dev; -struct opp_table *opp_table;struct cpufreq_frequency_table *freq_table;bool have_static_opps; +int opp_token; };static LIST_HEAD (priv_list);
@@ -220,9 +220,9 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)*/ reg_name[0 ] =find_supply_name (cpu_dev);if (reg_name[0 ]) { - priv->opp_table =dev_pm_opp_set_regulators (cpu_dev, reg_name); -if (IS_ERR (priv->opp_table)) { - ret =PTR_ERR (priv->opp_table); + priv->opp_token =dev_pm_opp_set_regulators (cpu_dev, reg_name); +if (priv->opp_token <0 ) { + ret = priv->opp_token;if (ret != -EPROBE_DEFER )dev_err (cpu_dev,"failed to set regulators: %d\n" , ret);
@@ -294,7 +294,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu) out:if (priv->have_static_opps)dev_pm_opp_of_cpumask_remove_table (priv->cpus); -dev_pm_opp_put_regulators (priv->opp_table); +dev_pm_opp_put_regulators (priv->opp_token); free_cpumask:free_cpumask_var (priv->cpus);return ret;
@@ -308,7 +308,7 @@ static void dt_cpufreq_release(void)dev_pm_opp_free_cpufreq_table (priv->cpu_dev, &priv->freq_table);if (priv->have_static_opps)dev_pm_opp_of_cpumask_remove_table (priv->cpus); -dev_pm_opp_put_regulators (priv->opp_table); +dev_pm_opp_put_regulators (priv->opp_token);free_cpumask_var (priv->cpus);list_del (&priv->node); }
drivers/devfreq/exynos-bus.c +7 -12
@@ -33,7 +33,7 @@ struct exynos_bus {unsigned long curr_freq; -struct opp_table *opp_table; +int opp_token;struct clk *clk;unsigned int ratio; };
@@ -161,8 +161,7 @@ static void exynos_bus_exit(struct device *dev)dev_pm_opp_of_remove_table (dev);clk_disable_unprepare (bus->clk); -dev_pm_opp_put_regulators (bus->opp_table); - bus->opp_table =NULL ; +dev_pm_opp_put_regulators (bus->opp_token); }static void exynos_bus_passive_exit (struct device *dev)
@@ -179,18 +178,16 @@ static int exynos_bus_parent_parse_of(struct device_node *np, struct exynos_bus *bus) {struct device *dev = bus->dev; -struct opp_table *opp_table;const char *supplies[] = {"vdd" ,NULL };int i, ret, count, size; - opp_table =dev_pm_opp_set_regulators (dev, supplies); -if (IS_ERR (opp_table)) { - ret =PTR_ERR (opp_table); + ret =dev_pm_opp_set_regulators (dev, supplies); +if (ret <0 ) {dev_err (dev,"failed to set regulators %d\n" , ret);return ret; } - bus->opp_table = opp_table; + bus->opp_token = ret;/* * Get the devfreq-event devices to get the current utilization of
@@ -236,8 +233,7 @@ static int exynos_bus_parent_parse_of(struct device_node *np,return 0 ; err_regulator: -dev_pm_opp_put_regulators (bus->opp_table); - bus->opp_table =NULL ; +dev_pm_opp_put_regulators (bus->opp_token);return ret; }
@@ -459,8 +455,7 @@ static int exynos_bus_probe(struct platform_device *pdev)dev_pm_opp_of_remove_table (dev);clk_disable_unprepare (bus->clk); err_reg: -dev_pm_opp_put_regulators (bus->opp_table); - bus->opp_table =NULL ; +dev_pm_opp_put_regulators (bus->opp_token);return ret; }
drivers/opp/core.c +19 -72
166 lines not on this page · raw message
include/linux/pm_opp.h +28 -16
60 lines not on this page · raw message
Signature · 1 line
2.31.1.272.g89b43f80a514
Re: [PATCH V3 10/20] OPP: Migrate set-regulators API to use set-config helpers
Quoted 16 lines · Viresh Kumar
Now that we have a central API to handle all OPP table configurations, migrate the set-regulators family of helpers to use the new infrastructure.
The return type and parameter to the APIs change a bit due to this, update the current users as well in the same commit in order to avoid breaking builds.
Signed-off-by Viresh Kumar <[email protected]>--- drivers/cpufreq/cpufreq-dt.c | 12 ++--- drivers/devfreq/exynos-bus.c | 19 +++----- drivers/opp/core.c | 91 ++++++++---------------------------- include/linux/pm_opp.h | 44 ++++++++++------- 4 files changed, 60 insertions(+), 106 deletions(-)
(snip)
Quoted 56 lines
drivers/devfreq/exynos-bus.c +6
-10@@ -33,7 +33,7 @@ struct exynos_bus {unsigned long curr_freq; -struct opp_table *opp_table; +int opp_token;struct clk *clk;unsigned int ratio; };@@ -161,8 +161,7 @@ static void exynos_bus_exit(struct device *dev)dev_pm_opp_of_remove_table (dev);clk_disable_unprepare (bus->clk); -dev_pm_opp_put_regulators (bus->opp_table); - bus->opp_table =NULL ; +dev_pm_opp_put_regulators (bus->opp_token); }static void exynos_bus_passive_exit (struct device *dev)@@ -179,18 +178,16 @@ static int exynos_bus_parent_parse_of(struct device_node *np, struct exynos_bus *bus) {struct device *dev = bus->dev; -struct opp_table *opp_table;const char *supplies[] = {"vdd" ,NULL };int i, ret, count, size; - opp_table =dev_pm_opp_set_regulators (dev, supplies); -if (IS_ERR (opp_table)) { - ret =PTR_ERR (opp_table); + ret =dev_pm_opp_set_regulators (dev, supplies); +if (ret <0 ) {dev_err (dev,"failed to set regulators %d\n" , ret);return ret; } - bus->opp_table = opp_table; + bus->opp_token = ret;/* * Get the devfreq-event devices to get the current utilization of @@ -236,8 +233,7 @@ static int exynos_bus_parent_parse_of(struct device_node *np,return 0 ; err_regulator: -dev_pm_opp_put_regulators (bus->opp_table); - bus->opp_table =NULL ; +dev_pm_opp_put_regulators (bus->opp_token);return ret; }
drivers/devfreq/exynos-bus.c static int exynos_bus_probe(struct platform_device *pdev) · line 461
Quoted 9 lines
drivers/devfreq/exynos-bus.c +1
-2@@ -459,8 +455,7 @@ static int exynos_bus_probe(struct platform_device *pdev)dev_pm_opp_of_remove_table (dev);clk_disable_unprepare (bus->clk); err_reg: -dev_pm_opp_put_regulators (bus->opp_table); - bus->opp_table =NULL ; +dev_pm_opp_put_regulators (bus->opp_token);return ret; }
Thanks.
(snip)
Signature · 3 lines
Best Regards, Samsung Electronics Chanwoo Choi
Viresh Kumar
maintainerPATCH v3 11/20 OPP: Migrate set-supported-hw API to use set-config helpers
In reply to Viresh KumarNow that we have a central API to handle all OPP table configurations, migrate the set-supported-hw family of helpers to use the new infrastructure.
The return type and parameter to the APIs change a bit due to this, update the current users as well in the same commit in order to avoid breaking builds.
--- drivers/cpufreq/imx-cpufreq-dt.c | 12 ++-- drivers/cpufreq/tegra20-cpufreq.c | 12 ++-- drivers/memory/tegra/tegra124-emc.c | 11 ++-- drivers/opp/core.c | 87 +++++++---------------------- include/linux/pm_opp.h | 49 +++++++++------- 5 files changed, 66 insertions(+), 105 deletions(-)
drivers/cpufreq/imx-cpufreq-dt.c +6 -6
@@ -31,8 +31,8 @@/* cpufreq-dt device registered by imx-cpufreq-dt */ static struct platform_device *cpufreq_dt_pdev; -static struct opp_table *cpufreq_opp_table;static struct device *cpu_dev; +static int cpufreq_opp_token;enum IMX7ULP_CPUFREQ_CLKS {ARM ,
@@ -153,9 +153,9 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)dev_info (&pdev->dev,"cpu speed grade %d mkt segment %d supported-hw %#x %#x\n" , speed_grade, mkt_segment, supported_hw[0 ], supported_hw[1 ]); - cpufreq_opp_table =dev_pm_opp_set_supported_hw (cpu_dev, supported_hw,2 ); -if (IS_ERR (cpufreq_opp_table)) { - ret =PTR_ERR (cpufreq_opp_table); + cpufreq_opp_token =dev_pm_opp_set_supported_hw (cpu_dev, supported_hw,2 ); +if (cpufreq_opp_token <0 ) { + ret = cpufreq_opp_token;dev_err (&pdev->dev,"Failed to set supported opp: %d\n" , ret);return ret; }
@@ -163,7 +163,7 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev) cpufreq_dt_pdev =platform_device_register_data ( &pdev->dev,"cpufreq-dt" ,-1 ,NULL ,0 );if (IS_ERR (cpufreq_dt_pdev)) { -dev_pm_opp_put_supported_hw (cpufreq_opp_table); +dev_pm_opp_put_supported_hw (cpufreq_opp_token); ret =PTR_ERR (cpufreq_dt_pdev);dev_err (&pdev->dev,"Failed to register cpufreq-dt: %d\n" , ret);return ret;
@@ -176,7 +176,7 @@ static int imx_cpufreq_dt_remove(struct platform_device *pdev) {platform_device_unregister (cpufreq_dt_pdev);if (!of_machine_is_compatible ("fsl,imx7ulp" )) -dev_pm_opp_put_supported_hw (cpufreq_opp_table); +dev_pm_opp_put_supported_hw (cpufreq_opp_token);else clk_bulk_put (ARRAY_SIZE (imx7ulp_clks), imx7ulp_clks);
drivers/cpufreq/tegra20-cpufreq.c +5 -7
@@ -32,9 +32,9 @@ static bool cpu0_node_has_opp_v2_prop(void)return ret; } -static void tegra20_cpufreq_put_supported_hw (void *opp_table) +static void tegra20_cpufreq_put_supported_hw (void *opp_token) { -dev_pm_opp_put_supported_hw (opp_table); +dev_pm_opp_put_supported_hw ((unsigned long ) opp_token); }static void tegra20_cpufreq_dt_unregister (void *cpufreq_dt)
@@ -45,7 +45,6 @@ static void tegra20_cpufreq_dt_unregister(void *cpufreq_dt)static int tegra20_cpufreq_probe (struct platform_device *pdev) {struct platform_device *cpufreq_dt; -struct opp_table *opp_table;struct device *cpu_dev;u32 versions[2 ];int err;
@@ -71,16 +70,15 @@ static int tegra20_cpufreq_probe(struct platform_device *pdev)if (WARN_ON (!cpu_dev))return -ENODEV ; - opp_table =dev_pm_opp_set_supported_hw (cpu_dev, versions,2 ); - err =PTR_ERR_OR_ZERO (opp_table); -if (err) { + err =dev_pm_opp_set_supported_hw (cpu_dev, versions,2 ); +if (err <0 ) {dev_err (&pdev->dev,"failed to set supported hw: %d\n" , err);return err; } err =devm_add_action_or_reset (&pdev->dev, tegra20_cpufreq_put_supported_hw, - opp_table); + (void *)((unsigned long ) err));if (err)return err;
drivers/memory/tegra/tegra124-emc.c +5 -6
@@ -1395,15 +1395,14 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc)static int tegra_emc_opp_table_init (struct tegra_emc *emc) {u32 hw_version =BIT (tegra_sku_info.soc_speedo_id); -struct opp_table *hw_opp_table; -int err; +int opp_token, err; - hw_opp_table =dev_pm_opp_set_supported_hw (emc->dev, &hw_version,1 ); - err =PTR_ERR_OR_ZERO (hw_opp_table); -if (err) { + err =dev_pm_opp_set_supported_hw (emc->dev, &hw_version,1 ); +if (err <0 ) {dev_err (emc->dev,"failed to set OPP supported HW: %d\n" , err);return err; } + opp_token = err; err =dev_pm_opp_of_add_table (emc->dev);if (err) {
@@ -1430,7 +1429,7 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc) remove_table:dev_pm_opp_of_remove_table (emc->dev); put_hw_table: -dev_pm_opp_put_supported_hw (hw_opp_table); +dev_pm_opp_put_supported_hw (opp_token);return err; }
drivers/opp/core.c +20 -67
130 lines not on this page · raw message
include/linux/pm_opp.h +30 -19
65 lines not on this page · raw message
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 12/20 OPP: Migrate set-clk-name API to use set-config helpers
In reply to Viresh KumarNow that we have a central API to handle all OPP table configurations, migrate the set-clk-name family of helpers to use the new infrastructure.
--- drivers/opp/core.c | 142 +++++++++++++---------------------------- include/linux/pm_opp.h | 41 +++++++----- 2 files changed, 69 insertions(+), 114 deletions(-)
drivers/opp/core.c +43 -99
@@ -2164,104 +2164,71 @@ static void _opp_put_regulators(struct opp_table *opp_table) }/** -* dev_pm_opp_set_clkname() - Set clk name for the device -* @dev: Device for which clk name is being set. -* @name: Clk name. -* -* In order to support OPP switching, OPP layer needs to get pointer to the -* clock for the device. Simple cases work fine without using this routine (i.e. -* by passing connection-id as NULL), but for a device with multiple clocks -* available, the OPP core needs to know the exact name of the clk to use. +* _opp_set_clknames() - Set clk names for the device +* @dev: Device for which clk names is being set. +* @names: Clk names. +* +* In order to support OPP switching, OPP layer needs to get pointers to the +* clocks for the device. Simple cases work fine without using this routine +* (i.e. by passing connection-id as NULL), but for a device with multiple +* clocks available, the OPP core needs to know the exact names of the clks to +* use. * * This must be called before any OPPs are initialized for the device. */ -struct opp_table *dev_pm_opp_set_clkname (struct device *dev,const char *name) +static int _opp_set_clknames (struct opp_table *opp_table,struct device *dev, +const char *const names[]) { -struct opp_table *opp_table; -int ret; +const char *const *temp = names; +int count =0 ; - opp_table =_add_opp_table (dev, false); -if (IS_ERR (opp_table)) -return opp_table; +/* Count number of clks */ +while (*temp++) + count++; -/* This should be called before OPPs are initialized */ -if (WARN_ON (!list_empty (&opp_table->opp_list))) { - ret = -EBUSY ; - goto err; - } +/* +* This is a special case where we have a single clock, whose connection +* id name is NULL, i.e. first two entries are NULL in the array. +*/ +if (!count && !names[1 ]) + count =1 ; + +/* We support only one clock name for now */ +if (count !=1 ) +return -EINVAL ;/* Another CPU that shares the OPP table has set the clkname ? */ if (opp_table->clk_configured) -return opp_table; +return 0 ;/* clk shouldn't be initialized at this point */ -if (WARN_ON (opp_table->clk)) { - ret = -EBUSY ; - goto err; - } +if (WARN_ON (opp_table->clk)) +return -EBUSY ;/* Find clk for the device */ - opp_table->clk =clk_get (dev, name); + opp_table->clk =clk_get (dev, names[0 ]);if (IS_ERR (opp_table->clk)) { - ret =dev_err_probe (dev,PTR_ERR (opp_table->clk), +return dev_err_probe (dev,PTR_ERR (opp_table->clk),"%s: Couldn't find clock\n" , __func__); - goto err; } opp_table->clk_configured = true; -return opp_table; - -err: -dev_pm_opp_put_opp_table (opp_table); - -return ERR_PTR (ret); -} -EXPORT_SYMBOL_GPL (dev_pm_opp_set_clkname); - -/** -* dev_pm_opp_put_clkname() - Releases resources blocked for clk. -* @opp_table: OPP table returned from dev_pm_opp_set_clkname(). -*/ -void dev_pm_opp_put_clkname (struct opp_table *opp_table) -{ -if (unlikely (!opp_table)) -return ; - -clk_put (opp_table->clk); - opp_table->clk =ERR_PTR (-EINVAL ); - opp_table->clk_configured = false; - -dev_pm_opp_put_opp_table (opp_table); -} -EXPORT_SYMBOL_GPL (dev_pm_opp_put_clkname); - -static void devm_pm_opp_clkname_release (void *data) -{ -dev_pm_opp_put_clkname (data); +return 0 ; }/** -* devm_pm_opp_set_clkname() - Set clk name for the device -* @dev: Device for which clk name is being set. -* @name: Clk name. -* -* This is a resource-managed variant of dev_pm_opp_set_clkname(). -* -* Return: 0 on success and errorno otherwise. +* _opp_put_clknames() - Releases resources blocked for clks. +* @opp_table: OPP table returned from _opp_set_clknames(). */ -int devm_pm_opp_set_clkname (struct device *dev,const char *name) +static void _opp_put_clknames (struct opp_table *opp_table) { -struct opp_table *opp_table; - - opp_table =dev_pm_opp_set_clkname (dev, name); -if (IS_ERR (opp_table)) -return PTR_ERR (opp_table); - -return devm_add_action_or_reset (dev, devm_pm_opp_clkname_release, - opp_table); +if (opp_table->clk_configured) { +clk_put (opp_table->clk); + opp_table->clk =ERR_PTR (-EINVAL ); + opp_table->clk_configured = false; + } } -EXPORT_SYMBOL_GPL (devm_pm_opp_set_clkname);/** * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
@@ -2544,7 +2511,7 @@ static void _opp_clear_config(struct opp_config_data *data)if (data->flags &OPP_CONFIG_PROP_NAME )dev_pm_opp_put_prop_name (data->opp_table);if (data->flags &OPP_CONFIG_CLK ) -dev_pm_opp_put_clkname (data->opp_table); +_opp_put_clknames (data->opp_table);dev_pm_opp_put_opp_table (data->opp_table);kfree (data);
@@ -2595,32 +2562,9 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)/* Configure clocks */ if (config->clk_names) { -const char *const *temp = config->clk_names; -int count =0 ; - -/* Count number of clks */ -while (*temp++) - count++; - -/* -* This is a special case where we have a single clock, whose -* connection id name is NULL, i.e. first two entries are NULL -* in the array. -*/ -if (!count && !config->clk_names[1 ]) - count =1 ; - -/* We support only one clock name for now */ -if (count !=1 ) { - ret = -EINVAL ; - goto err; - } - - err =dev_pm_opp_set_clkname (dev, config->clk_names[0 ]); -if (IS_ERR (err)) { - ret =PTR_ERR (err); + ret =_opp_set_clknames (opp_table, dev, config->clk_names); +if (ret) goto err; - } data->flags |=OPP_CONFIG_CLK ; }
include/linux/pm_opp.h +26 -15
57 lines not on this page · raw message
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 13/20 OPP: Migrate set-opp-helper API to use set-config helpers
In reply to Viresh KumarNow that we have a central API to handle all OPP table configurations, migrate the set-opp-helper family of helpers to use the new infrastructure.
The return type and parameter to the APIs change a bit due to this, update the current users as well in the same commit in order to avoid breaking builds.
Remove devm_pm_opp_register_set_opp_helper() as it has no users currently.
--- drivers/opp/core.c | 89 +++++++++---------------------------- drivers/opp/ti-opp-supply.c | 6 +-- include/linux/pm_opp.h | 33 +++++++------- 3 files changed, 39 insertions(+), 89 deletions(-)
drivers/opp/core.c +20 -69
@@ -2231,7 +2231,7 @@ static void _opp_put_clknames(struct opp_table *opp_table) }/** -* dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper +* _opp_register_set_opp_helper() - Register custom set OPP helper * @dev: Device for which the helper is getting registered. * @set_opp: Custom set OPP helper. *
@@ -2240,32 +2240,18 @@ static void _opp_put_clknames(struct opp_table *opp_table)* * This must be called before any OPPs are initialized for the device. */ -struct opp_table *dev_pm_opp_register_set_opp_helper (struct device *dev, -int (*set_opp)(struct dev_pm_set_opp_data *data)) +static int _opp_register_set_opp_helper (struct opp_table *opp_table, +struct device *dev,int (*set_opp)(struct dev_pm_set_opp_data *data)) {struct dev_pm_set_opp_data *data; -struct opp_table *opp_table; - -if (!set_opp) -return ERR_PTR (-EINVAL ); - - opp_table =_add_opp_table (dev, false); -if (IS_ERR (opp_table)) -return opp_table; - -/* This should be called before OPPs are initialized */ -if (WARN_ON (!list_empty (&opp_table->opp_list))) { -dev_pm_opp_put_opp_table (opp_table); -return ERR_PTR (-EBUSY ); - }/* Another CPU that shares the OPP table has set the helper ? */ if (opp_table->set_opp) -return opp_table; +return 0 ; data =kzalloc (sizeof (*data),GFP_KERNEL );if (!data) -return ERR_PTR (-ENOMEM ); +return -ENOMEM ;mutex_lock (&opp_table->lock); opp_table->set_opp_data = data;
@@ -2278,60 +2264,26 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, opp_table->set_opp = set_opp; -return opp_table; +return 0 ; } -EXPORT_SYMBOL_GPL (dev_pm_opp_register_set_opp_helper);/** -* dev_pm_opp_unregister_set_opp_helper() - Releases resources blocked for -* set_opp helper -* @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper(). +* _opp_unregister_set_opp_helper() - Releases resources blocked for set_opp helper +* @opp_table: OPP table returned from _opp_register_set_opp_helper(). * * Release resources blocked for platform specific set_opp helper. */ -void dev_pm_opp_unregister_set_opp_helper (struct opp_table *opp_table) +static void _opp_unregister_set_opp_helper (struct opp_table *opp_table) { -if (unlikely (!opp_table)) -return ; - - opp_table->set_opp =NULL ; - -mutex_lock (&opp_table->lock); -kfree (opp_table->set_opp_data); - opp_table->set_opp_data =NULL ; -mutex_unlock (&opp_table->lock); - -dev_pm_opp_put_opp_table (opp_table); -} -EXPORT_SYMBOL_GPL (dev_pm_opp_unregister_set_opp_helper); - -static void devm_pm_opp_unregister_set_opp_helper (void *data) -{ -dev_pm_opp_unregister_set_opp_helper (data); -} - -/** -* devm_pm_opp_register_set_opp_helper() - Register custom set OPP helper -* @dev: Device for which the helper is getting registered. -* @set_opp: Custom set OPP helper. -* -* This is a resource-managed version of dev_pm_opp_register_set_opp_helper(). -* -* Return: 0 on success and errorno otherwise. -*/ -int devm_pm_opp_register_set_opp_helper (struct device *dev, -int (*set_opp)(struct dev_pm_set_opp_data *data)) -{ -struct opp_table *opp_table; - - opp_table =dev_pm_opp_register_set_opp_helper (dev, set_opp); -if (IS_ERR (opp_table)) -return PTR_ERR (opp_table); +if (opp_table->set_opp) { + opp_table->set_opp =NULL ; -return devm_add_action_or_reset (dev, devm_pm_opp_unregister_set_opp_helper, - opp_table); +mutex_lock (&opp_table->lock); +kfree (opp_table->set_opp_data); + opp_table->set_opp_data =NULL ; +mutex_unlock (&opp_table->lock); + } } -EXPORT_SYMBOL_GPL (devm_pm_opp_register_set_opp_helper);static void _opp_detach_genpd (struct opp_table *opp_table) {
@@ -2507,7 +2459,7 @@ static void _opp_clear_config(struct opp_config_data *data)if (data->flags &OPP_CONFIG_SUPPORTED_HW )_opp_put_supported_hw (data->opp_table);if (data->flags &OPP_CONFIG_REGULATOR_HELPER ) -dev_pm_opp_unregister_set_opp_helper (data->opp_table); +_opp_unregister_set_opp_helper (data->opp_table);if (data->flags &OPP_CONFIG_PROP_NAME )dev_pm_opp_put_prop_name (data->opp_table);if (data->flags &OPP_CONFIG_CLK )
@@ -2582,11 +2534,10 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)/* Configure opp helper */ if (config->set_opp) { - err =dev_pm_opp_register_set_opp_helper (dev, config->set_opp); -if (IS_ERR (err)) { - ret =PTR_ERR (err); + ret =_opp_register_set_opp_helper (opp_table, dev, + config->set_opp); +if (ret) goto err; - } data->flags |=OPP_CONFIG_REGULATOR_HELPER ; }
drivers/opp/ti-opp-supply.c +3 -3
@@ -405,9 +405,9 @@ static int ti_opp_supply_probe(struct platform_device *pdev)return ret; } - ret =PTR_ERR_OR_ZERO (dev_pm_opp_register_set_opp_helper (cpu_dev, - ti_opp_supply_set_opp)); -if (ret) + ret =dev_pm_opp_register_set_opp_helper (cpu_dev, + ti_opp_supply_set_opp); +if (ret <0 )_free_optimized_voltages (dev, &opp_data);return ret;
include/linux/pm_opp.h +16 -17
@@ -186,9 +186,6 @@ void dev_pm_opp_clear_config(int token);struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name);void dev_pm_opp_put_prop_name (struct opp_table *opp_table); -struct opp_table *dev_pm_opp_register_set_opp_helper (struct device *dev,int (*set_opp)(struct dev_pm_set_opp_data *data)); -void dev_pm_opp_unregister_set_opp_helper (struct opp_table *opp_table); -int devm_pm_opp_register_set_opp_helper (struct device *dev,int (*set_opp)(struct dev_pm_set_opp_data *data));struct opp_table *dev_pm_opp_attach_genpd (struct device *dev,const char *const *names,struct device ***virt_devs);void dev_pm_opp_detach_genpd (struct opp_table *opp_table);int devm_pm_opp_attach_genpd (struct device *dev,const char *const *names,struct device ***virt_devs);
@@ -363,20 +360,6 @@ static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notireturn -EOPNOTSUPP ; } -static inline struct opp_table *dev_pm_opp_register_set_opp_helper (struct device *dev, -int (*set_opp)(struct dev_pm_set_opp_data *data)) -{ -return ERR_PTR (-EOPNOTSUPP ); -} - -static inline void dev_pm_opp_unregister_set_opp_helper (struct opp_table *opp_table) {} - -static inline int devm_pm_opp_register_set_opp_helper (struct device *dev, -int (*set_opp)(struct dev_pm_set_opp_data *data)) -{ -return -EOPNOTSUPP ; -} -static inline struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name) {return ERR_PTR (-EOPNOTSUPP );
@@ -640,4 +623,20 @@ static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name) return devm_pm_opp_set_config(dev, &config); } +/* set-opp helpers */ +static inline int dev_pm_opp_register_set_opp_helper (struct device *dev, +int (*set_opp)(struct dev_pm_set_opp_data *data)) +{ +struct dev_pm_opp_config config = { + .set_opp = set_opp, + }; + +return dev_pm_opp_set_config (dev, &config); +} + +static inline void dev_pm_opp_unregister_set_opp_helper (int token) +{ +dev_pm_opp_clear_config (token); +} +#endif /* __LINUX_OPP_H__ */
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 14/20 OPP: Migrate attach-genpd API to use set-config helpers
In reply to Viresh KumarNow that we have a central API to handle all OPP table configurations, migrate the attach-genpd family of helpers to use the new infrastructure.
--- drivers/opp/core.c | 85 +++++++++--------------------------------- include/linux/pm_opp.h | 48 +++++++++++++++--------- 2 files changed, 49 insertions(+), 84 deletions(-)
drivers/opp/core.c +18 -67
@@ -2285,7 +2285,7 @@ static void _opp_unregister_set_opp_helper(struct opp_table *opp_table) } } -static void _opp_detach_genpd (struct opp_table *opp_table) +static void _detach_genpd (struct opp_table *opp_table) {int index;
@@ -2305,7 +2305,7 @@ static void _opp_detach_genpd(struct opp_table *opp_table) }/** -* dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer +* _opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer * @dev: Consumer device for which the genpd is getting attached. * @names: Null terminated array of pointers containing names of genpd to attach. * @virt_devs: Pointer to return the array of virtual devices.
@@ -2326,30 +2326,23 @@ static void _opp_detach_genpd(struct opp_table *opp_table)* The order of entries in the names array must match the order in which * "required-opps" are added in DT. */ -struct opp_table *dev_pm_opp_attach_genpd (struct device *dev, -const char *const *names,struct device ***virt_devs) +static int _opp_attach_genpd (struct opp_table *opp_table,struct device *dev, +const char *const *names,struct device ***virt_devs) { -struct opp_table *opp_table;struct device *virt_dev;int index =0 , ret = -EINVAL ;const char *const *name = names; - opp_table =_add_opp_table (dev, false); -if (IS_ERR (opp_table)) -return opp_table; -if (opp_table->genpd_virt_devs) -return opp_table; +return 0 ;/* * If the genpd's OPP table isn't already initialized, parsing of the * required-opps fail for dev. We should retry this after genpd's OPP * table is added. */ -if (!opp_table->required_opp_count) { - ret = -EPROBE_DEFER ; - goto put_table; - } +if (!opp_table->required_opp_count) +return -EPROBE_DEFER ;mutex_lock (&opp_table->genpd_virt_dev_lock);
@@ -2382,78 +2375,38 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, *virt_devs = opp_table->genpd_virt_devs;mutex_unlock (&opp_table->genpd_virt_dev_lock); -return opp_table; +return 0 ; err: -_opp_detach_genpd (opp_table); +_detach_genpd (opp_table); unlock:mutex_unlock (&opp_table->genpd_virt_dev_lock); +return ret; -put_table: -dev_pm_opp_put_opp_table (opp_table); - -return ERR_PTR (ret); } -EXPORT_SYMBOL_GPL (dev_pm_opp_attach_genpd);/** -* dev_pm_opp_detach_genpd() - Detach genpd(s) from the device. -* @opp_table: OPP table returned by dev_pm_opp_attach_genpd(). +* _opp_detach_genpd() - Detach genpd(s) from the device. +* @opp_table: OPP table returned by _opp_attach_genpd(). * * This detaches the genpd(s), resets the virtual device pointers, and puts the * OPP table. */ -void dev_pm_opp_detach_genpd (struct opp_table *opp_table) +static void _opp_detach_genpd (struct opp_table *opp_table) { -if (unlikely (!opp_table)) -return ; -/* * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting * used in parallel. */ mutex_lock (&opp_table->genpd_virt_dev_lock); -_opp_detach_genpd (opp_table); +_detach_genpd (opp_table);mutex_unlock (&opp_table->genpd_virt_dev_lock); - -dev_pm_opp_put_opp_table (opp_table); } -EXPORT_SYMBOL_GPL (dev_pm_opp_detach_genpd); - -static void devm_pm_opp_detach_genpd (void *data) -{ -dev_pm_opp_detach_genpd (data); -} - -/** -* devm_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual -* device pointer -* @dev: Consumer device for which the genpd is getting attached. -* @names: Null terminated array of pointers containing names of genpd to attach. -* @virt_devs: Pointer to return the array of virtual devices. -* -* This is a resource-managed version of dev_pm_opp_attach_genpd(). -* -* Return: 0 on success and errorno otherwise. -*/ -int devm_pm_opp_attach_genpd (struct device *dev,const char *const *names, -struct device ***virt_devs) -{ -struct opp_table *opp_table; - - opp_table =dev_pm_opp_attach_genpd (dev, names, virt_devs); -if (IS_ERR (opp_table)) -return PTR_ERR (opp_table); - -return devm_add_action_or_reset (dev, devm_pm_opp_detach_genpd, - opp_table); -} -EXPORT_SYMBOL_GPL (devm_pm_opp_attach_genpd);static void _opp_clear_config (struct opp_config_data *data) {if (data->flags &OPP_CONFIG_GENPD ) -dev_pm_opp_detach_genpd (data->opp_table); +_opp_detach_genpd (data->opp_table);if (data->flags &OPP_CONFIG_REGULATOR )_opp_put_regulators (data->opp_table);if (data->flags &OPP_CONFIG_SUPPORTED_HW )
@@ -2564,12 +2517,10 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)/* Attach genpds */ if (config->genpd_names) { - err =dev_pm_opp_attach_genpd (dev, config->genpd_names, - config->virt_devs); -if (IS_ERR (err)) { - ret =PTR_ERR (err); + ret =_opp_attach_genpd (opp_table, dev, config->genpd_names, + config->virt_devs); +if (ret) goto err; - } data->flags |=OPP_CONFIG_GENPD ; }
include/linux/pm_opp.h +31 -17
64 lines not on this page · raw message
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 15/20 OPP: Migrate set-prop-name helper API to use set-config helpers
In reply to Viresh KumarNow that we have a central API to handle all OPP table configurations, migrate the set-prop-name family of helpers to use the new infrastructure.
The return type and parameter to the APIs change a bit due to this, update the current users as well in the same commit in order to avoid breaking builds.
--- drivers/cpufreq/sun50i-cpufreq-nvmem.c | 31 +++++++-------- drivers/opp/core.c | 55 +++++++++----------------- include/linux/pm_opp.h | 23 ++++++----- 3 files changed, 46 insertions(+), 63 deletions(-)
drivers/cpufreq/sun50i-cpufreq-nvmem.c +14 -17
@@ -86,20 +86,20 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)static int sun50i_cpufreq_nvmem_probe (struct platform_device *pdev) { -struct opp_table **opp_tables; +int *opp_tokens;char name[MAX_NAME_LEN ];unsigned int cpu;u32 speed =0 ;int ret; - opp_tables =kcalloc (num_possible_cpus (),sizeof (*opp_tables), + opp_tokens =kcalloc (num_possible_cpus (),sizeof (*opp_tokens),GFP_KERNEL ); -if (!opp_tables) +if (!opp_tokens)return -ENOMEM ; ret =sun50i_cpufreq_get_efuse (&speed);if (ret) { -kfree (opp_tables); +kfree (opp_tokens);return ret; }
@@ -113,9 +113,9 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) goto free_opp; } - opp_tables[cpu] =dev_pm_opp_set_prop_name (cpu_dev, name); -if (IS_ERR (opp_tables[cpu])) { - ret =PTR_ERR (opp_tables[cpu]); + opp_tokens[cpu] =dev_pm_opp_set_prop_name (cpu_dev, name); +if (opp_tokens[cpu] <0 ) { + ret = opp_tokens[cpu];pr_err ("Failed to set prop name\n" ); goto free_opp; }
@@ -124,7 +124,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) cpufreq_dt_pdev =platform_device_register_simple ("cpufreq-dt" ,-1 ,NULL ,0 );if (!IS_ERR (cpufreq_dt_pdev)) { -platform_set_drvdata (pdev, opp_tables); +platform_set_drvdata (pdev, opp_tokens);return 0 ; }
@@ -132,27 +132,24 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)pr_err ("Failed to register platform device\n" ); free_opp: -for_each_possible_cpu (cpu) { -if (IS_ERR_OR_NULL (opp_tables[cpu])) -break ; -dev_pm_opp_put_prop_name (opp_tables[cpu]); - } -kfree (opp_tables); +for_each_possible_cpu (cpu) +dev_pm_opp_put_prop_name (opp_tokens[cpu]); +kfree (opp_tokens);return ret; }static int sun50i_cpufreq_nvmem_remove (struct platform_device *pdev) { -struct opp_table **opp_tables =platform_get_drvdata (pdev); +int *opp_tokens =platform_get_drvdata (pdev);unsigned int cpu;platform_device_unregister (cpufreq_dt_pdev);for_each_possible_cpu (cpu) -dev_pm_opp_put_prop_name (opp_tables[cpu]); +dev_pm_opp_put_prop_name (opp_tokens[cpu]); -kfree (opp_tables); +kfree (opp_tokens);return 0 ; }
drivers/opp/core.c +18 -37
100 lines not on this page · raw message
include/linux/pm_opp.h +14 -9
@@ -184,8 +184,6 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);int devm_pm_opp_set_config (struct device *dev,struct dev_pm_opp_config *config);void dev_pm_opp_clear_config (int token); -struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name); -void dev_pm_opp_put_prop_name (struct opp_table *opp_table);struct dev_pm_opp *dev_pm_opp_xlate_required_opp (struct opp_table *src_table,struct opp_table *dst_table,struct dev_pm_opp *src_opp);int dev_pm_opp_xlate_performance_state (struct opp_table *src_table,struct opp_table *dst_table,unsigned int pstate);int dev_pm_opp_set_rate (struct device *dev,unsigned long target_freq);
@@ -357,13 +355,6 @@ static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notireturn -EOPNOTSUPP ; } -static inline struct opp_table *dev_pm_opp_set_prop_name (struct device *dev,const char *name) -{ -return ERR_PTR (-EOPNOTSUPP ); -} - -static inline void dev_pm_opp_put_prop_name (struct opp_table *opp_table) {} -static inline int dev_pm_opp_set_config (struct device *dev,struct dev_pm_opp_config *config) {return -EOPNOTSUPP ;
@@ -652,5 +643,19 @@ static inline int devm_pm_opp_attach_genpd(struct device *dev, return devm_pm_opp_set_config(dev, &config); } +/* prop-name helpers */ +static inline int dev_pm_opp_set_prop_name (struct device *dev,const char *name) +{ +struct dev_pm_opp_config config = { + .prop_name = name, + }; + +return dev_pm_opp_set_config (dev, &config); +} + +static inline void dev_pm_opp_put_prop_name (int token) +{ +dev_pm_opp_clear_config (token); +}#endif /* __LINUX_OPP_H__ */
Signature · 1 line
2.31.1.272.g89b43f80a514
Re: [PATCH V3 15/20] OPP: Migrate set-prop-name helper API to use set-config helpers
Quoted 11 lines · Viresh Kumar
Now that we have a central API to handle all OPP table configurations, migrate the set-prop-name family of helpers to use the new infrastructure.
The return type and parameter to the APIs change a bit due to this, update the current users as well in the same commit in order to avoid breaking builds.
Signed-off-by Viresh Kumar <[email protected]>--- drivers/cpufreq/sun50i-cpufreq-nvmem.c | 31 +++++++--------
For sun50i-cpufreq-nvmem.c:
Quoted 3 lines
drivers/opp/core.c | 55 +++++++++----------------- include/linux/pm_opp.h | 23 ++++++----- 3 files changed, 46 insertions(+), 63 deletions(-)
Viresh Kumar
maintainerPATCH v3 16/20 OPP: Add support for config_regulators() helper
In reply to Viresh KumarExtend the dev_pm_opp_set_config() interface to allow adding config_regulators() helpers. This helper will be called to set the voltages of the regulators from the regular path in _set_opp(), while we are trying to change the OPP.
This will eventually replace the custom set_opp() helper.
--- drivers/opp/core.c | 68 +++++++++++++++++++++++++++++++++++++++++- drivers/opp/opp.h | 2 ++ include/linux/pm_opp.h | 22 ++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-)
drivers/opp/core.c +67 -1
@@ -1185,6 +1185,17 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,dev_err (dev,"Failed to set bw: %d\n" , ret);return ret; } + +if (opp_table->config_regulators) { + ret = opp_table->config_regulators (dev, old_opp, opp, + opp_table->regulators, + opp_table->regulator_count); +if (ret) { +dev_err (dev,"Failed to set regulator voltages: %d\n" , + ret); +return ret; + } + } }if (opp_table->set_opp) {
@@ -1202,6 +1213,17 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,/* Scaling down? Configure required OPPs after frequency */ if (scaling_down) { +if (opp_table->config_regulators) { + ret = opp_table->config_regulators (dev, old_opp, opp, + opp_table->regulators, + opp_table->regulator_count); +if (ret) { +dev_err (dev,"Failed to set regulator voltages: %d\n" , + ret); +return ret; + } + } + ret =_set_opp_bw (opp_table, opp, dev);if (ret) {dev_err (dev,"Failed to set bw: %d\n" , ret);
@@ -2268,6 +2290,38 @@ static void _opp_unregister_set_opp_helper(struct opp_table *opp_table) } } +/** +* _opp_set_config_regulators_helper() - Register custom set regulator helper. +* @dev: Device for which the helper is getting registered. +* @config_regulators: Custom set regulator helper. +* +* This is useful to support platforms with multiple regulators per device. +* +* This must be called before any OPPs are initialized for the device. +*/ +static int _opp_set_config_regulators_helper (struct opp_table *opp_table, +struct device *dev,config_regulators_t config_regulators) +{ +/* Another CPU that shares the OPP table has set the helper ? */ +if (!opp_table->config_regulators) + opp_table->config_regulators = config_regulators; + +return 0 ; +} + +/** +* _opp_put_config_regulators_helper() - Releases resources blocked for +* config_regulators helper. +* @opp_table: OPP table returned from _opp_set_config_regulators_helper(). +* +* Release resources blocked for platform specific config_regulators helper. +*/ +static void _opp_put_config_regulators_helper (struct opp_table *opp_table) +{ +if (opp_table->config_regulators) + opp_table->config_regulators =NULL ; +} +static void _detach_genpd (struct opp_table *opp_table) {int index;
@@ -2394,8 +2448,10 @@ static void _opp_clear_config(struct opp_config_data *data)_opp_put_regulators (data->opp_table);if (data->flags &OPP_CONFIG_SUPPORTED_HW )_opp_put_supported_hw (data->opp_table); -if (data->flags &OPP_CONFIG_REGULATOR_HELPER ) +if (data->flags &OPP_CONFIG_REGULATOR_HELPER ) { +_opp_put_config_regulators_helper (data->opp_table);_opp_unregister_set_opp_helper (data->opp_table); + }if (data->flags &OPP_CONFIG_PROP_NAME )_opp_put_prop_name (data->opp_table);if (data->flags &OPP_CONFIG_CLK )
@@ -2476,6 +2532,16 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config) data->flags |=OPP_CONFIG_REGULATOR_HELPER ; } +/* Configure config_regulators helper */ +if (config->config_regulators) { + ret =_opp_set_config_regulators_helper (opp_table, dev, + config->config_regulators); +if (ret) + goto err; + + data->flags |=OPP_CONFIG_REGULATOR_HELPER ; + } +/* Configure supported hardware */ if (config->supported_hw) { ret = _opp_set_supported_hw(opp_table, config->supported_hw,
drivers/opp/opp.h +2 -0
@@ -172,6 +172,7 @@ enum opp_table_access {* @prop_name: A name to postfix to many DT properties, while parsing them. * @clk_configured: Clock name is configured by the platform. * @clk: Device's clock handle +* @config_regulators: Platform specific config_regulators() callback. * @regulators: Supply regulators * @regulator_count: Number of power supply regulators. Its value can be -1 * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt
@@ -224,6 +225,7 @@ struct opp_table {const char *prop_name;bool clk_configured;struct clk *clk; +config_regulators_t config_regulators;struct regulator **regulators;int regulator_count;struct icc_path **paths;
include/linux/pm_opp.h +22 -0
@@ -90,11 +90,16 @@ struct dev_pm_set_opp_data {struct device *dev; }; +typedef int (*config_regulators_t )(struct device *dev, +struct dev_pm_opp *old_opp,struct dev_pm_opp *new_opp, +struct regulator **regulators,unsigned int count); +/** * struct dev_pm_opp_config - Device OPP configuration values * @clk_names: Clk names, NULL terminated array, max 1 clock for now. * @prop_name: Name to postfix to properties. * @set_opp: Custom set OPP helper. +* @config_regulators: Custom set regulator helper. * @supported_hw: Array of hierarchy of versions to match. * @supported_hw_count: Number of elements in the array. * @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
@@ -109,6 +114,7 @@ struct dev_pm_opp_config {const char *const *clk_names;const char *prop_name;int (*set_opp)(struct dev_pm_set_opp_data *data); +config_regulators_t config_regulators;const unsigned int *supported_hw;unsigned int supported_hw_count;const char *const *regulator_names;
@@ -613,6 +619,22 @@ static inline void dev_pm_opp_unregister_set_opp_helper(int token)dev_pm_opp_clear_config (token); } +/* config-regulators helpers */ +static inline int dev_pm_opp_set_config_regulators (struct device *dev, +config_regulators_t helper) +{ +struct dev_pm_opp_config config = { + .config_regulators = helper, + }; + +return dev_pm_opp_set_config (dev, &config); +} + +static inline void dev_pm_opp_put_config_regulators (int token) +{ +dev_pm_opp_clear_config (token); +} +/* genpd helpers */ static inline int dev_pm_opp_attach_genpd(struct device *dev, const char * const *names,
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 17/20 OPP: Make _generic_set_opp_regulator() a config_regulators() interface
In reply to Viresh KumarIn order to reuse the same code path, i.e. clk_set_rate() from _set_opp(), migrate _generic_set_opp_regulator() to implement a config_regulators() interface.
It is renamed to _opp_config_regulator_single() and is set as the preferred config_regulators() interface whenever we have a single regulator available.
Note that this also drops code responsible for restoring the voltage/freq in case of errors. We aren't handling that properly currently, restoring only some of the resources while leaving others out (like bandwidth and required OPPs). It is better to drop all of it instead of partial restoration.
--- drivers/opp/core.c | 51 +++++++++++----------------------------------- 1 file changed, 12 insertions(+), 39 deletions(-)
drivers/opp/core.c +12 -39
@@ -896,62 +896,34 @@ static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk,return ret; } -static int _generic_set_opp_regulator (struct opp_table *opp_table, -struct device *dev, -struct dev_pm_opp *opp, -unsigned long freq, -int scaling_down) +static int _opp_config_regulator_single (struct device *dev, +struct dev_pm_opp *old_opp,struct dev_pm_opp *new_opp, +struct regulator **regulators,unsigned int count) { -struct regulator *reg = opp_table->regulators[0 ]; -struct dev_pm_opp *old_opp = opp_table->current_opp; +struct regulator *reg = regulators[0 ];int ret;/* This function only supports single regulator per device */ -if (WARN_ON (opp_table->regulator_count >1 )) { +if (WARN_ON (count >1 )) {dev_err (dev,"multiple regulators are not supported\n" );return -EINVAL ; } -/* Scaling up? Scale voltage before frequency */ -if (!scaling_down) { - ret =_set_opp_voltage (dev, reg, opp->supplies); -if (ret) - goto restore_voltage; - } - -/* Change frequency */ - ret =_generic_set_opp_clk_only (dev, opp_table->clk, freq); + ret =_set_opp_voltage (dev, reg, new_opp->supplies);if (ret) - goto restore_voltage; - -/* Scaling down? Scale voltage after frequency */ -if (scaling_down) { - ret =_set_opp_voltage (dev, reg, opp->supplies); -if (ret) - goto restore_freq; - } +return ret;/* * Enable the regulator after setting its voltages, otherwise it breaks * some boot-enabled regulators. */ -if (unlikely (!opp_table->enabled)) { +if (unlikely (!new_opp->opp_table->enabled)) { ret =regulator_enable (reg);if (ret <0 )dev_warn (dev,"Failed to enable regulator: %d" , ret); }return 0 ; - -restore_freq: -if (_generic_set_opp_clk_only (dev, opp_table->clk, old_opp->rate)) -dev_err (dev,"%s: failed to restore old-freq (%lu Hz)\n" , - __func__, old_opp->rate); -restore_voltage: -/* This shouldn't harm even if the voltages weren't updated earlier */ -_set_opp_voltage (dev, reg, old_opp->supplies); - -return ret; } static int _set_opp_bw(const struct opp_table *opp_table,
@@ -1200,9 +1172,6 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,if (opp_table->set_opp) { ret =_set_opp_custom (opp_table, dev, opp, freq); - }else if (opp_table->regulators) { - ret =_generic_set_opp_regulator (opp_table, dev, opp, freq, - scaling_down); }else {/* Only frequency scaling */ ret =_generic_set_opp_clk_only (dev, opp_table->clk, freq);
@@ -2121,6 +2090,10 @@ static int _opp_set_regulators(struct opp_table *opp_table, struct device *dev, }mutex_unlock (&opp_table->lock); +/* Set generic config_regulators() for single regulators here */ +if (count ==1 ) + opp_table->config_regulators = _opp_config_regulator_single; +return 0 ; free_regulators:
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 18/20 OPP: Add dev_pm_opp_get_supplies()
In reply to Viresh KumarWe already have an API for getting voltage information for a single regulator, dev_pm_opp_get_voltage(), but there is nothing available for multiple regulator case.
This patch adds a new API, dev_pm_opp_get_supplies(), to get all information related to the supplies for an OPP.
--- drivers/opp/core.c | 25 +++++++++++++++++++++++++ include/linux/pm_opp.h | 7 +++++++ 2 files changed, 32 insertions(+)
drivers/opp/core.c +25 -0
@@ -117,6 +117,31 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) }EXPORT_SYMBOL_GPL (dev_pm_opp_get_voltage); +/** +* dev_pm_opp_get_supplies() - Gets the supply information corresponding to an opp +* @opp: opp for which voltage has to be returned for +* @supplies: Placeholder for copying the supply information. +* +* Return: negative error number on failure, 0 otherwise on success after +* setting @supplies. +* +* This can be used for devices with any number of power supplies. The caller +* must ensure the @supplies array must contain space for each regulator. +*/ +int dev_pm_opp_get_supplies (struct dev_pm_opp *opp, +struct dev_pm_opp_supply *supplies) +{ +if (IS_ERR_OR_NULL (opp) || !supplies) { +pr_err ("%s: Invalid parameters\n" , __func__); +return -EINVAL ; + } + +memcpy (supplies, opp->supplies, +sizeof (*supplies) * opp->opp_table->regulator_count); +return 0 ; +} +EXPORT_SYMBOL_GPL (dev_pm_opp_get_supplies); +/** * dev_pm_opp_get_power() - Gets the power corresponding to an opp * @opp: opp for which power has to be returned for
include/linux/pm_opp.h +7 -0
@@ -129,6 +129,8 @@ void dev_pm_opp_put_opp_table(struct opp_table *opp_table);unsigned long dev_pm_opp_get_voltage (struct dev_pm_opp *opp); +int dev_pm_opp_get_supplies (struct dev_pm_opp *opp,struct dev_pm_opp_supply *supplies); +unsigned long dev_pm_opp_get_power (struct dev_pm_opp *opp);unsigned long dev_pm_opp_get_freq (struct dev_pm_opp *opp);
@@ -217,6 +219,11 @@ static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)return 0 ; } +static inline int dev_pm_opp_get_supplies (struct dev_pm_opp *opp,struct dev_pm_opp_supply *supplies) +{ +return -EOPNOTSUPP ; +} +static inline unsigned long dev_pm_opp_get_power (struct dev_pm_opp *opp) {return 0 ;
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 19/20 OPP: ti: Migrate to dev_pm_opp_set_config_regulators()
In reply to Viresh KumarThe OPP core now provides dev_pm_opp_set_config_regulators() interface, which needs the platforms to just set the OPP voltages instead of both clk and voltage. The clock is set by the OPP core instead and hence reduces code redundancy.
Migrate the only user of the custom set_opp() todev_pm_opp_set_config_regulators().
--- drivers/opp/ti-opp-supply.c | 75 +++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 41 deletions(-)
drivers/opp/ti-opp-supply.c +34 -41
@@ -36,11 +36,15 @@ struct ti_opp_supply_optimum_voltage_table {* @vdd_table: Optimized voltage mapping table * @num_vdd_table: number of entries in vdd_table * @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply +* @old_supplies: Placeholder for supplies information for old OPP. +* @new_supplies: Placeholder for supplies information for new OPP. */ struct ti_opp_supply_data {struct ti_opp_supply_optimum_voltage_table *vdd_table;u32 num_vdd_table;u32 vdd_absolute_max_voltage_uv; +struct dev_pm_opp_supply old_supplies[2 ]; +struct dev_pm_opp_supply new_supplies[2 ]; };static struct ti_opp_supply_data opp_data;
@@ -266,27 +270,32 @@ static int _opp_set_voltage(struct device *dev,return 0 ; } -/** -* ti_opp_supply_set_opp() - do the opp supply transition -* @data: information on regulators and new and old opps provided by -* opp core to use in transition -* -* Return: If successful, 0, else appropriate error value. -*/ -static int ti_opp_supply_set_opp (struct dev_pm_set_opp_data *data) +/* Do the opp supply transition */ +static int ti_opp_config_regulators (struct device *dev, +struct dev_pm_opp *old_opp,struct dev_pm_opp *new_opp, +struct regulator **regulators,unsigned int count) { -struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0 ]; -struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1 ]; -struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0 ]; -struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1 ]; -struct device *dev = data->dev; -unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; -struct clk *clk = data->clk; -struct regulator *vdd_reg = data->regulators[0 ]; -struct regulator *vbb_reg = data->regulators[1 ]; +struct dev_pm_opp_supply *old_supply_vdd = &opp_data.old_supplies[0 ]; +struct dev_pm_opp_supply *old_supply_vbb = &opp_data.old_supplies[1 ]; +struct dev_pm_opp_supply *new_supply_vdd = &opp_data.new_supplies[0 ]; +struct dev_pm_opp_supply *new_supply_vbb = &opp_data.new_supplies[1 ]; +struct regulator *vdd_reg = regulators[0 ]; +struct regulator *vbb_reg = regulators[1 ]; +unsigned long old_freq, freq;int vdd_uv;int ret; +/* We must have two regulators here */ +WARN_ON (count !=2 ); + +/* Fetch supplies and freq information from OPP core */ + ret =dev_pm_opp_get_supplies (new_opp, opp_data.new_supplies); +WARN_ON (ret); + + old_freq =dev_pm_opp_get_freq (old_opp); + freq =dev_pm_opp_get_freq (new_opp); +WARN_ON (!old_freq || !freq); + vdd_uv =_get_optimal_vdd_voltage (dev, &opp_data, new_supply_vdd->u_volt);
@@ -303,39 +312,24 @@ static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data) ret =_opp_set_voltage (dev, new_supply_vbb,0 , vbb_reg,"vbb" );if (ret) goto restore_voltage; - } - -/* Change frequency */ -dev_dbg (dev,"%s: switching OPP: %lu Hz --> %lu Hz\n" , - __func__, old_freq, freq); - - ret =clk_set_rate (clk, freq); -if (ret) { -dev_err (dev,"%s: failed to set clock rate: %d\n" , __func__, - ret); - goto restore_voltage; - } - -/* Scaling down? Scale voltage after frequency */ -if (freq < old_freq) { + }else { ret =_opp_set_voltage (dev, new_supply_vbb,0 , vbb_reg,"vbb" );if (ret) - goto restore_freq; + goto restore_voltage; ret =_opp_set_voltage (dev, new_supply_vdd, vdd_uv, vdd_reg,"vdd" );if (ret) - goto restore_freq; + goto restore_voltage; }return 0 ; -restore_freq: - ret =clk_set_rate (clk, old_freq); -if (ret) -dev_err (dev,"%s: failed to restore old-freq (%lu Hz)\n" , - __func__, old_freq); restore_voltage: +/* Fetch old supplies information only if required */ + ret =dev_pm_opp_get_supplies (old_opp, opp_data.old_supplies); +WARN_ON (ret); +/* This shouldn't harm even if the voltages weren't updated earlier */ if (old_supply_vdd->u_volt) { ret =_opp_set_voltage (dev, old_supply_vbb,0 , vbb_reg,"vbb" );
@@ -405,8 +399,7 @@ static int ti_opp_supply_probe(struct platform_device *pdev)return ret; } - ret =dev_pm_opp_register_set_opp_helper (cpu_dev, - ti_opp_supply_set_opp); + ret =dev_pm_opp_set_config_regulators (cpu_dev, ti_opp_config_regulators);if (ret <0 )_free_optimized_voltages (dev, &opp_data);
Signature · 1 line
2.31.1.272.g89b43f80a514
Viresh Kumar
maintainerPATCH v3 20/20 OPP: Remove custom OPP helper support
In reply to Viresh KumarThe only user of the custom helper is migrated to use dev_pm_opp_set_config_regulators() interface. Remove the now unused custom OPP helper support.
This cleans up _set_opp() and leaves a single code path to be used by all users.
--- drivers/opp/core.c | 132 +---------------------------------------- drivers/opp/opp.h | 7 --- include/linux/pm_opp.h | 51 ---------------- 3 files changed, 2 insertions(+), 188 deletions(-)
drivers/opp/core.c +2 -130
@@ -979,36 +979,6 @@ static int _set_opp_bw(const struct opp_table *opp_table,return 0 ; } -static int _set_opp_custom (const struct opp_table *opp_table, -struct device *dev,struct dev_pm_opp *opp, -unsigned long freq) -{ -struct dev_pm_set_opp_data *data = opp_table->set_opp_data; -struct dev_pm_opp *old_opp = opp_table->current_opp; -int size; - -/* -* We support this only if dev_pm_opp_set_config() was called -* earlier to set regulators. -*/ -if (opp_table->sod_supplies) { - size =sizeof (*old_opp->supplies) * opp_table->regulator_count; -memcpy (data->old_opp.supplies, old_opp->supplies, size); -memcpy (data->new_opp.supplies, opp->supplies, size); - data->regulator_count = opp_table->regulator_count; - }else { - data->regulator_count =0 ; - } - - data->regulators = opp_table->regulators; - data->clk = opp_table->clk; - data->dev = dev; - data->old_opp.rate = old_opp->rate; - data->new_opp.rate = freq; - -return opp_table->set_opp (data); -} -static int _set_required_opp (struct device *dev,struct device *pd_dev,struct dev_pm_opp *opp,int i) {
@@ -1195,13 +1165,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, } } -if (opp_table->set_opp) { - ret =_set_opp_custom (opp_table, dev, opp, freq); - }else { -/* Only frequency scaling */ - ret =_generic_set_opp_clk_only (dev, opp_table->clk, freq); - } - + ret =_generic_set_opp_clk_only (dev, opp_table->clk, freq);if (ret)return ret;
@@ -2065,7 +2029,6 @@ static void _opp_put_prop_name(struct opp_table *opp_table)static int _opp_set_regulators (struct opp_table *opp_table,struct device *dev,const char *const names[]) { -struct dev_pm_opp_supply *supplies;const char *const *temp = names;struct regulator *reg;int count =0 , ret, i;
@@ -2101,20 +2064,6 @@ static int _opp_set_regulators(struct opp_table *opp_table, struct device *dev, opp_table->regulator_count = count; - supplies =kmalloc_array (count *2 ,sizeof (*supplies),GFP_KERNEL ); -if (!supplies) { - ret = -ENOMEM ; - goto free_regulators; - } - -mutex_lock (&opp_table->lock); - opp_table->sod_supplies = supplies; -if (opp_table->set_opp_data) { - opp_table->set_opp_data->old_opp.supplies = supplies; - opp_table->set_opp_data->new_opp.supplies = supplies + count; - } -mutex_unlock (&opp_table->lock); -/* Set generic config_regulators() for single regulators here */ if (count ==1 ) opp_table->config_regulators = _opp_config_regulator_single;
@@ -2151,16 +2100,6 @@ static void _opp_put_regulators(struct opp_table *opp_table)for (i = opp_table->regulator_count -1 ; i >=0 ; i--)regulator_put (opp_table->regulators[i]); -mutex_lock (&opp_table->lock); -if (opp_table->set_opp_data) { - opp_table->set_opp_data->old_opp.supplies =NULL ; - opp_table->set_opp_data->new_opp.supplies =NULL ; - } - -kfree (opp_table->sod_supplies); - opp_table->sod_supplies =NULL ; -mutex_unlock (&opp_table->lock); -kfree (opp_table->regulators); opp_table->regulators =NULL ; opp_table->regulator_count =-1 ;
@@ -2233,61 +2172,6 @@ static void _opp_put_clknames(struct opp_table *opp_table) } } -/** -* _opp_register_set_opp_helper() - Register custom set OPP helper -* @dev: Device for which the helper is getting registered. -* @set_opp: Custom set OPP helper. -* -* This is useful to support complex platforms (like platforms with multiple -* regulators per device), instead of the generic OPP set rate helper. -* -* This must be called before any OPPs are initialized for the device. -*/ -static int _opp_register_set_opp_helper (struct opp_table *opp_table, -struct device *dev,int (*set_opp)(struct dev_pm_set_opp_data *data)) -{ -struct dev_pm_set_opp_data *data; - -/* Another CPU that shares the OPP table has set the helper ? */ -if (opp_table->set_opp) -return 0 ; - - data =kzalloc (sizeof (*data),GFP_KERNEL ); -if (!data) -return -ENOMEM ; - -mutex_lock (&opp_table->lock); - opp_table->set_opp_data = data; -if (opp_table->sod_supplies) { - data->old_opp.supplies = opp_table->sod_supplies; - data->new_opp.supplies = opp_table->sod_supplies + - opp_table->regulator_count; - } -mutex_unlock (&opp_table->lock); - - opp_table->set_opp = set_opp; - -return 0 ; -} - -/** -* _opp_unregister_set_opp_helper() - Releases resources blocked for set_opp helper -* @opp_table: OPP table returned from _opp_register_set_opp_helper(). -* -* Release resources blocked for platform specific set_opp helper. -*/ -static void _opp_unregister_set_opp_helper (struct opp_table *opp_table) -{ -if (opp_table->set_opp) { - opp_table->set_opp =NULL ; - -mutex_lock (&opp_table->lock); -kfree (opp_table->set_opp_data); - opp_table->set_opp_data =NULL ; -mutex_unlock (&opp_table->lock); - } -} -/** * _opp_set_config_regulators_helper() - Register custom set regulator helper. * @dev: Device for which the helper is getting registered.
@@ -2446,10 +2330,8 @@ static void _opp_clear_config(struct opp_config_data *data)_opp_put_regulators (data->opp_table);if (data->flags &OPP_CONFIG_SUPPORTED_HW )_opp_put_supported_hw (data->opp_table); -if (data->flags &OPP_CONFIG_REGULATOR_HELPER ) { +if (data->flags &OPP_CONFIG_REGULATOR_HELPER )_opp_put_config_regulators_helper (data->opp_table); -_opp_unregister_set_opp_helper (data->opp_table); - }if (data->flags &OPP_CONFIG_PROP_NAME )_opp_put_prop_name (data->opp_table);if (data->flags &OPP_CONFIG_CLK )
@@ -2520,16 +2402,6 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config) data->flags |=OPP_CONFIG_PROP_NAME ; } -/* Configure opp helper */ -if (config->set_opp) { - ret =_opp_register_set_opp_helper (opp_table, dev, - config->set_opp); -if (ret) - goto err; - - data->flags |=OPP_CONFIG_REGULATOR_HELPER ; - } -/* Configure config_regulators helper */ if (config->config_regulators) { ret = _opp_set_config_regulators_helper(opp_table, dev,
drivers/opp/opp.h +0 -7
@@ -182,9 +182,6 @@ enum opp_table_access {* @enabled: Set to true if the device's resources are enabled/configured. * @genpd_performance_state: Device's power domain support performance state. * @is_genpd: Marks if the OPP table belongs to a genpd. -* @set_opp: Platform specific set_opp callback -* @sod_supplies: Set opp data supplies -* @set_opp_data: Data to be passed to set_opp callback * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. *
@@ -234,10 +231,6 @@ struct opp_table {bool genpd_performance_state;bool is_genpd; -int (*set_opp)(struct dev_pm_set_opp_data *data); -struct dev_pm_opp_supply *sod_supplies; -struct dev_pm_set_opp_data *set_opp_data; -#ifdef CONFIG_DEBUG_FS struct dentry *dentry;char dentry_name[NAME_MAX ];
include/linux/pm_opp.h +0 -51
75 lines not on this page · raw message
Signature · 1 line
2.31.1.272.g89b43f80a514