Skip to content

Commit

Permalink
PM wip
Browse files Browse the repository at this point in the history
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
  • Loading branch information
krzk committed Apr 5, 2022
1 parent 4718d53 commit 9262291
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 41 deletions.
145 changes: 106 additions & 39 deletions drivers/opp/core.c
Expand Up @@ -66,6 +66,21 @@ static struct opp_table *_find_opp_table_unlocked(struct device *dev)
return ERR_PTR(-ENODEV);
}

static void _put_clocks(struct opp_table *opp_table)
{
int i;

if (!opp_table->clks)
return;

for (i = opp_table->clk_count - 1; i >= 0; i--)
clk_put(opp_table->clks[i]);

kfree(opp_table->clks);
opp_table->clks = NULL;
opp_table->clk_count = -1;
};

/**
* _find_opp_table() - find opp_table struct using device pointer
* @dev: device pointer used to lookup OPP table
Expand Down Expand Up @@ -796,7 +811,7 @@ static int _generic_set_opp_regulator(struct opp_table *opp_table,
}

/* Change frequency */
ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
ret = _generic_set_opp_clk_only(dev, opp_table->clks[0], freq);
if (ret)
goto restore_voltage;

Expand All @@ -820,7 +835,7 @@ static int _generic_set_opp_regulator(struct opp_table *opp_table,
return 0;

restore_freq:
if (_generic_set_opp_clk_only(dev, opp_table->clk, old_opp->rate))
if (_generic_set_opp_clk_only(dev, opp_table->clks[0], old_opp->rate))
dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
__func__, old_opp->rate);
restore_voltage:
Expand Down Expand Up @@ -880,7 +895,7 @@ static int _set_opp_custom(const struct opp_table *opp_table,
}

data->regulators = opp_table->regulators;
data->clk = opp_table->clk;
data->clk = opp_table->clks[0];
data->dev = dev;
data->old_opp.rate = old_opp->rate;
data->new_opp.rate = freq;
Expand Down Expand Up @@ -969,8 +984,8 @@ static void _find_current_opp(struct device *dev, struct opp_table *opp_table)
struct dev_pm_opp *opp = ERR_PTR(-ENODEV);
unsigned long freq;

if (!IS_ERR(opp_table->clk)) {
freq = clk_get_rate(opp_table->clk);
if (!IS_ERR(opp_table->clks[0])) {
freq = clk_get_rate(opp_table->clks[0]);
opp = _find_freq_ceil(opp_table, &freq);
}

Expand Down Expand Up @@ -1070,7 +1085,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
scaling_down);
} else {
/* Only frequency scaling */
ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
ret = _generic_set_opp_clk_only(dev, opp_table->clks[0], freq);
}

if (ret)
Expand Down Expand Up @@ -1135,11 +1150,11 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
* equivalent to a clk_set_rate()
*/
if (!_get_opp_count(opp_table)) {
ret = _generic_set_opp_clk_only(dev, opp_table->clk, target_freq);
ret = _generic_set_opp_clk_only(dev, opp_table->clks[0], target_freq);
goto put_opp_table;
}

freq = clk_round_rate(opp_table->clk, target_freq);
freq = clk_round_rate(opp_table->clks[0], target_freq);
if ((long)freq <= 0)
freq = target_freq;

Expand Down Expand Up @@ -1247,7 +1262,8 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index,
INIT_LIST_HEAD(&opp_table->dev_list);
INIT_LIST_HEAD(&opp_table->lazy);

/* Mark regulator count uninitialized */
/* Mark regulator/clk count uninitialized */
opp_table->clk_count = -1;
opp_table->regulator_count = -1;
opp_table->version = version;

Expand Down Expand Up @@ -1297,21 +1313,33 @@ static struct opp_table *_update_opp_table_clk(struct device *dev,
* Return early if we don't need to get clk or we have already tried it
* earlier.
*/
if (!getclk || IS_ERR(opp_table) || opp_table->clk)
if (!getclk || IS_ERR(opp_table) || opp_table->clks)
return opp_table;

opp_table->clks = kmalloc_array(1, sizeof(*opp_table->clks),
GFP_KERNEL);
if (!opp_table->clks)
return ERR_PTR(-ENOMEM);

/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
opp_table->clks[0] = clk_get(dev, NULL);

ret = PTR_ERR_OR_ZERO(opp_table->clk);
if (!ret)
ret = PTR_ERR_OR_ZERO(opp_table->clks[0]);
if (!ret) {
WARN_ON(1);
opp_table->clk_count = 1;
return opp_table;
}

if (ret == -ENOENT) {
opp_table->clk_count = 0;
dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
return opp_table;
}

kfree(opp_table->clks);
opp_table->clks = NULL;
opp_table->clk_count = -1;
dev_pm_opp_put_opp_table(opp_table);
dev_err_probe(dev, ret, "Couldn't find clock\n");

Expand Down Expand Up @@ -1412,9 +1440,7 @@ static void _opp_table_kref_release(struct kref *kref)

_of_clear_opp_table(opp_table);

/* Release clk */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
_put_clocks(opp_table);

if (opp_table->paths) {
for (i = 0; i < opp_table->path_count; i++)
Expand Down Expand Up @@ -2155,11 +2181,35 @@ EXPORT_SYMBOL_GPL(devm_pm_opp_set_regulators);
* 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)
{
return dev_pm_opp_set_clknames(dev, &name, 1);
}
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)
{
return dev_pm_opp_put_clknames(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);
}

