opp: Add support for parsing interconnect bandwidth
The OPP bindings now support bandwidth values, so add support to parse it from device tree and store it into the new dev_pm_opp_icc_bw struct, which is part of the dev_pm_opp. Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org> Reviewed-by: Matthias Kaehlcke <mka@chromium.org> [ Viresh: Create _read_bw() and use it, renamed _of_find_icc_paths() to dev_pm_opp_of_find_icc_paths(), exported it and made opp_table argument optional. Also drop the depends on from Kconfig. ] Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:

committed by
Viresh Kumar

parent
90562c8182
commit
6d3f922c46
114
drivers/opp/of.c
114
drivers/opp/of.c
@@ -332,6 +332,62 @@ free_required_opps:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_pm_opp_of_find_icc_paths(struct device *dev,
|
||||
struct opp_table *opp_table)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret = 0, i, count, num_paths;
|
||||
struct icc_path **paths;
|
||||
|
||||
np = of_node_get(dev->of_node);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
count = of_count_phandle_with_args(np, "interconnects",
|
||||
"#interconnect-cells");
|
||||
of_node_put(np);
|
||||
if (count < 0)
|
||||
return 0;
|
||||
|
||||
/* two phandles when #interconnect-cells = <1> */
|
||||
if (count % 2) {
|
||||
dev_err(dev, "%s: Invalid interconnects values\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_paths = count / 2;
|
||||
paths = kcalloc(num_paths, sizeof(*paths), GFP_KERNEL);
|
||||
if (!paths)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_paths; i++) {
|
||||
paths[i] = of_icc_get_by_index(dev, i);
|
||||
if (IS_ERR(paths[i])) {
|
||||
ret = PTR_ERR(paths[i]);
|
||||
if (ret != -EPROBE_DEFER) {
|
||||
dev_err(dev, "%s: Unable to get path%d: %d\n",
|
||||
__func__, i, ret);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (opp_table) {
|
||||
opp_table->paths = paths;
|
||||
opp_table->path_count = num_paths;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err:
|
||||
while (i--)
|
||||
icc_put(paths[i]);
|
||||
|
||||
kfree(paths);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_find_icc_paths);
|
||||
|
||||
static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
|
||||
struct device_node *np)
|
||||
{
|
||||
@@ -521,9 +577,45 @@ void dev_pm_opp_of_remove_table(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
|
||||
|
||||
static int _read_bw(struct dev_pm_opp *new_opp, struct device_node *np,
|
||||
bool peak)
|
||||
{
|
||||
const char *name = peak ? "opp-peak-kBps" : "opp-avg-kBps";
|
||||
struct property *prop;
|
||||
int i, count, ret;
|
||||
u32 *bw;
|
||||
|
||||
prop = of_find_property(np, name, NULL);
|
||||
if (!prop)
|
||||
return -ENODEV;
|
||||
|
||||
count = prop->length / sizeof(u32);
|
||||
bw = kmalloc_array(count, sizeof(*bw), GFP_KERNEL);
|
||||
if (!bw)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32_array(np, name, bw, count);
|
||||
if (ret) {
|
||||
pr_err("%s: Error parsing %s: %d\n", __func__, name, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (peak)
|
||||
new_opp->bandwidth[i].peak = kBps_to_icc(bw[i]);
|
||||
else
|
||||
new_opp->bandwidth[i].avg = kBps_to_icc(bw[i]);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(bw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _read_opp_key(struct dev_pm_opp *new_opp, struct device_node *np,
|
||||
bool *rate_not_available)
|
||||
{
|
||||
bool found = false;
|
||||
u64 rate;
|
||||
int ret;
|
||||
|
||||
@@ -535,10 +627,30 @@ static int _read_opp_key(struct dev_pm_opp *new_opp, struct device_node *np,
|
||||
* bit guaranteed in clk API.
|
||||
*/
|
||||
new_opp->rate = (unsigned long)rate;
|
||||
found = true;
|
||||
}
|
||||
*rate_not_available = !!ret;
|
||||
|
||||
of_property_read_u32(np, "opp-level", &new_opp->level);
|
||||
/*
|
||||
* Bandwidth consists of peak and average (optional) values:
|
||||
* opp-peak-kBps = <path1_value path2_value>;
|
||||
* opp-avg-kBps = <path1_value path2_value>;
|
||||
*/
|
||||
ret = _read_bw(new_opp, np, true);
|
||||
if (!ret) {
|
||||
found = true;
|
||||
ret = _read_bw(new_opp, np, false);
|
||||
}
|
||||
|
||||
/* The properties were found but we failed to parse them */
|
||||
if (ret && ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
if (!of_property_read_u32(np, "opp-level", &new_opp->level))
|
||||
found = true;
|
||||
|
||||
if (found)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user