Thread (19 messages) 19 messages, 3 authors, 2015-12-06

Re: [PATCH v2 2/3] clk: bcm2835: Support for clock parent selection

From: Remi Pommarel <hidden>
Date: 2015-12-04 20:36:41
Also in: lkml
Subsystem: common clk framework, the rest · Maintainers: Michael Turquette, Stephen Boyd, Linus Torvalds

On Thu, Dec 03, 2015 at 04:37:07PM -0800, Eric Anholt wrote:
Remi Pommarel [off-list ref] writes:
quoted
On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:

[...]
quoted
quoted
+static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+		struct clk_rate_request *req)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct clk_hw *parent, *best_parent = NULL;
+	struct clk_rate_request parent_req;
+	unsigned long rate, best_rate = 0;
+	unsigned long prate, best_prate = 0;
+	size_t i;
+	u32 div;
+
+	/*
+	 * Select parent clock that results in the closest but lower rate
+	 */
+	for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
+		parent = clk_hw_get_parent_by_index(hw, i);
+		if (!parent)
+			continue;
+		parent_req = *req;
parent_req appears dead, so it should be removed.
Yes, will do thanks.
quoted
quoted
+		prate = clk_hw_get_rate(parent);
+		div = bcm2835_clock_choose_div(hw, req->rate, prate);
+		rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+		if (rate > best_rate && rate <= req->rate) {
+			best_parent = parent;
+			best_prate = prate;
+			best_rate = rate;
+		}
+	}
+
+	if (!best_parent)
+		return -EINVAL;
+
+	req->best_parent_hw = best_parent;
+	req->best_parent_rate = best_prate;
I think you're supposed to req->rate = best_rate, here, too.  With these
two fixes,
I did not set req->rate to best_rate in order to avoid rounding down
twice the actual clock rate.

Indeed with patch 1 from this patchset bcm2835_clock_choose_div()
chooses a divisor that produces a rate lower or equal to the requested
one. As we call bcm2835_clock_choose_div() twice when using
clk_set_rate() (once with ->determine_rate() and once with ->set_rate()),
if I set req->rate in bcm2835_clock_determine_rate to the rounded down
one, the final rate will likely be again rounded down in
bcm2835_clock_set_rate().
If we pass bcm2835_clock_rate_from_divisor(bcm2835_clock_choose_div()),
to bcm2835_clock_choose_div(), will it actually give a different divisor
than the first call?  (That seems like an unfortunate problem in our
implementation, if so).
Unfortunately yes. Because we want the divided rate to be lower or equal
to the expected one, I round up the div each time the div_64() produces a
reminder. Thus calling bcm2835_clock_choose_div() with
bcm2835_clock_rate_from_divisor(bcm2835_clock_choose_div()) will still
likely see a reminder from div_64().
I'd be willing to go along with this, but if so I'd like a comment
explaining why we aren't setting the field that we should pretty
obviously be setting.
I can either put a comment here explaining why we do not update
req->rate or do as the patch attached at the end.

This patch adds an argument to bcm2835_clock_choose_div() to switch on or
off the div round up. Then bcm2835_clock_determine_rate() could choose
the appropriate divisor that produces the highest lower rate while
bcm2835_clock_set_rate() can actually set the divisor which will remain
the same.

On second though I prefer the second solution. What do you think ?

Thanks.

Best Regards,

-- 
Remi

---------------------------------->8------------------------------
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 08ae4f6..1b0803c 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1158,7 +1158,8 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)

 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
                                    unsigned long rate,
-                                   unsigned long parent_rate)
+                                   unsigned long parent_rate,
+                                   int round_up)
 {
        struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
        const struct bcm2835_clock_data *data = clock->data;
@@ -1172,7 +1173,7 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
        div = temp;

        /* Round up and mask off the unused bits */
-       if ((div & unused_frac_mask) != 0 || rem != 0)
+       if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
                div += unused_frac_mask + 1;
        div &= ~unused_frac_mask;
@@ -1272,7 +1273,7 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
        struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
        struct bcm2835_cprman *cprman = clock->cprman;
        const struct bcm2835_clock_data *data = clock->data;
-       u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
+       u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, 0);

        cprman_write(cprman, data->div_reg, div);
@@ -1297,7 +1298,7 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
                if (!parent)
                        continue;
                prate = clk_hw_get_rate(parent);
-               div = bcm2835_clock_choose_div(hw, req->rate, prate);
+               div = bcm2835_clock_choose_div(hw, req->rate, prate, 1);
                rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
                if (rate > best_rate && rate <= req->rate) {
                        best_parent = parent;
@@ -1312,6 +1313,8 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
        req->best_parent_hw = best_parent;
        req->best_parent_rate = best_prate;

+       req->rate = best_rate;
+
        return 0;
 }
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help