Skip to content

Commit 71472c0

Browse files
James HoganMike Turquette
authored andcommitted
clk: add support for clock reparent on set_rate
Add core support to allow clock implementations to select the best parent clock when rounding a rate, e.g. the one which can provide the closest clock rate to that requested. This is by way of adding a new clock op, determine_rate(), which is like round_rate() but has an extra parameter to allow the clock implementation to optionally select a different parent clock. The core then takes care of reparenting the clock when setting the rate. The parent change takes place with the help of some new private data members. struct clk::new_parent specifies a clock's new parent (NULL indicates no change), and struct clk::new_child specifies a clock's new child (whose new_parent member points back to it). The purpose of these are to allow correct walking of the future tree for notifications prior to actually reparenting any clocks, specifically to skip child clocks who are being reparented to another clock (they will be notified via the new parent), and to include any new child clock. These pointers are set by clk_calc_subtree(), and the new_child pointer gets cleared when a child is actually reparented to avoid duplicate POST_RATE_CHANGE notifications. Each place where round_rate() is called, determine_rate() is checked first and called in preference. This restructures a few of the call sites to simplify the logic into if/else blocks. Signed-off-by: James Hogan <james.hogan@imgtec.com> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Cc: Mike Turquette <mturquette@linaro.org> Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Mike Turquette <mturquette@linaro.org>
1 parent 4935b22 commit 71472c0

File tree

4 files changed

+132
-66
lines changed

4 files changed

+132
-66
lines changed

Documentation/clk.txt

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ the operations defined in clk.h:
7070
unsigned long parent_rate);
7171
long (*round_rate)(struct clk_hw *hw, unsigned long,
7272
unsigned long *);
73+
long (*determine_rate)(struct clk_hw *hw,
74+
unsigned long rate,
75+
unsigned long *best_parent_rate,
76+
struct clk **best_parent_clk);
7377
int (*set_parent)(struct clk_hw *hw, u8 index);
7478
u8 (*get_parent)(struct clk_hw *hw);
7579
int (*set_rate)(struct clk_hw *hw, unsigned long);
@@ -179,26 +183,28 @@ mandatory, a cell marked as "n" implies that either including that
179183
callback is invalid or otherwise unnecessary. Empty cells are either
180184
optional or must be evaluated on a case-by-case basis.
181185

182-
clock hardware characteristics
183-
-----------------------------------------------------------
184-
| gate | change rate | single parent | multiplexer | root |
185-
|------|-------------|---------------|-------------|------|
186-
.prepare | | | | | |
187-
.unprepare | | | | | |
188-
| | | | | |
189-
.enable | y | | | | |
190-
.disable | y | | | | |
191-
.is_enabled | y | | | | |
192-
| | | | | |
193-
.recalc_rate | | y | | | |
194-
.round_rate | | y | | | |
195-
.set_rate | | y | | | |
196-
| | | | | |
197-
.set_parent | | | n | y | n |
198-
.get_parent | | | n | y | n |
199-
| | | | | |
200-
.init | | | | | |
201-
-----------------------------------------------------------
186+
clock hardware characteristics
187+
-----------------------------------------------------------
188+
| gate | change rate | single parent | multiplexer | root |
189+
|------|-------------|---------------|-------------|------|
190+
.prepare | | | | | |
191+
.unprepare | | | | | |
192+
| | | | | |
193+
.enable | y | | | | |
194+
.disable | y | | | | |
195+
.is_enabled | y | | | | |
196+
| | | | | |
197+
.recalc_rate | | y | | | |
198+
.round_rate | | y [1] | | | |
199+
.determine_rate | | y [1] | | | |
200+
.set_rate | | y | | | |
201+
| | | | | |
202+
.set_parent | | | n | y | n |
203+
.get_parent | | | n | y | n |
204+
| | | | | |
205+
.init | | | | | |
206+
-----------------------------------------------------------
207+
[1] either one of round_rate or determine_rate is required.
202208

203209
Finally, register your clock at run-time with a hardware-specific
204210
registration function. This function simply populates struct clk_foo's

drivers/clk/clk.c

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -889,21 +889,24 @@ EXPORT_SYMBOL_GPL(clk_enable);
889889
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
890890
{
891891
unsigned long parent_rate = 0;
892+
struct clk *parent;
892893

893894
if (!clk)
894895
return 0;
895896

896-
if (!clk->ops->round_rate) {
897-
if (clk->flags & CLK_SET_RATE_PARENT)
898-
return __clk_round_rate(clk->parent, rate);
899-
else
900-
return clk->rate;
901-
}
902-
903-
if (clk->parent)
904-
parent_rate = clk->parent->rate;
905-
906-
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
897+
parent = clk->parent;
898+
if (parent)
899+
parent_rate = parent->rate;
900+
901+
if (clk->ops->determine_rate)
902+
return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
903+
&parent);
904+
else if (clk->ops->round_rate)
905+
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
906+
else if (clk->flags & CLK_SET_RATE_PARENT)
907+
return __clk_round_rate(clk->parent, rate);
908+
else
909+
return clk->rate;
907910
}
908911

