linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements
@ 2021-04-01 13:01 Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 1/5] clk: renesas: div6: Use clamp() instead of clamp_t() Geert Uytterhoeven
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2021-04-01 13:01 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-renesas-soc, linux-clk, Geert Uytterhoeven

	Hi Mike, Stephen,

This patch series converts the Renesas DIV6 clock driver from the old
.round_rate() callback to the newer .determine_rate() callback, and
improves the driver to switch parent clocks.

This has been tested on R-Car Gen2, R-Car Gen3, SH-Mobile AG5, R-Mobile
A1, and R-Mobile APE6.

I plan to queue this series in renesas-clk for v5.14.

Thanks for your comments!

Geert Uytterhoeven (5):
  clk: renesas: div6: Use clamp() instead of clamp_t()
  clk: renesas: div6: Simplify src mask handling
  clk: renesas: div6: Switch to .determine_rate()
  clk: renesas: div6: Consider all parents for requested rate
  clk: renesas: div6: Implement range checking

 drivers/clk/renesas/clk-div6.c | 80 +++++++++++++++++++++++-----------
 1 file changed, 54 insertions(+), 26 deletions(-)

-- 
2.25.1

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] clk: renesas: div6: Use clamp() instead of clamp_t()
  2021-04-01 13:01 [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements Geert Uytterhoeven
@ 2021-04-01 13:01 ` Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 2/5] clk: renesas: div6: Simplify src mask handling Geert Uytterhoeven
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2021-04-01 13:01 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-renesas-soc, linux-clk, Geert Uytterhoeven

As "div" is already "unsigned int", adding "U" suffixes to the constants
"1" and "64" allows us to replace the call to clamp_t() by a call to
clamp().  This removes hidden casts, and thus helps the compiler doing a
better job at type-checking.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/clk/renesas/clk-div6.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index 8fb68e703a6bab8c..a3c4fbeb7b0d2ec0 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -99,7 +99,7 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
 		rate = 1;
 
 	div = DIV_ROUND_CLOSEST(parent_rate, rate);
-	return clamp_t(unsigned int, div, 1, 64);
+	return clamp(div, 1U, 64U);
 }
 
 static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] clk: renesas: div6: Simplify src mask handling
  2021-04-01 13:01 [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 1/5] clk: renesas: div6: Use clamp() instead of clamp_t() Geert Uytterhoeven
@ 2021-04-01 13:01 ` Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 3/5] clk: renesas: div6: Switch to .determine_rate() Geert Uytterhoeven
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2021-04-01 13:01 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-renesas-soc, linux-clk, Geert Uytterhoeven

Simplify the handling of the register bits to select the parent clock,
by storing a bitmask instead of separate shift and width values.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/clk/renesas/clk-div6.c | 31 +++++++++++--------------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index a3c4fbeb7b0d2ec0..2920bec49bce0eb8 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -28,8 +28,7 @@
  * @hw: handle between common and hardware-specific interfaces
  * @reg: IO-remapped register
  * @div: divisor value (1-64)
- * @src_shift: Shift to access the register bits to select the parent clock
- * @src_width: Number of register bits to select the parent clock (may be 0)
+ * @src_mask: Bitmask covering the register bits to select the parent clock
  * @nb: Notifier block to save/restore clock state for system resume
  * @parents: Array to map from valid parent clocks indices to hardware indices
  */
@@ -37,8 +36,7 @@ struct div6_clock {
 	struct clk_hw hw;
 	void __iomem *reg;
 	unsigned int div;
-	u32 src_shift;
-	u32 src_width;
+	u32 src_mask;
 	struct notifier_block nb;
 	u8 parents[];
 };
@@ -133,11 +131,11 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
 	unsigned int i;
 	u8 hw_index;
 
-	if (clock->src_width == 0)
+	if (clock->src_mask == 0)
 		return 0;
 
-	hw_index = (readl(clock->reg) >> clock->src_shift) &
-		   (BIT(clock->src_width) - 1);
+	hw_index = (readl(clock->reg) & clock->src_mask) >>
+		   __ffs(clock->src_mask);
 	for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
 		if (clock->parents[i] == hw_index)
 			return i;
