Skip to content

Commit 364a609

Browse files
committed
Merge tag 'sunxi-clk-for-6.6-2' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into clk-allwinner
Pull Allwinner clk driver changes from Chen-Yu Tsai: - Parameter name correction for ccu_nkm_round_rate() - Implement CLK_SET_RATE_PARENT for NKM clocks, i.e. consider alternative parent rates when determining clock rates - Set CLK_SET_RATE_PARENT for A64 pll-mipi - Support finding closest (as opposed to closest but not higher) clock rate for NM, NKM, mux and div type clocks, as use it for A64 pll-video0 - Prefer current parent rate if able to generate ideal clock rate for NKM clocks * tag 'sunxi-clk-for-6.6-2' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux: clk: sunxi-ng: nkm: Prefer current parent rate clk: sunxi-ng: a64: select closest rate for pll-video0 clk: sunxi-ng: div: Support finding closest rate clk: sunxi-ng: mux: Support finding closest rate clk: sunxi-ng: nkm: Support finding closest rate clk: sunxi-ng: nm: Support finding closest rate clk: sunxi-ng: Add helper function to find closest rate clk: sunxi-ng: Add feature to find closest rate clk: sunxi-ng: a64: allow pll-mipi to set parent's rate clk: sunxi-ng: nkm: consider alternative parent rates when determining rate clk: sunxi-ng: nkm: Use correct parameter name for parent HW
2 parents 7458ea3 + a69f946 commit 364a609

File tree

9 files changed

+204
-54
lines changed

9 files changed

+204
-54
lines changed

drivers/clk/sunxi-ng/ccu-sun50i-a64.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
6868
BIT(28), /* lock */
6969
CLK_SET_RATE_UNGATE);
7070

71-
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0",
71+
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(pll_video0_clk, "pll-video0",
7272
"osc24M", 0x010,
7373
192000000, /* Minimum rate */
7474
1008000000, /* Maximum rate */
@@ -179,7 +179,9 @@ static struct ccu_nkm pll_mipi_clk = {
179179
.common = {
180180
.reg = 0x040,
181181
.hw.init = CLK_HW_INIT("pll-mipi", "pll-video0",
182-
&ccu_nkm_ops, CLK_SET_RATE_UNGATE),
182+
&ccu_nkm_ops,
183+
CLK_SET_RATE_UNGATE | CLK_SET_RATE_PARENT),
184+
.features = CCU_FEATURE_CLOSEST_RATE,
183185
},
184186
};
185187

@@ -536,25 +538,18 @@ static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents,
536538

537539
static const char * const tcon0_parents[] = { "pll-mipi", "pll-video0-2x" };
538540
static const u8 tcon0_table[] = { 0, 2, };
539-
static SUNXI_CCU_MUX_TABLE_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents,
540-
tcon0_table, 0x118, 24, 3, BIT(31),
541-
CLK_SET_RATE_PARENT |
542-
CLK_SET_RATE_NO_REPARENT);
541+
static SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(tcon0_clk, "tcon0", tcon0_parents,
542+
tcon0_table, 0x118, 24, 3, BIT(31),
543+
CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT);
543544

544545
static const char * const tcon1_parents[] = { "pll-video0", "pll-video1" };
545546
static const u8 tcon1_table[] = { 0, 2, };
546-
static struct ccu_div tcon1_clk = {
547-
.enable = BIT(31),
548-
.div = _SUNXI_CCU_DIV(0, 4),
549-
.mux = _SUNXI_CCU_MUX_TABLE(24, 2, tcon1_table),
550-
.common = {
551-
.reg = 0x11c,
552-
.hw.init = CLK_HW_INIT_PARENTS("tcon1",
553-
tcon1_parents,
554-
&ccu_div_ops,
555-
CLK_SET_RATE_PARENT),
556-
},
557-
};
547+
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(tcon1_clk, "tcon1", tcon1_parents,
548+
tcon1_table, 0x11c,
549+
0, 4, /* M */
550+
24, 2, /* mux */
551+
BIT(31), /* gate */
552+
CLK_SET_RATE_PARENT);
558553

559554
static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" };
560555
static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents,
@@ -584,8 +579,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
584579
0x144, BIT(31), 0);
585580

586581
static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" };
587-
static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
588-
0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT);
582+
static SUNXI_CCU_M_WITH_MUX_GATE_CLOSEST(hdmi_clk, "hdmi", hdmi_parents,
583+
0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT);
589584

590585
static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M",
591586
0x154, BIT(31), 0);
@@ -597,9 +592,9 @@ static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents,
597592

598593
static const char * const dsi_dphy_parents[] = { "pll-video0", "pll-periph0" };
599594
static const u8 dsi_dphy_table[] = { 0, 2, };
600-
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_dphy_clk, "dsi-dphy",
601-
dsi_dphy_parents, dsi_dphy_table,
602-
0x168, 0, 4, 8, 2, BIT(15), CLK_SET_RATE_PARENT);
595+
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(dsi_dphy_clk, "dsi-dphy",
596+
dsi_dphy_parents, dsi_dphy_table,
597+
0x168, 0, 4, 8, 2, BIT(15), CLK_SET_RATE_PARENT);
603598

