Skip to content

Commit 3492e4f

Browse files
Frank Oltmannswens
authored andcommitted
clk: sunxi-ng: nkm: consider alternative parent rates when determining rate
In case the CLK_SET_RATE_PARENT flag is set, consider using a different parent rate when determining a new rate. To find the best match for the requested rate, perform the following steps for each NKM combination: - calculate the optimal parent rate, - find the best parent rate that the parent clock actually supports - use that parent rate to calculate the effective rate. In case the clk does not support setting the parent rate, use the same algorithm as before. Acked-by: Maxime Ripard <[email protected]> Signed-off-by: Frank Oltmanns <[email protected]> Reviewed-by: Chen-Yu Tsai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Chen-Yu Tsai <[email protected]>
1 parent 80c439c commit 3492e4f

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

drivers/clk/sunxi-ng/ccu_nkm.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,45 @@ struct _ccu_nkm {
1616
unsigned long m, min_m, max_m;
1717
};
1818

19+
static unsigned long ccu_nkm_find_best_with_parent_adj(struct clk_hw *parent_hw,
20+
unsigned long *parent, unsigned long rate,
21+
struct _ccu_nkm *nkm)
22+
{
23+
unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent;
24+
unsigned long best_n = 0, best_k = 0, best_m = 0;
25+
unsigned long _n, _k, _m;
26+
27+
for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
28+
for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
29+
for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
30+
unsigned long tmp_rate;
31+
32+
tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k));
33+
34+
tmp_rate = tmp_parent * _n * _k / _m;
35+
if (tmp_rate > rate)
36+
continue;
37+
38+
if ((rate - tmp_rate) < (rate - best_rate)) {
39+
best_rate = tmp_rate;
40+
best_parent_rate = tmp_parent;
41+
best_n = _n;
42+
best_k = _k;
43+
best_m = _m;
44+
}
45+
}
46+
}
47+
}
48+
49+
nkm->n = best_n;
50+
nkm->k = best_k;
51+
nkm->m = best_m;
52+
53+
*parent = best_parent_rate;
54+
55+
return best_rate;
56+
}
57+
1958
static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
2059
struct _ccu_nkm *nkm)
2160
{
@@ -124,7 +163,10 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
124163
if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
125164
rate *= nkm->fixed_post_div;
126165

127-
rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm);
166+
if (!clk_hw_can_set_rate_parent(&nkm->common.hw))
167+
rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm);
168+
else
169+
rate = ccu_nkm_find_best_with_parent_adj(parent_hw, parent_rate, rate, &_nkm);
128170

129171
if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
130172
rate /= nkm->fixed_post_div;

0 commit comments

Comments
 (0)