struct opp_table *dev_pm_opp_set_clknames(struct device *dev,
const char * const names[],
unsigned int count)
{
struct opp_table *opp_table;
int ret;
struct clk *clk;
int ret, i;

opp_table = _add_opp_table(dev, false, OPP_TABLE_VERSION_UNKNOWN);
opp_table = _add_opp_table(dev, false, OPP_TABLE_VERSION_2);
if (IS_ERR(opp_table))
return opp_table;

Expand All @@ -2170,48 +2220,64 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
}

/* clk shouldn't be initialized at this point */
if (WARN_ON(opp_table->clk)) {
if (WARN_ON(opp_table->clks)) {
ret = -EBUSY;
goto err;
}

/* Find clk for the device */
opp_table->clk = clk_get(dev, name);
if (IS_ERR(opp_table->clk)) {
ret = dev_err_probe(dev, PTR_ERR(opp_table->clk),
"%s: Couldn't find clock\n", __func__);
if (!names) {

}
opp_table->clks = kmalloc_array(count, sizeof(*opp_table->clks),
GFP_KERNEL);
if (!opp_table->clks) {
ret = -ENOMEM;
goto err;
}

for (i = 0; i < count; i++) {
clk = clk_get(dev, names[i]);
if (IS_ERR(clk)) {
ret = dev_err_probe(dev, PTR_ERR(clk),
"%s: Couldn't find clock %s\n",
__func__, names[i]);
goto free_clks;
}
pr_err("AAA getting clock %s=%px\n", names[i], clk);

opp_table->clks[i] = clk;
}

pr_err("AAA %s:%d - read %s - %d clocks (count %d)\n", __func__, __LINE__,
of_node_full_name(np), count, opp_table->clk_count);
opp_table->clk_count = count;

return opp_table;

free_clks:
while (i != 0)
clk_put(opp_table->clks[--i]);

kfree(opp_table->clks);
opp_table->clks = NULL;
opp_table->clk_count = -1;
err:
dev_pm_opp_put_opp_table(opp_table);

return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_clkname);
EXPORT_SYMBOL_GPL(dev_pm_opp_set_clknames);

/**
* 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)
void dev_pm_opp_put_clknames(struct opp_table *opp_table)
{
if (unlikely(!opp_table))
return;

clk_put(opp_table->clk);
opp_table->clk = ERR_PTR(-EINVAL);
_put_clocks(opp_table);

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);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_clknames);

/**
* devm_pm_opp_set_clkname() - Set clk name for the device
Expand Down Expand Up @@ -2648,7 +2714,8 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);

/* Fix regulator count for dynamic OPPs */
/* Fix regulator/clk count for dynamic OPPs */
opp_table->clk_count = 1;
opp_table->regulator_count = 1;

ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
Expand Down
48 changes: 47 additions & 1 deletion drivers/opp/of.c
Expand Up @@ -771,6 +771,43 @@ void dev_pm_opp_of_remove_table(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);

static int _read_clocks(struct dev_pm_opp *opp, struct opp_table *opp_table,
struct device_node *np)
{
int count, ret;
u64 *freq;

count = of_property_count_u64_elems(np, "opp-hz");
if (count < 0) {
pr_err("%s: Invalid %s property (%d)\n",
__func__, of_node_full_name(np), count);
return count;
}

freq = kmalloc_array(count, sizeof(*freq), GFP_KERNEL);
if (!freq)
return -ENOMEM;

ret = of_property_read_u64_array(np, "opp-hz", freq, count);
if (ret) {
pr_err("%s: error parsing %s: %d\n", __func__,
of_node_full_name(np), ret);
ret = -EINVAL;
goto free_freq;
}

pr_err("AAA %s:%d - read %s - %d clocks (count %d)\n", __func__, __LINE__,
of_node_full_name(np), count, opp_table->clk_count);

opp->rates = freq;
return 0;

free_freq:
kfree(freq);

return ret;
}

static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
struct device_node *np, bool peak)
{
Expand Down Expand Up @@ -820,6 +857,8 @@ static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
int ret;

ret = of_property_read_u64(np, "opp-hz", &rate);
pr_err("AAA %s:%d - read rate %s - %llu\n", __func__, __LINE__,
of_node_full_name(np), rate);
if (!ret) {
/*
* Rate is defined as an unsigned long in clk API, and so
Expand All @@ -831,6 +870,13 @@ static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
}
*rate_not_available = !!ret;

if (!ret) {
ret = _read_clocks(new_opp, table, np);
/* The properties were found but we failed to parse them */
if (ret && ret != -ENODEV)
return ret;
}

/*
* Bandwidth consists of peak and average (optional) values:
* opp-peak-kBps = <path1_value path2_value>;
Expand Down Expand Up @@ -996,7 +1042,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
opp_table->parsed_static_opps = 1;
mutex_unlock(&opp_table->lock);

WARN_ON(opp_table->version != OPP_TABLE_VERSION_UNKNOWN);
//WARN_ON(opp_table->version != OPP_TABLE_VERSION_UNKNOWN);
opp_table->version = OPP_TABLE_VERSION_2;

/* We have opp-table node now, iterate over it and add OPPs */
Expand Down
4 changes: 3 additions & 1 deletion drivers/opp/opp.h
Expand Up @@ -84,6 +84,7 @@ struct dev_pm_opp {
unsigned long rate;
unsigned int level;

u64 *rates;
struct dev_pm_opp_supply *supplies;
struct dev_pm_opp_icc_bw *bandwidth;

Expand Down Expand Up @@ -208,7 +209,8 @@ struct opp_table {
unsigned int *supported_hw;
unsigned int supported_hw_count;
const char *prop_name;
struct clk *clk;
struct clk **clks;
int clk_count;
struct regulator **regulators;
int regulator_count;
struct icc_path **paths;
Expand Down

0 comments on commit 9262291

Please sign in to comment.