604599
static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
605600
0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT);

drivers/clk/sunxi-ng/ccu_common.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
3939
}
4040
EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, SUNXI_CCU);
4141

42+
bool ccu_is_better_rate(struct ccu_common *common,
43+
unsigned long target_rate,
44+
unsigned long current_rate,
45+
unsigned long best_rate)
46+
{
47+
if (common->features & CCU_FEATURE_CLOSEST_RATE)
48+
return abs(current_rate - target_rate) < abs(best_rate - target_rate);
49+
50+
return current_rate <= target_rate && current_rate > best_rate;
51+
}
52+
EXPORT_SYMBOL_NS_GPL(ccu_is_better_rate, SUNXI_CCU);
53+
4254
/*
4355
* This clock notifier is called when the frequency of a PLL clock is
4456
* changed. In common PLL designs, changes to the dividers take effect

drivers/clk/sunxi-ng/ccu_common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define CCU_FEATURE_MMC_TIMING_SWITCH BIT(6)
1919
#define CCU_FEATURE_SIGMA_DELTA_MOD BIT(7)
2020
#define CCU_FEATURE_KEY_FIELD BIT(8)
21+
#define CCU_FEATURE_CLOSEST_RATE BIT(9)
2122

2223
/* MMC timing mode switch bit */
2324
#define CCU_MMC_NEW_TIMING_MODE BIT(30)
@@ -52,6 +53,11 @@ struct sunxi_ccu_desc {
5253

5354
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock);
5455

56+
bool ccu_is_better_rate(struct ccu_common *common,
57+
unsigned long target_rate,
58+
unsigned long current_rate,
59+
unsigned long best_rate);
60+
5561
struct ccu_pll_nb {
5662
struct notifier_block clk_nb;
5763
struct ccu_common *common;

drivers/clk/sunxi-ng/ccu_div.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,26 @@ struct ccu_div {
143143
}, \
144144
}
145145

146+
#define SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \
147+
_parents, _table, \
148+
_reg, \
149+
_mshift, _mwidth, \
150+
_muxshift, _muxwidth, \
151+
_gate, _flags) \
152+
struct ccu_div _struct = { \
153+
.enable = _gate, \
154+
.div = _SUNXI_CCU_DIV_FLAGS(_mshift, _mwidth, CLK_DIVIDER_ROUND_CLOSEST), \
155+
.mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \
156+
.common = { \
157+
.reg = _reg, \
158+
.hw.init = CLK_HW_INIT_PARENTS(_name, \
159+
_parents, \
160+
&ccu_div_ops, \
161+
_flags), \
162+
.features = CCU_FEATURE_CLOSEST_RATE, \
163+
}, \
164+
}
165+
146166
#define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
147167
_mshift, _mwidth, _muxshift, _muxwidth, \
148168
_gate, _flags) \
@@ -152,6 +172,16 @@ struct ccu_div {
152172
_muxshift, _muxwidth, \
153173
_gate, _flags)
154174

175+
#define SUNXI_CCU_M_WITH_MUX_GATE_CLOSEST(_struct, _name, _parents, \
176+
_reg, _mshift, _mwidth, \
177+
_muxshift, _muxwidth, \
178+
_gate, _flags) \
179+
SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \
180+
_parents, NULL, \
181+
_reg, _mshift, _mwidth, \
182+
_muxshift, _muxwidth, \
183+
_gate, _flags)
184+
155185
#define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \
156186
_mshift, _mwidth, _muxshift, _muxwidth, \
157187
_flags) \

drivers/clk/sunxi-ng/ccu_mux.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common,
139139
goto out;
140140
}
141141

142-
if ((req->rate - tmp_rate) < (req->rate - best_rate)) {
142+
if (ccu_is_better_rate(common, req->rate, tmp_rate, best_rate)) {
143143
best_rate = tmp_rate;
144144
best_parent_rate = parent_rate;
145145
best_parent = parent;
@@ -242,6 +242,17 @@ static int ccu_mux_set_parent(struct clk_hw *hw, u8 index)
242242
return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index);
243243
}
244244

245+
static int ccu_mux_determine_rate(struct clk_hw *hw,
246+
struct clk_rate_request *req)
247+
{
248+
struct ccu_mux *cm = hw_to_ccu_mux(hw);
249+
250+
if (cm->common.features & CCU_FEATURE_CLOSEST_RATE)
251+
return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST);
252+
253+
return clk_mux_determine_rate_flags(hw, req, 0);
254+
}
255+
245256
static unsigned long ccu_mux_recalc_rate(struct clk_hw *hw,
246257
unsigned long parent_rate)
247258
{
@@ -259,7 +270,7 @@ const struct clk_ops ccu_mux_ops = {
259270
.get_parent = ccu_mux_get_parent,
260271
.set_parent = ccu_mux_set_parent,
261272

262-
.determine_rate = __clk_mux_determine_rate,
273+
.determine_rate = ccu_mux_determine_rate,
263274
.recalc_rate = ccu_mux_recalc_rate,
264275
};
265276
EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU);

