summaryrefslogtreecommitdiffstats
path: root/drivers/opp
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2018-04-06 05:05:45 -0400
committerViresh Kumar <viresh.kumar@linaro.org>2018-05-09 00:45:18 -0400
commita1e8c13600bfd96c51580732ccf31f69bc6de4d1 (patch)
tree42bf4de0062d62d7468d8a620d669721cc33108e /drivers/opp
parentb89469bdf0c2025a1c1f6ce2b841cb8abe589688 (diff)
PM / OPP: "opp-hz" is optional for power domains
"opp-hz" property is optional for power domains now and we shouldn't error out if it is missing for power domains. This patch creates two new routines, _get_opp_count() and _opp_is_duplicate(), by separating existing code from their parent functions. Also skip duplicate OPP check for power domain OPPs as they may not have any the "opp-hz" field, but a platform specific performance state binding to uniquely identify OPP nodes. By default the debugfs OPP nodes are named using the "rate" value, but that isn't possible for the power domain OPP nodes and hence they use the index of the OPP node in the OPP node list instead. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/opp')
-rw-r--r--drivers/opp/core.c92
-rw-r--r--drivers/opp/debugfs.c15
-rw-r--r--drivers/opp/of.c26
-rw-r--r--drivers/opp/opp.h3
4 files changed, 89 insertions, 47 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 92fa94a6dcc1..a0f72c732718 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -281,6 +281,23 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
281} 281}
282EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); 282EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
283 283
284int _get_opp_count(struct opp_table *opp_table)
285{
286 struct dev_pm_opp *opp;
287 int count = 0;
288
289 mutex_lock(&opp_table->lock);
290
291 list_for_each_entry(opp, &opp_table->opp_list, node) {
292 if (opp->available)
293 count++;
294 }
295
296 mutex_unlock(&opp_table->lock);
297
298 return count;
299}
300
284/** 301/**
285 * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table 302 * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
286 * @dev: device for which we do this operation 303 * @dev: device for which we do this operation
@@ -291,25 +308,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
291int dev_pm_opp_get_opp_count(struct device *dev) 308int dev_pm_opp_get_opp_count(struct device *dev)
292{ 309{
293 struct opp_table *opp_table; 310 struct opp_table *opp_table;
294 struct dev_pm_opp *temp_opp; 311 int count;
295 int count = 0;
296 312
297 opp_table = _find_opp_table(dev); 313 opp_table = _find_opp_table(dev);
298 if (IS_ERR(opp_table)) { 314 if (IS_ERR(opp_table)) {
299 count = PTR_ERR(opp_table); 315 count = PTR_ERR(opp_table);
300 dev_dbg(dev, "%s: OPP table not found (%d)\n", 316 dev_dbg(dev, "%s: OPP table not found (%d)\n",
301 __func__, count); 317 __func__, count);
302 return count; 318 return 0;
303 }
304
305 mutex_lock(&opp_table->lock);
306
307 list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
308 if (temp_opp->available)
309 count++;
310 } 319 }
311 320
312 mutex_unlock(&opp_table->lock); 321 count = _get_opp_count(opp_table);
313 dev_pm_opp_put_opp_table(opp_table); 322 dev_pm_opp_put_opp_table(opp_table);
314 323
315 return count; 324 return count;
@@ -985,22 +994,11 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
985 return true; 994 return true;
986} 995}
987 996
988/* 997static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
989 * Returns: 998 struct opp_table *opp_table,
990 * 0: On success. And appropriate error message for duplicate OPPs. 999 struct list_head **head)
991 * -EBUSY: For OPP with same freq/volt and is available. The callers of
992 * _opp_add() must return 0 if they receive -EBUSY from it. This is to make
993 * sure we don't print error messages unnecessarily if different parts of
994 * kernel try to initialize the OPP table.
995 * -EEXIST: For OPP with same freq but different volt or is unavailable. This
996 * should be considered an error by the callers of _opp_add().
997 */
998int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
999 struct opp_table *opp_table)
1000{ 1000{
1001 struct dev_pm_opp *opp; 1001 struct dev_pm_opp *opp;
1002 struct list_head *head;
1003 int ret;
1004 1002
1005 /* 1003 /*
1006 * Insert new OPP in order of increasing frequency and discard if 1004 * Insert new OPP in order of increasing frequency and discard if
@@ -1010,17 +1008,14 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
1010 * loop, don't replace it with head otherwise it will become an infinite 1008 * loop, don't replace it with head otherwise it will become an infinite
1011 * loop. 1009 * loop.
1012 */ 1010 */
1013 mutex_lock(&opp_table->lock);
1014 head = &opp_table->opp_list;
1015
1016 list_for_each_entry(opp, &opp_table->opp_list, node) { 1011 list_for_each_entry(opp, &opp_table->opp_list, node) {
1017 if (new_opp->rate > opp->rate) { 1012 if (new_opp->rate > opp->rate) {
1018 head = &opp->node; 1013 *head = &opp->node;
1019 continue; 1014 continue;
1020 } 1015 }
1021 1016
1022 if (new_opp->rate < opp->rate) 1017 if (new_opp->rate < opp->rate)
1023 break; 1018 return 0;
1024 1019
1025 /* Duplicate OPPs */ 1020 /* Duplicate OPPs */
1026 dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", 1021 dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
@@ -1029,11 +1024,38 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
1029 new_opp->supplies[0].u_volt, new_opp->available); 1024 new_opp->supplies[0].u_volt, new_opp->available);
1030 1025
1031 /* Should we compare voltages for all regulators here ? */ 1026 /* Should we compare voltages for all regulators here ? */
1032 ret = opp->available && 1027 return opp->available &&
1033 new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST; 1028 new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST;
1029 }
1030
1031 return 0;
1032}
1033
1034/*
1035 * Returns:
1036 * 0: On success. And appropriate error message for duplicate OPPs.
1037 * -EBUSY: For OPP with same freq/volt and is available. The callers of
1038 * _opp_add() must return 0 if they receive -EBUSY from it. This is to make
1039 * sure we don't print error messages unnecessarily if different parts of
1040 * kernel try to initialize the OPP table.
1041 * -EEXIST: For OPP with same freq but different volt or is unavailable. This
1042 * should be considered an error by the callers of _opp_add().
1043 */
1044int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
1045 struct opp_table *opp_table, bool rate_not_available)
1046{
1047 struct list_head *head;
1048 int ret;
1049
1050 mutex_lock(&opp_table->lock);
1051 head = &opp_table->opp_list;
1034 1052
1035 mutex_unlock(&opp_table->lock); 1053 if (likely(!rate_not_available)) {
1036 return ret; 1054 ret = _opp_is_duplicate(dev, new_opp, opp_table, &head);
1055 if (ret) {
1056 mutex_unlock(&opp_table->lock);
1057 return ret;
1058 }
1037 } 1059 }
1038 1060
1039 if (opp_table->get_pstate) 1061 if (opp_table->get_pstate)
@@ -1104,7 +1126,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
1104 new_opp->available = true; 1126 new_opp->available = true;
1105 new_opp->dynamic = dynamic; 1127 new_opp->dynamic = dynamic;
1106 1128
1107 ret = _opp_add(dev, new_opp, opp_table); 1129 ret = _opp_add(dev, new_opp, opp_table, false);
1108 if (ret) { 1130 if (ret) {
1109 /* Don't return error for duplicate OPPs */ 1131 /* Don't return error for duplicate OPPs */
1110 if (ret == -EBUSY) 1132 if (ret == -EBUSY)
diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c
index b03c03576a62..e6828e5f81b0 100644
--- a/drivers/opp/debugfs.c
+++ b/drivers/opp/debugfs.c
@@ -77,10 +77,21 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
77{ 77{
78 struct dentry *pdentry = opp_table->dentry; 78 struct dentry *pdentry = opp_table->dentry;
79 struct dentry *d; 79 struct dentry *d;
80 unsigned long id;
80 char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ 81 char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */
81 82
82 /* Rate is unique to each OPP, use it to give opp-name */ 83 /*
83 snprintf(name, sizeof(name), "opp:%lu", opp->rate); 84 * Get directory name for OPP.
85 *
86 * - Normally rate is unique to each OPP, use it to get unique opp-name.
87 * - For some devices rate isn't available, use index instead.
88 */
89 if (likely(opp->rate))
90 id = opp->rate;
91 else
92 id = _get_opp_count(opp_table);
93
94 snprintf(name, sizeof(name), "opp:%lu", id);
84 95
85 /* Create per-opp directory */ 96 /* Create per-opp directory */
86 d = debugfs_create_dir(name, pdentry); 97 d = debugfs_create_dir(name, pdentry);
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index cb716aa2f44b..c5c5afcaa2e3 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -292,6 +292,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
292 u64 rate; 292 u64 rate;
293 u32 val; 293 u32 val;
294 int ret; 294 int ret;
295 bool rate_not_available = false;
295 296
296 new_opp = _opp_allocate(opp_table); 297 new_opp = _opp_allocate(opp_table);
297 if (!new_opp) 298 if (!new_opp)
@@ -299,8 +300,21 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
299 300
300 ret = of_property_read_u64(np, "opp-hz", &rate); 301 ret = of_property_read_u64(np, "opp-hz", &rate);
301 if (ret < 0) { 302 if (ret < 0) {
302 dev_err(dev, "%s: opp-hz not found\n", __func__); 303 /* "opp-hz" is optional for devices like power domains. */
303 goto free_opp; 304 if (!of_find_property(dev->of_node, "#power-domain-cells",
305 NULL)) {
306 dev_err(dev, "%s: opp-hz not found\n", __func__);
307 goto free_opp;
308 }
309
310 rate_not_available = true;
311 } else {
312 /*
313 * Rate is defined as an unsigned long in clk API, and so
314 * casting explicitly to its type. Must be fixed once rate is 64
315 * bit guaranteed in clk API.
316 */
317 new_opp->rate = (unsigned long)rate;
304 } 318 }
305 319
306 /* Check if the OPP supports hardware's hierarchy of versions or not */ 320 /* Check if the OPP supports hardware's hierarchy of versions or not */
@@ -309,12 +323,6 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
309 goto free_opp; 323 goto free_opp;
310 } 324 }
311 325
312 /*
313 * Rate is defined as an unsigned long in clk API, and so casting
314 * explicitly to its type. Must be fixed once rate is 64 bit
315 * guaranteed in clk API.
316 */
317 new_opp->rate = (unsigned long)rate;
318 new_opp->turbo = of_property_read_bool(np, "turbo-mode"); 326 new_opp->turbo = of_property_read_bool(np, "turbo-mode");
319 327
320 new_opp->np = np; 328 new_opp->np = np;
@@ -328,7 +336,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
328 if (ret) 336 if (ret)
329 goto free_opp; 337 goto free_opp;
330 338
331 ret = _opp_add(dev, new_opp, opp_table); 339 ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
332 if (ret) { 340 if (ret) {
333 /* Don't return error for duplicate OPPs */ 341 /* Don't return error for duplicate OPPs */
334 if (ret == -EBUSY) 342 if (ret == -EBUSY)
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 4d00061648a3..381a4fb15d5c 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -188,13 +188,14 @@ struct opp_table {
188 188
189/* Routines internal to opp core */ 189/* Routines internal to opp core */
190void _get_opp_table_kref(struct opp_table *opp_table); 190void _get_opp_table_kref(struct opp_table *opp_table);
191int _get_opp_count(struct opp_table *opp_table);
191struct opp_table *_find_opp_table(struct device *dev); 192struct opp_table *_find_opp_table(struct device *dev);
192struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); 193struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
193void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all); 194void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all);
194void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all); 195void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all);
195struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); 196struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
196void _opp_free(struct dev_pm_opp *opp); 197void _opp_free(struct dev_pm_opp *opp);
197int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); 198int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
198int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); 199int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
199void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); 200void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
200struct opp_table *_add_opp_table(struct device *dev); 201struct opp_table *_add_opp_table(struct device *dev);