clk: sunxi-ng: nm: Support finding closest rate
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> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Frank Oltmanns <frank@oltmanns.dev> Link: https://lore.kernel.org/r/20230807-pll-mipi_set_rate_parent-v6-6-f173239a4b59@oltmanns.dev Signed-off-by: Chen-Yu Tsai <wens@csie.org>
This commit is contained in:
parent
e373315d8f
commit
c0380d1474
|
@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent,
|
||||||
return rate;
|
return rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
|
static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned long parent,
|
||||||
struct _ccu_nm *nm)
|
unsigned long rate, struct _ccu_nm *nm)
|
||||||
{
|
{
|
||||||
unsigned long best_rate = 0;
|
unsigned long best_rate = 0;
|
||||||
unsigned long best_n = 0, best_m = 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,
|
unsigned long tmp_rate = ccu_nm_calc_rate(parent,
|
||||||
_n, _m);
|
_n, _m);
|
||||||
|
|
||||||
if (tmp_rate > rate)
|
if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((rate - tmp_rate) < (rate - best_rate)) {
|
|
||||||
best_rate = tmp_rate;
|
best_rate = tmp_rate;
|
||||||
best_n = _n;
|
best_n = _n;
|
||||||
best_m = _m;
|
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.min_m = 1;
|
||||||
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
|
_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)
|
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||||
rate /= nm->fixed_post_div;
|
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);
|
&_nm.m, &_nm.n);
|
||||||
} else {
|
} else {
|
||||||
ccu_sdm_helper_disable(&nm->common, &nm->sdm);
|
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);
|
spin_lock_irqsave(nm->common.lock, flags);
|
||||||
|
|
|
@ -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, \
|
_parent, _reg, \
|
||||||
_min_rate, _max_rate, \
|
_min_rate, _max_rate, \
|
||||||
_nshift, _nwidth, \
|
_nshift, _nwidth, \
|
||||||
|
@ -116,7 +116,8 @@ struct ccu_nm {
|
||||||
_frac_en, _frac_sel, \
|
_frac_en, _frac_sel, \
|
||||||
_frac_rate_0, \
|
_frac_rate_0, \
|
||||||
_frac_rate_1, \
|
_frac_rate_1, \
|
||||||
_gate, _lock, _flags) \
|
_gate, _lock, _flags, \
|
||||||
|
_features) \
|
||||||
struct ccu_nm _struct = { \
|
struct ccu_nm _struct = { \
|
||||||
.enable = _gate, \
|
.enable = _gate, \
|
||||||
.lock = _lock, \
|
.lock = _lock, \
|
||||||
|
@ -129,7 +130,7 @@ struct ccu_nm {
|
||||||
.max_rate = _max_rate, \
|
.max_rate = _max_rate, \
|
||||||
.common = { \
|
.common = { \
|
||||||
.reg = _reg, \
|
.reg = _reg, \
|
||||||
.features = CCU_FEATURE_FRACTIONAL, \
|
.features = _features, \
|
||||||
.hw.init = CLK_HW_INIT(_name, \
|
.hw.init = CLK_HW_INIT(_name, \
|
||||||
_parent, \
|
_parent, \
|
||||||
&ccu_nm_ops, \
|
&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, \
|
#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
|
||||||
_nshift, _nwidth, \
|
_nshift, _nwidth, \
|
||||||
_mshift, _mwidth, \
|
_mshift, _mwidth, \
|
||||||
|
|
Loading…
Reference in New Issue