drivers/clk/sunxi-ng/ccu_mux.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,36 @@ struct ccu_mux {
4646
struct ccu_common common;
4747
};
4848

49+
#define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table, \
50+
_reg, _shift, _width, _gate, \
51+
_flags, _features) \
52+
struct ccu_mux _struct = { \
53+
.enable = _gate, \
54+
.mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \
55+
.common = { \
56+
.reg = _reg, \
57+
.hw.init = CLK_HW_INIT_PARENTS(_name, \
58+
_parents, \
59+
&ccu_mux_ops, \
60+
_flags), \
61+
.features = _features, \
62+
} \
63+
}
64+
65+
#define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents, \
66+
_table, _reg, _shift, \
67+
_width, _gate, _flags) \
68+
SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \
69+
_table, _reg, _shift, \
70+
_width, _gate, _flags, \
71+
CCU_FEATURE_CLOSEST_RATE)
72+
4973
#define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table, \
5074
_reg, _shift, _width, _gate, \
5175
_flags) \
52-
struct ccu_mux _struct = { \
53-
.enable = _gate, \
54-
.mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \
55-
.common = { \
56-
.reg = _reg, \
57-
.hw.init = CLK_HW_INIT_PARENTS(_name, \
58-
_parents, \
59-
&ccu_mux_ops, \
60-
_flags), \
61-
} \
62-
}
76+
SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \
77+
_table, _reg, _shift, \
78+
_width, _gate, _flags, 0)
6379

6480
#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \
6581
_shift, _width, _gate, _flags) \

drivers/clk/sunxi-ng/ccu_nkm.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,47 @@ 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 ccu_common *common,
20+
struct clk_hw *parent_hw,
21+
unsigned long *parent, unsigned long rate,
22+
struct _ccu_nkm *nkm)
23+
{
24+
unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent;
25+
unsigned long best_n = 0, best_k = 0, best_m = 0;
26+
unsigned long _n, _k, _m;
27+
28+
for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
29+
for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
30+
for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
31+
unsigned long tmp_rate;
32+
33+
tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k));
34+
35+
tmp_rate = tmp_parent * _n * _k / _m;
36+
37+
if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) ||
38+
(tmp_parent == *parent && tmp_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,
20-
struct _ccu_nkm *nkm)
59+
struct _ccu_nkm *nkm, struct ccu_common *common)
2160
{
2261
unsigned long best_rate = 0;
2362
unsigned long best_n = 0, best_k = 0, best_m = 0;
@@ -30,9 +69,7 @@ static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
3069

3170
tmp_rate = parent * _n * _k / _m;
3271

33-
if (tmp_rate > rate)
34-
continue;
35-
if ((rate - tmp_rate) < (rate - best_rate)) {
72+
if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
3673
best_rate = tmp_rate;
3774
best_n = _n;
3875
best_k = _k;
@@ -106,7 +143,7 @@ static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw,
106143
}
107144

108145
static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
109-
struct clk_hw *hw,
146+
struct clk_hw *parent_hw,
110147
unsigned long *parent_rate,
111148
unsigned long rate,
112149
void *data)
@@ -124,7 +161,11 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
124161
if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
125162
rate *= nkm->fixed_post_div;
126163

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

129170
if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
130171
rate /= nkm->fixed_post_div;
@@ -159,7 +200,7 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
159200
_nkm.min_m = 1;
160201
_nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;
161202

162-
ccu_nkm_find_best(parent_rate, rate, &_nkm);
203+
ccu_nkm_find_best(parent_rate, rate, &_nkm, &nkm->common);
163204

164205
spin_lock_irqsave(nkm->common.lock, flags);
165206

drivers/clk/sunxi-ng/ccu_nm.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent,
2727
return rate;
2828
}
2929

30-
static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
31-
struct _ccu_nm *nm)
30+
static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned long parent,
31+
unsigned long rate, struct _ccu_nm *nm)
3232
{
3333
unsigned long best_rate = 0;
3434
unsigned long best_n = 0, best_m = 0;
@@ -39,10 +39,7 @@ static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
3939
unsigned long tmp_rate = ccu_nm_calc_rate(parent,
4040
_n, _m);
4141

42-
if (tmp_rate > rate)
43-
continue;
44-
45-
if ((rate - tmp_rate) < (rate - best_rate)) {
42+
if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
4643
best_rate = tmp_rate;
4744
best_n = _n;
4845
best_m = _m;
@@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
159156
_nm.min_m = 1;
160157
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
161158

162-
rate = ccu_nm_find_best(*parent_rate, rate, &_nm);
159+
rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm);
163160

164161
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
165162
rate /= nm->fixed_post_div;
@@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
210207
&_nm.m, &_nm.n);
211208
} else {
212209
ccu_sdm_helper_disable(&nm->common, &nm->sdm);
213-
ccu_nm_find_best(parent_rate, rate, &_nm);
210+
ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm);
214211
}
215212

216213
spin_lock_irqsave(nm->common.lock, flags);

0 commit comments

Comments
 (0)