All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frank Oltmanns <frank@oltmanns.dev>
To: Andre Przywara <andre.przywara@arm.com>,
	Chen-Yu Tsai <wens@csie.org>, Frank Oltmanns <frank@oltmanns.dev>,
	Jernej Skrabec <jernej.skrabec@gmail.com>,
	Maxime Ripard <maxime@cerno.tech>,
	Michael Turquette <mturquette@baylibre.com>,
	Roman Beranek <me@crly.cz>, Samuel Holland <samuel@sholland.org>,
	Stephen Boyd <sboyd@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-sunxi@lists.linux.dev
Subject: [PATCH v2 1/2] clk: sunxi-ng: nkm: consider alternative parent rates when finding rate
Date: Sun, 11 Jun 2023 11:01:42 +0200	[thread overview]
Message-ID: <20230611090143.132257-2-frank@oltmanns.dev> (raw)
In-Reply-To: <20230611090143.132257-1-frank@oltmanns.dev>

In case the CLK_SET_RATE_PARENT flag is set, consider using a different
parent rate when determining a new rate.

To find the best match for the requested rate, perform the following
steps for each NKM combination:
 - calculate the optimal parent rate,
 - find the best parent rate that the parent clock actually supports
 - use that parent rate to calculate the effective rate.

In case the clk does not support setting the parent rate, use the same
algorithm as before.

Signed-off-by: Frank Oltmanns <frank@oltmanns.dev>
---
 drivers/clk/sunxi-ng/ccu_nkm.c | 66 +++++++++++++++++++++++++++++-----
 1 file changed, 58 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
index a0978a50edae..c49d5879fe73 100644
--- a/drivers/clk/sunxi-ng/ccu_nkm.c
+++ b/drivers/clk/sunxi-ng/ccu_nkm.c
@@ -6,6 +6,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
+#include <linux/math.h>
 
 #include "ccu_gate.h"
 #include "ccu_nkm.h"
@@ -16,10 +17,49 @@ struct _ccu_nkm {
 	unsigned long	m, min_m, max_m;
 };
 
-static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
-				       struct _ccu_nkm *nkm)
+static unsigned long optimal_parent_rate(unsigned long rate, unsigned long n,
+					 unsigned long k, unsigned long m)
 {
-	unsigned long best_rate = 0;
+	unsigned long _rate, parent;
+
+	// We must first try to find the desired parent rate that is rounded up, because there are
+	// cases where truncating makes us miss the requested rate.
+	// E.g. rate=449035712, n=11, k=3, m=16
+	// When truncating, we'd get parent=217714284 and calculating the rate from that would give
+	// us 449035710. When rounding up, we get parent=217714285 which would give us the requested
+	// rate of 449035712.
+	parent = DIV_ROUND_UP(rate * m, n * k);
+
+	// But there are other cases, where rounding up the parent gives us a too high rate.
+	// Therefore, we need to check for this case and, if necessary, truncate the parent rate
+	// instead of rounding up.
+	_rate = parent * n * k / m;
+	if (_rate > rate)
+		parent = rate * m / (n * k);
+	return parent;
+}
+
+/**
+ * ccu_nkm_find_best - Find the best nkm combination for a given rate
+ *
+ * @parent: rate of parent clock. This is used either as an input or out parameter:
+ *           - In cases where the parent clock can be set, this parameter will be updated to contain
+ *             the optimal rate for the parent to achieve the best rate for the nkm clock.
+ *           - In cases where the parent clock can not be set, this parameter must contain the
+ *             current rate of the parent, which is used to determine the best combination of n, k,
+ *             and m.
+ * @rate: requested rate.
+ * @nkm: Input/output parameter that contains the clocks constraints on the n, k, m combinations and
+ *       is updated in this function to contain the resulting best n, k, m combination.
+ * @parent_hw: parent clock. If set, this function assumes that the parent clock can be updated to a
+ *             rate that would be best to in order to get as close as possible to @rate. This
+ *             parameter must be set to NULL if this function shall not try to find the optimal
+ *             parent rate for the requested rate.
+ */
+static unsigned long ccu_nkm_find_best(unsigned long *parent, unsigned long rate,
+				       struct _ccu_nkm *nkm, struct clk_hw *parent_hw)
+{
+	unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent;
 	unsigned long best_n = 0, best_k = 0, best_m = 0;
 	unsigned long _n, _k, _m;
 
@@ -28,12 +68,17 @@ static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
 			for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
 				unsigned long tmp_rate;
 
-				tmp_rate = parent * _n * _k / _m;
-
+				if (parent_hw) {
+					tmp_parent = optimal_parent_rate(rate, _n, _k, _m);
+					tmp_parent = clk_hw_round_rate(parent_hw, tmp_parent);
+				}
+				tmp_rate = tmp_parent * _n * _k / _m;
 				if (tmp_rate > rate)
 					continue;
+
 				if ((rate - tmp_rate) < (rate - best_rate)) {
 					best_rate = tmp_rate;
+					best_parent_rate = tmp_parent;
 					best_n = _n;
 					best_k = _k;
 					best_m = _m;
@@ -46,6 +91,8 @@ static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
 	nkm->k = best_k;
 	nkm->m = best_m;
 
+	*parent = best_parent_rate;
+
 	return best_rate;
 }
 
@@ -106,7 +153,7 @@ static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw,
 }
 
 static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
-					struct clk_hw *hw,
+					struct clk_hw *parent_hw,
 					unsigned long *parent_rate,
 					unsigned long rate,
 					void *data)
@@ -124,7 +171,10 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
 	if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
 		rate *= nkm->fixed_post_div;
 
-	rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm);
+	if (!clk_hw_can_set_rate_parent(&nkm->common.hw))
+		rate = ccu_nkm_find_best(parent_rate, rate, &_nkm, NULL);
+	else
+		rate = ccu_nkm_find_best(parent_rate, rate, &_nkm, parent_hw);
 
 	if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
 		rate /= nkm->fixed_post_div;
@@ -159,7 +209,7 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
 	_nkm.min_m = 1;
 	_nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;
 
-	ccu_nkm_find_best(parent_rate, rate, &_nkm);
+	ccu_nkm_find_best(&parent_rate, rate, &_nkm, NULL);
 
 	spin_lock_irqsave(nkm->common.lock, flags);
 
-- 
2.41.0


  reply	other threads:[~2023-06-11  9:02 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-11  9:01 [PATCH v2 0/2] clk: sunxi-ng: Consider alternative parent rates when determining NKM clock rate Frank Oltmanns
2023-06-11  9:01 ` Frank Oltmanns [this message]
2023-06-12  8:51   ` [PATCH v2 1/2] clk: sunxi-ng: nkm: consider alternative parent rates when finding rate Frank Oltmanns
2023-06-12 12:31     ` Maxime Ripard
2023-06-25 10:45       ` Frank Oltmanns
2023-06-25 10:45         ` Frank Oltmanns
2023-06-26 16:50         ` Maxime Ripard
2023-06-26 16:50           ` Maxime Ripard
2023-06-12 12:21   ` Maxime Ripard
2023-06-11  9:01 ` [PATCH v2 2/2] clk: sunxi-ng: a64: allow pll-mipi to set parent's rate Frank Oltmanns

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230611090143.132257-2-frank@oltmanns.dev \
    --to=frank@oltmanns.dev \
    --cc=andre.przywara@arm.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sunxi@lists.linux.dev \
    --cc=maxime@cerno.tech \
    --cc=me@crly.cz \
    --cc=mturquette@baylibre.com \
    --cc=samuel@sholland.org \
    --cc=sboyd@kernel.org \
    --cc=wens@csie.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.