909912
/**
@@ -1056,6 +1059,10 @@ static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
10561059

10571060
static void clk_reparent(struct clk *clk, struct clk *new_parent)
10581061
{
1062+
/* avoid duplicate POST_RATE_CHANGE notifications */
1063+
if (new_parent->new_child == clk)
1064+
new_parent->new_child = NULL;
1065+
10591066
hlist_del(&clk->child_node);
10601067

10611068
if (new_parent)
@@ -1176,18 +1183,25 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
11761183
return ret;
11771184
}
11781185

1179-
static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
1186+
static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
1187+
struct clk *new_parent, u8 p_index)
11801188
{
11811189
struct clk *child;
11821190

11831191
clk->new_rate = new_rate;
1192+
clk->new_parent = new_parent;
1193+
clk->new_parent_index = p_index;
1194+
/* include clk in new parent's PRE_RATE_CHANGE notifications */
1195+
clk->new_child = NULL;
1196+
if (new_parent && new_parent != clk->parent)
1197+
new_parent->new_child = clk;
11841198

11851199
hlist_for_each_entry(child, &clk->children, child_node) {
11861200
if (child->ops->recalc_rate)
11871201
child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
11881202
else
11891203
child->new_rate = new_rate;
1190-
clk_calc_subtree(child, child->new_rate);
1204+
clk_calc_subtree(child, child->new_rate, NULL, 0);
11911205
}
11921206
}
11931207

