diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 09230728c400..4503c9780c39 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -92,66 +92,65 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common, struct clk_rate_request adj_req = *req; best_parent = clk_hw_get_parent(hw); - best_parent_rate = clk_hw_get_rate(best_parent); - + adj_req.best_parent_rate = clk_hw_get_rate(best_parent); adj_req.best_parent_hw = best_parent; - adj_req.best_parent_rate = ccu_mux_helper_apply_prediv(common, cm, -1, - best_parent_rate); + + /* + * This effectively treats the predivider as a postdivider. + * It stays mathematically correct and ensures whatever + * round() will do stays correct while walking the tree. + * It may query the parent rate too while handling rate + * propagation. + */ + adj_req.rate = ccu_mux_helper_unapply_prediv(common, cm, -1, + req->rate); ret = round(cm, &adj_req, data); if (ret) return ret; - best_rate = adj_req.rate; - /* - * best_parent_rate might have been modified by our clock. - * Unapply the pre-divider if there's one, and give - * the actual frequency the parent needs to run at. + * parent_rate might have been modified by our clock as part + * of the rate propagation mechanism. Same goes below. */ - best_parent_rate = ccu_mux_helper_unapply_prediv(common, cm, -1, - adj_req.best_parent_rate); + best_parent_rate = adj_req.best_parent_rate; + best_rate = ccu_mux_helper_apply_prediv(common, cm, -1, + adj_req.rate); goto out; } for (i = 0; i < clk_hw_get_num_parents(hw); i++) { struct clk_rate_request tmp_req = *req; - unsigned long parent_rate; + unsigned long rate; struct clk_hw *parent; parent = clk_hw_get_parent_by_index(hw, i); if (!parent) continue; - parent_rate = ccu_mux_helper_apply_prediv(common, cm, i, - clk_hw_get_rate(parent)); - tmp_req.best_parent_hw = parent; - tmp_req.best_parent_rate = parent_rate; + tmp_req.best_parent_rate = clk_hw_get_rate(parent); + tmp_req.rate = ccu_mux_helper_unapply_prediv(common, cm, i, + req->rate); ret = round(cm, &tmp_req, data); if (ret) continue; - /* - * parent_rate might have been modified by our clock. - * Unapply the pre-divider if there's one, and give - * the actual frequency the parent needs to run at. - */ - parent_rate = ccu_mux_helper_unapply_prediv(common, cm, i, - tmp_req.best_parent_rate); + rate = ccu_mux_helper_apply_prediv(common, cm, i, + tmp_req.rate); - if (tmp_req.rate == req->rate) { + if (rate == req->rate) { best_parent = parent; - best_parent_rate = parent_rate; - best_rate = tmp_req.rate; + best_parent_rate = tmp_req.best_parent_rate; + best_rate = rate; goto out; } - if (ccu_is_better_rate(common, req->rate, tmp_req.rate, best_rate)) { - best_rate = tmp_req.rate; - best_parent_rate = parent_rate; + if (ccu_is_better_rate(common, req->rate, rate, best_rate)) { + best_rate = rate; + best_parent_rate = tmp_req.best_parent_rate; best_parent = parent; } }