Message ID | 20230717-pll-mipi_set_rate_parent-v4-3-04acf1d39765@oltmanns.dev (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | clk: sunxi-ng: Consider alternative parent rates when determining NKM clock rate | expand |
Hi, On Mon, Jul 17, 2023 at 03:34:27PM +0200, Frank Oltmanns wrote: > Make the SET_PARENT_RATE flag independent of the parents round_rate or > determine_rate implementation. > > Currently, the algorithm for ccu_nkm_find_best_with_parent_adj simply > calculates the optimal parent rate as > (1) parent = rate * m / (n * k) > > Due to integer division (1) might return a parent rate that is too low. > So using this value for asking the parent for a rate it supports via > clk_hw_round_rate causes problems on > a) parents that only support finding rates that are lower than the > requested rate - which is the default for sunxi-ng ccu's. > b) parents that incidentally also support the truncated rate. > > In those cases ccu_nkm_determine_rate might return A' when A is > requested and A'' when rate A' is requested. > > Prevent this by trying to find a parent rate so that > (2) _rate = parent * n * k / m > matches the requested rate exactly, if possible. > > Background: > =========== > determine_rate may be called multiple times by the clk framework when > setting a clock's rate. But the clk framework expects that the values > determine_rate returns (i.e. the rate and parent_rate) are consistent > with previous calls. > > Specifically, clock's have to ensure that if determine_rate is called > with requested rate A and the best rate it can find is A', it must also > return A' when called with requested rate A'. > > Signed-off-by: Frank Oltmanns <frank@oltmanns.dev> As stated in my earlier mail, I still disagree with that patch. Maxime
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index 750e2b8da24b..793160bc2d47 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -17,6 +17,27 @@ struct _ccu_nkm { unsigned long m, min_m, max_m; }; +/* + * Calculate the optimal parent when determining the nkm clock's rate. + * + * This function is used when the nkm clock supports setting the parent rate and ensures that the + * determine_rate function returns consistent values. I.e., when determine rate is called for rate A + * and the best rate it can find is A', this function ensures that determine_rate will also return + * A' when A' is requested. + */ +static unsigned long ccu_nkm_optimal_parent_rate(unsigned long rate, unsigned long n, + unsigned long k, unsigned long m) +{ + unsigned long _rate, parent; + + parent = DIV_ROUND_UP(rate * m, n * k); + + _rate = parent * n * k / m; + if (_rate > rate) + parent = rate * m / (n * k); + return parent; +} + static unsigned long ccu_nkm_find_best_with_parent_adj(struct clk_hw *phw, struct _ccu_nkm *nkm, unsigned long *parent, unsigned long rate) { @@ -29,7 +50,8 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct clk_hw *phw, struc for (_m = nkm->min_m; _m <= nkm->max_m; _m++) { unsigned long tmp_rate; - tmp_parent = clk_hw_round_rate(phw, rate * _m / (_n * _k)); + tmp_parent = ccu_nkm_optimal_parent_rate(rate, _n, _k, _m); + tmp_parent = clk_hw_round_rate(phw, tmp_parent); tmp_rate = tmp_parent * _n * _k / _m; if (tmp_rate > rate)
Make the SET_PARENT_RATE flag independent of the parents round_rate or determine_rate implementation. Currently, the algorithm for ccu_nkm_find_best_with_parent_adj simply calculates the optimal parent rate as (1) parent = rate * m / (n * k) Due to integer division (1) might return a parent rate that is too low. So using this value for asking the parent for a rate it supports via clk_hw_round_rate causes problems on a) parents that only support finding rates that are lower than the requested rate - which is the default for sunxi-ng ccu's. b) parents that incidentally also support the truncated rate. In those cases ccu_nkm_determine_rate might return A' when A is requested and A'' when rate A' is requested. Prevent this by trying to find a parent rate so that (2) _rate = parent * n * k / m matches the requested rate exactly, if possible. Background: =========== determine_rate may be called multiple times by the clk framework when setting a clock's rate. But the clk framework expects that the values determine_rate returns (i.e. the rate and parent_rate) are consistent with previous calls. Specifically, clock's have to ensure that if determine_rate is called with requested rate A and the best rate it can find is A', it must also return A' when called with requested rate A'. Signed-off-by: Frank Oltmanns <frank@oltmanns.dev> --- drivers/clk/sunxi-ng/ccu_nkm.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)