@@ -151,18 +149,13 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
 static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index)
 {
 	struct div6_clock *clock = to_div6_clock(hw);
-	u8 hw_index;
-	u32 mask;
+	u32 src;
 
 	if (index >= clk_hw_get_num_parents(hw))
 		return -EINVAL;
 
-	mask = ~((BIT(clock->src_width) - 1) << clock->src_shift);
-	hw_index = clock->parents[index];
-
-	writel((readl(clock->reg) & mask) | (hw_index << clock->src_shift),
-	       clock->reg);
-
+	src = clock->parents[index] << __ffs(clock->src_mask);
+	writel((readl(clock->reg) & ~clock->src_mask) | src, clock->reg);
 	return 0;
 }
 
@@ -236,17 +229,15 @@ struct clk * __init cpg_div6_register(const char *name,
 	switch (num_parents) {
 	case 1:
 		/* fixed parent clock */
-		clock->src_shift = clock->src_width = 0;
+		clock->src_mask = 0;
 		break;
 	case 4:
 		/* clock with EXSRC bits 6-7 */
-		clock->src_shift = 6;
-		clock->src_width = 2;
+		clock->src_mask = GENMASK(7, 6);
 		break;
 	case 8:
 		/* VCLK with EXSRC bits 12-14 */
-		clock->src_shift = 12;
-		clock->src_width = 3;
+		clock->src_mask = GENMASK(14, 12);
 		break;
 	default:
 		pr_err("%s: invalid number of parents for DIV6 clock %s\n",
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] clk: renesas: div6: Switch to .determine_rate()
  2021-04-01 13:01 [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 1/5] clk: renesas: div6: Use clamp() instead of clamp_t() Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 2/5] clk: renesas: div6: Simplify src mask handling Geert Uytterhoeven
@ 2021-04-01 13:01 ` Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 4/5] clk: renesas: div6: Consider all parents for requested rate Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 5/5] clk: renesas: div6: Implement range checking Geert Uytterhoeven
  4 siblings, 0 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2021-04-01 13:01 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-renesas-soc, linux-clk, Geert Uytterhoeven

As the .round_rate() callback returns a long clock rate, it cannot
return clock rates that do not fit in signed long, but do fit in
unsigned long.  Hence switch the DIV6 clocks on SH/R-Mobile and R-Car
SoCs from the old .round_rate() callback to the newer .determine_rate()
callback, which does not suffer from this limitation.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/clk/renesas/clk-div6.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index 2920bec49bce0eb8..3af65ef5690e3d84 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -100,12 +100,14 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
 	return clamp(div, 1U, 64U);
 }
 
-static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate,
-				      unsigned long *parent_rate)
+static int cpg_div6_clock_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
 {
-	unsigned int div = cpg_div6_clock_calc_div(rate, *parent_rate);
+	unsigned int div = cpg_div6_clock_calc_div(req->rate,
+						   req->best_parent_rate);
 
-	return *parent_rate / div;
+	req->rate = req->best_parent_rate / div;
+	return 0;
 }
 
 static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -166,7 +168,7 @@ static const struct clk_ops cpg_div6_clock_ops = {
 	.get_parent = cpg_div6_clock_get_parent,
 	.set_parent = cpg_div6_clock_set_parent,
 	.recalc_rate = cpg_div6_clock_recalc_rate,
-	.round_rate = cpg_div6_clock_round_rate,
+	.determine_rate = cpg_div6_clock_determine_rate,
 	.set_rate = cpg_div6_clock_set_rate,
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] clk: renesas: div6: Consider all parents for requested rate
  2021-04-01 13:01 [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements Geert Uytterhoeven
                   ` (2 preceding siblings ...)
  2021-04-01 13:01 ` [PATCH 3/5] clk: renesas: div6: Switch to .determine_rate() Geert Uytterhoeven
@ 2021-04-01 13:01 ` Geert Uytterhoeven
  2021-04-01 13:01 ` [PATCH 5/5] clk: renesas: div6: Implement range checking Geert Uytterhoeven
  4 siblings, 0 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2021-04-01 13:01 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-renesas-soc, linux-clk, Geert Uytterhoeven

Currently the .determine_rate() callback considers only the current
parent clock, limiting the range of achievable clock rates on DIV6
clocks with multiple parents, as found on SH/R-Mobile SoCs.

Extend the callback to consider all available parent clocks.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/clk/renesas/clk-div6.c | 35 +++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index 3af65ef5690e3d84..a9ac2a83c1d0daa0 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -103,10 +103,39 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
 static int cpg_div6_clock_determine_rate(struct clk_hw *hw,
 					 struct clk_rate_request *req)
 {
-	unsigned int div = cpg_div6_clock_calc_div(req->rate,
-						   req->best_parent_rate);
+	unsigned long prate, calc_rate, diff, best_rate, best_prate;
+	unsigned int num_parents = clk_hw_get_num_parents(hw);
+	struct clk_hw *parent, *best_parent = NULL;
+	unsigned long min_diff = ULONG_MAX;
+	unsigned int i, div;
+
+	for (i = 0; i < num_parents; i++) {
+		parent = clk_hw_get_parent_by_index(hw, i);
+		if (!parent)
+			continue;
+
+		prate = clk_hw_get_rate(parent);
+		if (!prate)
+			continue;
+
+		div = cpg_div6_clock_calc_div(req->rate, prate);
+		calc_rate = prate / div;
+		diff = calc_rate > req->rate ? calc_rate - req->rate
+					     : req->rate - calc_rate;
+		if (diff < min_diff) {
+			best_rate = calc_rate;
+			best_parent = parent;
+			best_prate = prate;
+			min_diff = diff;
+		}
+	}
+
+	if (!best_parent)
+		return -EINVAL;
 
-	req->rate = req->best_parent_rate / div;
+	req->best_parent_rate = best_prate;
+	req->best_parent_hw = best_parent;
+	req->rate = best_rate;
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] clk: renesas: div6: Implement range checking
  2021-04-01 13:01 [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements Geert Uytterhoeven
                   ` (3 preceding siblings ...)
  2021-04-01 13:01 ` [PATCH 4/5] clk: renesas: div6: Consider all parents for requested rate Geert Uytterhoeven
@ 2021-04-01 13:01 ` Geert Uytterhoeven
  4 siblings, 0 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2021-04-01 13:01 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-renesas-soc, linux-clk, Geert Uytterhoeven

Consider the minimum and maximum clock rates imposed by clock users when
calculating the most appropriate clock rate in the .determine_rate()
callback.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/clk/renesas/clk-div6.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index a9ac2a83c1d0daa0..3abd6e5400aded6a 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -106,8 +106,8 @@ static int cpg_div6_clock_determine_rate(struct clk_hw *hw,
 	unsigned long prate, calc_rate, diff, best_rate, best_prate;
 	unsigned int num_parents = clk_hw_get_num_parents(hw);
 	struct clk_hw *parent, *best_parent = NULL;
+	unsigned int i, min_div, max_div, div;
 	unsigned long min_diff = ULONG_MAX;
-	unsigned int i, div;
 
 	for (i = 0; i < num_parents; i++) {
 		parent = clk_hw_get_parent_by_index(hw, i);
@@ -118,7 +118,13 @@ static int cpg_div6_clock_determine_rate(struct clk_hw *hw,
 		if (!prate)
 			continue;
 
+		min_div = max(DIV_ROUND_UP(prate, req->max_rate), 1UL);
+		max_div = req->min_rate ? min(prate / req->min_rate, 64UL) : 64;
+		if (max_div < min_div)
+			continue;
+
 		div = cpg_div6_clock_calc_div(req->rate, prate);
+		div = clamp(div, min_div, max_div);
 		calc_rate = prate / div;
 		diff = calc_rate > req->rate ? calc_rate - req->rate
 					     : req->rate - calc_rate;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-04-01 18:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-01 13:01 [PATCH 0/5] clk: renesas: div6: .determine_rate() conversion and improvements Geert Uytterhoeven
2021-04-01 13:01 ` [PATCH 1/5] clk: renesas: div6: Use clamp() instead of clamp_t() Geert Uytterhoeven
2021-04-01 13:01 ` [PATCH 2/5] clk: renesas: div6: Simplify src mask handling Geert Uytterhoeven
2021-04-01 13:01 ` [PATCH 3/5] clk: renesas: div6: Switch to .determine_rate() Geert Uytterhoeven
2021-04-01 13:01 ` [PATCH 4/5] clk: renesas: div6: Consider all parents for requested rate Geert Uytterhoeven
2021-04-01 13:01 ` [PATCH 5/5] clk: renesas: div6: Implement range checking Geert Uytterhoeven

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).