Use the helper function ccu_is_better_rate() to determine the rate that
is closest to the requested rate, thereby supporting rates that are
higher than the requested rate if the clock uses the
CCU_FEATURE_CLOSEST_RATE.
Add the macro SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST which
sets CCU_FEATURE_CLOSEST_RATE.
To avoid code duplication, add the macros
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT that allows selecting
arbitrary features and use it in the original
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX as well as the newly introduced
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST macros.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Frank Oltmanns <frank@oltmanns.dev>
---
drivers/clk/sunxi-ng/ccu_nm.c | 13 +++++-------
drivers/clk/sunxi-ng/ccu_nm.h | 48 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index c1fd11542c45..ffac3deb89d6 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent,
return rate;
}
-static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nm *nm)
+static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned long parent,
+ unsigned long rate, struct _ccu_nm *nm)
{
unsigned long best_rate = 0;
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,
unsigned long tmp_rate = ccu_nm_calc_rate(parent,
_n, _m);
- if (tmp_rate > rate)
- continue;
-
- if ((rate - tmp_rate) < (rate - best_rate)) {
+ if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
best_rate = tmp_rate;
best_n = _n;
best_m = _m;
@@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
_nm.min_m = 1;
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
- rate = ccu_nm_find_best(*parent_rate, rate, &_nm);
+ rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm);
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nm->fixed_post_div;
@@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
&_nm.m, &_nm.n);
} else {
ccu_sdm_helper_disable(&nm->common, &nm->sdm);
- ccu_nm_find_best(parent_rate, rate, &_nm);
+ ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm);
}
spin_lock_irqsave(nm->common.lock, flags);
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
index 2904e67f05a8..93c11693574f 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.h
+++ b/drivers/clk/sunxi-ng/ccu_nm.h
@@ -108,7 +108,7 @@ struct ccu_nm {
}, \
}
-#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
_parent, _reg, \
_min_rate, _max_rate, \
_nshift, _nwidth, \
@@ -116,7 +116,8 @@ struct ccu_nm {
_frac_en, _frac_sel, \
_frac_rate_0, \
_frac_rate_1, \
- _gate, _lock, _flags) \
+ _gate, _lock, _flags, \
+ _features) \
struct ccu_nm _struct = { \
.enable = _gate, \
.lock = _lock, \
@@ -129,7 +130,7 @@ struct ccu_nm {
.max_rate = _max_rate, \
.common = { \
.reg = _reg, \
- .features = CCU_FEATURE_FRACTIONAL, \
+ .features = _features, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nm_ops, \
@@ -137,6 +138,47 @@ struct ccu_nm {
}, \
}
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags) \
+ SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags, \
+ CCU_FEATURE_FRACTIONAL)
+
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags) \
+ SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags, \
+ CCU_FEATURE_FRACTIONAL |\
+ CCU_FEATURE_CLOSEST_RATE)
+
#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_mshift, _mwidth, \
--
2.41.0
Dne nedelja, 06. avgust 2023 ob 15:06:51 CEST je Frank Oltmanns napisal(a): > Use the helper function ccu_is_better_rate() to determine the rate that > is closest to the requested rate, thereby supporting rates that are > higher than the requested rate if the clock uses the > CCU_FEATURE_CLOSEST_RATE. > > Add the macro SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST which > sets CCU_FEATURE_CLOSEST_RATE. > > To avoid code duplication, add the macros > SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT that allows selecting > arbitrary features and use it in the original > SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX as well as the newly introduced > SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST macros. > > Acked-by: Maxime Ripard <mripard@kernel.org> > Signed-off-by: Frank Oltmanns <frank@oltmanns.dev> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Best regards, Jernej > --- > drivers/clk/sunxi-ng/ccu_nm.c | 13 +++++------- > drivers/clk/sunxi-ng/ccu_nm.h | 48 > ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 50 > insertions(+), 11 deletions(-) > > diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c > index c1fd11542c45..ffac3deb89d6 100644 > --- a/drivers/clk/sunxi-ng/ccu_nm.c > +++ b/drivers/clk/sunxi-ng/ccu_nm.c > @@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long > parent, return rate; > } > > -static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long > rate, - struct _ccu_nm *nm) > +static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned > long parent, + unsigned long rate, struct _ccu_nm *nm) > { > unsigned long best_rate = 0; > 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, unsigned long tmp_rate = > ccu_nm_calc_rate(parent, > _n, _m); > > - if (tmp_rate > rate) > - continue; > - > - if ((rate - tmp_rate) < (rate - best_rate)) { > + if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) { > best_rate = tmp_rate; > best_n = _n; > best_m = _m; > @@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, > unsigned long rate, _nm.min_m = 1; > _nm.max_m = nm->m.max ?: 1 << nm->m.width; > > - rate = ccu_nm_find_best(*parent_rate, rate, &_nm); > + rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm); > > if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) > rate /= nm->fixed_post_div; > @@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned > long rate, &_nm.m, &_nm.n); > } else { > ccu_sdm_helper_disable(&nm->common, &nm->sdm); > - ccu_nm_find_best(parent_rate, rate, &_nm); > + ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm); > } > > spin_lock_irqsave(nm->common.lock, flags); > diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h > index 2904e67f05a8..93c11693574f 100644 > --- a/drivers/clk/sunxi-ng/ccu_nm.h > +++ b/drivers/clk/sunxi-ng/ccu_nm.h > @@ -108,7 +108,7 @@ struct ccu_nm { > }, \ > } > > -#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \ > +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \ > _parent, _reg, \ > _min_rate, _max_rate, \ > _nshift, _nwidth, \ > @@ -116,7 +116,8 @@ struct ccu_nm { > _frac_en, _frac_sel, \ > _frac_rate_0, \ > _frac_rate_1, \ > - _gate, _lock, _flags) \ > + _gate, _lock, _flags, \ > + _features) \ > struct ccu_nm _struct = { \ > .enable = _gate, \ > .lock = _lock, \ > @@ -129,7 +130,7 @@ struct ccu_nm { > .max_rate = _max_rate, \ > .common = { \ > .reg = _reg, \ > - .features = CCU_FEATURE_FRACTIONAL, \ > + .features = _features, \ > .hw.init = CLK_HW_INIT(_name, \ > _parent, \ > &ccu_nm_ops, \ > @@ -137,6 +138,47 @@ struct ccu_nm { > }, \ > } > > +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \ > + _parent, _reg, \ > + _min_rate, _max_rate, \ > + _nshift, _nwidth, \ > + _mshift, _mwidth, \ > + _frac_en, _frac_sel, \ > + _frac_rate_0, \ > + _frac_rate_1, \ > + _gate, _lock, _flags) \ > + SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \ > + _parent, _reg, \ > + _min_rate, _max_rate, \ > + _nshift, _nwidth, \ > + _mshift, _mwidth, \ > + _frac_en, _frac_sel, \ > + _frac_rate_0, \ > + _frac_rate_1, \ > + _gate, _lock, _flags, \ > + CCU_FEATURE_FRACTIONAL) > + > +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(_struct, _name, \ > + _parent, _reg, \ > + _min_rate, _max_rate, \ > + _nshift, _nwidth, \ > + _mshift, _mwidth, \ > + _frac_en, _frac_sel, \ > + _frac_rate_0, \ > + _frac_rate_1, \ > + _gate, _lock, _flags) \ > + SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \ > + _parent, _reg, \ > + _min_rate, _max_rate, \ > + _nshift, _nwidth, \ > + _mshift, _mwidth, \ > + _frac_en, _frac_sel, \ > + _frac_rate_0, \ > + _frac_rate_1, \ > + _gate, _lock, _flags, \ > + CCU_FEATURE_FRACTIONAL |\ > + CCU_FEATURE_CLOSEST_RATE) > + > #define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \ > _nshift, _nwidth, \ > _mshift, _mwidth, \
© 2016 - 2025 Red Hat, Inc.