@@ -1198,50 +1212,63 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
11981212
static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
11991213
{
12001214
struct clk *top = clk;
1215+
struct clk *old_parent, *parent;
12011216
unsigned long best_parent_rate = 0;
12021217
unsigned long new_rate;
1218+
u8 p_index = 0;
12031219

12041220
/* sanity */
12051221
if (IS_ERR_OR_NULL(clk))
12061222
return NULL;
12071223

12081224
/* save parent rate, if it exists */
1209-
if (clk->parent)
1210-
best_parent_rate = clk->parent->rate;
1211-
1212-
/* never propagate up to the parent */
1213-
if (!(clk->flags & CLK_SET_RATE_PARENT)) {
1214-
if (!clk->ops->round_rate) {
1215-
clk->new_rate = clk->rate;
1216-
return NULL;
1217-
}
1218-
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
1225+
parent = old_parent = clk->parent;
1226+
if (parent)
1227+
best_parent_rate = parent->rate;
1228+
1229+
/* find the closest rate and parent clk/rate */
1230+
if (clk->ops->determine_rate) {
1231+
new_rate = clk->ops->determine_rate(clk->hw, rate,
1232+
&best_parent_rate,
1233+
&parent);
1234+
} else if (clk->ops->round_rate) {
1235+
new_rate = clk->ops->round_rate(clk->hw, rate,
1236+
&best_parent_rate);
1237+
} else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
1238+
/* pass-through clock without adjustable parent */
1239+
clk->new_rate = clk->rate;
1240+
return NULL;
1241+
} else {
1242+
/* pass-through clock with adjustable parent */
1243+
top = clk_calc_new_rates(parent, rate);
1244+
new_rate = parent->new_rate;
12191245
goto out;
12201246
}
12211247

1222-
/* need clk->parent from here on out */
1223-
if (!clk->parent) {
1224-
pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
1248+
/* some clocks must be gated to change parent */
1249+
if (parent != old_parent &&
1250+
(clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
1251+
pr_debug("%s: %s not gated but wants to reparent\n",
1252+
__func__, clk->name);
12251253
return NULL;
12261254
}
12271255

1228-
if (!clk->ops->round_rate) {
1229-
top = clk_calc_new_rates(clk->parent, rate);
1230-
new_rate = clk->parent->new_rate;
1231-
1232-
goto out;
1256+
/* try finding the new parent index */
1257+
if (parent) {
1258+
p_index = clk_fetch_parent_index(clk, parent);
1259+
if (p_index == clk->num_parents) {
1260+
pr_debug("%s: clk %s can not be parent of clk %s\n",
1261+
__func__, parent->name, clk->name);
1262+
return NULL;
1263+
}
12331264
}
12341265

1235-
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
1236-
1237-
if (best_parent_rate != clk->parent->rate) {
1238-
top = clk_calc_new_rates(clk->parent, best_parent_rate);
1239-
1240-
goto out;
1241-
}
1266+
if ((clk->flags & CLK_SET_RATE_PARENT) && parent &&
1267+
best_parent_rate != parent->rate)
1268+
top = clk_calc_new_rates(parent, best_parent_rate);
12421269

12431270
out:
1244-
clk_calc_subtree(clk, new_rate);
1271+
clk_calc_subtree(clk, new_rate, parent, p_index);
12451272

12461273
return top;
12471274
}
@@ -1253,7 +1280,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
12531280
*/
12541281
static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
12551282
{
1256-
struct clk *child, *fail_clk = NULL;
1283+
struct clk *child, *tmp_clk, *fail_clk = NULL;
12571284
int ret = NOTIFY_DONE;
12581285

12591286
if (clk->rate == clk->new_rate)
@@ -1266,9 +1293,19 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
12661293
}
12671294

12681295
hlist_for_each_entry(child, &clk->children, child_node) {
1269-
clk = clk_propagate_rate_change(child, event);
1270-
if (clk)
1271-
fail_clk = clk;
1296+
/* Skip children who will be reparented to another clock */
1297+
if (child->new_parent && child->new_parent != clk)
1298+
continue;
1299+
tmp_clk = clk_propagate_rate_change(child, event);
1300+
if (tmp_clk)
1301+
fail_clk = tmp_clk;
1302+
}
1303+
1304+
/* handle the new child who might not be in clk->children yet */
1305+
if (clk->new_child) {
1306+
tmp_clk = clk_propagate_rate_change(clk->new_child, event);
1307+
if (tmp_clk)
1308+
fail_clk = tmp_clk;
12721309
}
12731310

12741311
return fail_clk;
@@ -1286,6 +1323,10 @@ static void clk_change_rate(struct clk *clk)
12861323

12871324
old_rate = clk->rate;
12881325

1326+
/* set parent */
1327+
if (clk->new_parent && clk->new_parent != clk->parent)
1328+
__clk_set_parent(clk, clk->new_parent, clk->new_parent_index);
1329+
12891330
if (clk->parent)
12901331
best_parent_rate = clk->parent->rate;
12911332

@@ -1300,8 +1341,16 @@ static void clk_change_rate(struct clk *clk)
13001341
if (clk->notifier_count && old_rate != clk->rate)
13011342
__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
13021343

1303-
hlist_for_each_entry(child, &clk->children, child_node)
1344+
hlist_for_each_entry(child, &clk->children, child_node) {
1345+
/* Skip children who will be reparented to another clock */
1346+
if (child->new_parent && child->new_parent != clk)
1347+
continue;
13041348
clk_change_rate(child);
1349+
}
1350+
1351+
/* handle the new child who might not be in clk->children yet */
1352+
if (clk->new_child)
1353+
clk_change_rate(clk->new_child);
13051354
}
13061355

13071356
/**
@@ -1552,8 +1601,9 @@ int __clk_init(struct device *dev, struct clk *clk)
15521601

15531602
/* check that clk_ops are sane. See Documentation/clk.txt */
15541603
if (clk->ops->set_rate &&
1555-
!(clk->ops->round_rate && clk->ops->recalc_rate)) {
1556-
pr_warning("%s: %s must implement .round_rate & .recalc_rate\n",
1604+
!((clk->ops->round_rate || clk->ops->determine_rate) &&
1605+
clk->ops->recalc_rate)) {
1606+
pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n",
15571607
__func__, clk->name);
15581608
ret = -EINVAL;
15591609
goto out;

include/linux/clk-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ struct clk {
3333
const char **parent_names;
3434
struct clk **parents;
3535
u8 num_parents;
36+
u8 new_parent_index;
3637
unsigned long rate;
3738
unsigned long new_rate;
39+
struct clk *new_parent;
40+
struct clk *new_child;
3841
unsigned long flags;
3942
unsigned int enable_count;
4043
unsigned int prepare_count;

include/linux/clk-provider.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ struct clk_hw;
7979
* @round_rate: Given a target rate as input, returns the closest rate actually
8080
* supported by the clock.
8181
*
82+
* @determine_rate: Given a target rate as input, returns the closest rate
83+
* actually supported by the clock, and optionally the parent clock
84+
* that should be used to provide the clock rate.
85+
*
8286
* @get_parent: Queries the hardware to determine the parent of a clock. The
8387
* return value is a u8 which specifies the index corresponding to
8488
* the parent clock. This index can be applied to either the
@@ -126,6 +130,9 @@ struct clk_ops {
126130
unsigned long parent_rate);
127131
long (*round_rate)(struct clk_hw *hw, unsigned long,
128132
unsigned long *);
133+
long (*determine_rate)(struct clk_hw *hw, unsigned long rate,
134+
unsigned long *best_parent_rate,
135+
struct clk **best_parent_clk);
129136
int (*set_parent)(struct clk_hw *hw, u8 index);
130137
u8 (*get_parent)(struct clk_hw *hw);
131138
int (*set_rate)(struct clk_hw *hw, unsigned long,

0 commit comments

Comments
 (0)