summaryrefslogtreecommitdiff
path: root/drivers/opp/of.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2018-06-26 16:29:34 +0530
committerViresh Kumar <viresh.kumar@linaro.org>2018-11-05 07:40:43 +0530
commit4f018bc0e1cfdec2e25072db9fecc1f363ba79ea (patch)
tree7c6552851a12015f8f598f865fb891240d331f1c /drivers/opp/of.c
parente38f89d310fcc543b0b94594a92db1d6cfbd9376 (diff)
OPP: Add dev_pm_opp_{set|put}_genpd_virt_dev() helper
Multiple generic power domains for a consumer device are supported with the help of virtual devices, which are created for each consumer device - genpd pair. These are the device structures which are attached to the power domain and are required by the OPP core to set the performance state of the genpd. The helpers added by this commit are required to be called once for each of these virtual devices. These are required only if multiple domains are available for a device, otherwise the actual device structure will be used instead by the OPP core. The new helpers also support the complex cases where the consumer device wouldn't always require all the domains. For example, a camera may require only one power domain during normal operations but two during high resolution operations. The consumer driver can call dev_pm_opp_put_genpd_virt_dev(high_resolution_genpd_virt_dev) if it is currently operating in the normal mode and doesn't have any performance requirements from the genpd which manages high resolution power requirements. The consumer driver can later call dev_pm_opp_set_genpd_virt_dev(high_resolution_genpd_virt_dev) once it switches back to the high resolution mode. The new helpers differ from other OPP set/put helpers as the new ones can be called with OPPs initialized for the table as we may need to call them on the fly because of the complex case explained above. For this reason it is possible that the genpd virt_dev structure may be used in parallel while the new helpers are running and a new mutex is added to protect against that. We didn't use the existing opp_table->lock mutex as that is widely used in the OPP core and we will need this lock in the dev_pm_opp_set_rate() helper while changing OPP and we need to make sure there is not much contention while doing that as that's the hotpath. Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Diffstat (limited to 'drivers/opp/of.c')
-rw-r--r--drivers/opp/of.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index ffaeefef98ce..71aef28953c2 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -134,6 +134,7 @@ static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
static void _opp_table_free_required_tables(struct opp_table *opp_table)
{
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
+ struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
int i;
if (!required_opp_tables)
@@ -147,8 +148,10 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table)
}
kfree(required_opp_tables);
+ kfree(genpd_virt_devs);
opp_table->required_opp_count = 0;
+ opp_table->genpd_virt_devs = NULL;
opp_table->required_opp_tables = NULL;
}
@@ -161,6 +164,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
struct device_node *opp_np)
{
struct opp_table **required_opp_tables;
+ struct device **genpd_virt_devs = NULL;
struct device_node *required_np, *np;
int count, i;
@@ -175,11 +179,21 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
if (!count)
goto put_np;
+ if (count > 1) {
+ genpd_virt_devs = kcalloc(count, sizeof(*genpd_virt_devs),
+ GFP_KERNEL);
+ if (!genpd_virt_devs)
+ goto put_np;
+ }
+
required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
GFP_KERNEL);
- if (!required_opp_tables)
+ if (!required_opp_tables) {
+ kfree(genpd_virt_devs);
goto put_np;
+ }
+ opp_table->genpd_virt_devs = genpd_virt_devs;
opp_table->required_opp_tables = required_opp_tables;
opp_table->required_opp_count = count;