All of lore.kernel.org
 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:11 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 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.