2015-11-11 14:23:03

by Remi Pommarel

[permalink] [raw]
Subject: [PATCH v2 0/3] Add PWM clock support for bcm2835

Hi,

This patchset adds support for pwm clock. At boot, this clock does not have a
default parent nor a default rate set. Thus we should be able to change its
parent to get this clock working. The current clock implementation is using a
mux to select the parent, but these clocks need to add a password (0x5a) in
higher register bits when changing parent. So a generic mux cannot be used
here.

The two first patches fix the clock parent selection, while the second one is
actually adding the pwm clock registration.

Changes since v1:
- determine_rate now based its parent selection upon divided rate
instead of the parent one
- bcm2835_clock_choose_div has been modified to produce an avarage rate
lower or equal to the requested one
- devicetree modifications have removed to be send in another patch

Remi Pommarel (3):
clk: bcm2835: Always round up clock divisor
clk: bcm2835: Support for clock parent selection
clk: bcm2835: Add PWM clock support

drivers/clk/bcm/clk-bcm2835.c | 151 +++++++++++++++++++++++-------------
include/dt-bindings/clock/bcm2835.h | 3 +-
2 files changed, 101 insertions(+), 53 deletions(-)

--
2.0.1


2015-11-11 14:23:43

by Remi Pommarel

[permalink] [raw]
Subject: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

Make bcm2835_clock_choose_div always round up the chosen MASH divisor so that
the resulting average rate will not be higher than the requested one.

Signed-off-by: Remi Pommarel <[email protected]>
---
drivers/clk/bcm/clk-bcm2835.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39bf582..1237716 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
- u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
+ u32 unused_frac_mask =
+ GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+ u64 rem;
u32 div;

- do_div(temp, rate);
+ rem = do_div(temp, rate);
div = temp;

- /* Round and mask off the unused bits */
- if (unused_frac_mask != 0) {
- div += unused_frac_mask >> 1;
- div &= ~unused_frac_mask;
- }
+ /* Round up and mask off the unused bits */
+ if ((div & unused_frac_mask) != 0 || rem != 0)
+ div += unused_frac_mask + 1;
+ div &= ~unused_frac_mask;

/* Clamp to the limits. */
div = max(div, unused_frac_mask + 1);
--
2.0.1

2015-11-11 14:23:09

by Remi Pommarel

[permalink] [raw]
Subject: [PATCH v2 2/3] clk: bcm2835: Support for clock parent selection

Some bcm2835 clocks used by hardware (like "PWM" or "H264") can have multiple
parent clocks. These clocks divide the rate of a parent which can be selected by
setting the proper bits in the clock control register.

Previously all these parents where handled by a mux clock. But a mux clock
cannot be used because updating clock control register to select parent needs a
password to be xor'd with the parent index.

This patch get rid of mux clock and make these clocks handle their own parent,
allowing them to select the one to use.

Signed-off-by: Remi Pommarel <[email protected]>
---
drivers/clk/bcm/clk-bcm2835.c | 122 ++++++++++++++++++++++++++----------------
1 file changed, 77 insertions(+), 45 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 1237716..2b01a53 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1198,16 +1198,6 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
return temp;
}

-static long bcm2835_clock_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *parent_rate)
-{
- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
- u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
-
- return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
-}
-
static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -1279,13 +1269,75 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
return 0;
}

+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;
+ 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;
+
+ return 0;
+}
+
+static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+ const struct bcm2835_clock_data *data = clock->data;
+ u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
+
+ cprman_write(cprman, data->ctl_reg, src);
+ return 0;
+}
+
+static u8 bcm2835_clock_get_parent(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 src = cprman_read(cprman, data->ctl_reg);
+
+ return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+}
+
+
static const struct clk_ops bcm2835_clock_clk_ops = {
.is_prepared = bcm2835_clock_is_on,
.prepare = bcm2835_clock_on,
.unprepare = bcm2835_clock_off,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
- .round_rate = bcm2835_clock_round_rate,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
};

static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@@ -1301,7 +1353,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.is_prepared = bcm2835_vpu_clock_is_on,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
- .round_rate = bcm2835_clock_round_rate,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
};

static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@@ -1395,45 +1449,23 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
{
struct bcm2835_clock *clock;
struct clk_init_data init;
- const char *parent;
+ const char *parents[1 << CM_SRC_BITS];
+ size_t i;

/*
- * Most of the clock generators have a mux field, so we
- * instantiate a generic mux as our parent to handle it.
+ * Replace our "xosc" references with the oscillator's
+ * actual name.
*/
- if (data->num_mux_parents) {
- const char *parents[1 << CM_SRC_BITS];
- int i;
-
- parent = devm_kasprintf(cprman->dev, GFP_KERNEL,
- "mux_%s", data->name);
- if (!parent)
- return NULL;
-
- /*
- * Replace our "xosc" references with the oscillator's
- * actual name.
- */
- for (i = 0; i < data->num_mux_parents; i++) {
- if (strcmp(data->parents[i], "xosc") == 0)
- parents[i] = cprman->osc_name;
- else
- parents[i] = data->parents[i];
- }
-
- clk_register_mux(cprman->dev, parent,
- parents, data->num_mux_parents,
- CLK_SET_RATE_PARENT,
- cprman->regs + data->ctl_reg,
- CM_SRC_SHIFT, CM_SRC_BITS,
- 0, &cprman->regs_lock);
- } else {
- parent = data->parents[0];
+ for (i = 0; i < data->num_mux_parents; i++) {
+ if (strcmp(data->parents[i], "xosc") == 0)
+ parents[i] = cprman->osc_name;
+ else
+ parents[i] = data->parents[i];
}

memset(&init, 0, sizeof(init));
- init.parent_names = &parent;
- init.num_parents = 1;
+ init.parent_names = parents;
+ init.num_parents = data->num_mux_parents;
init.name = data->name;
init.flags = CLK_IGNORE_UNUSED;

--
2.0.1

2015-11-11 14:23:07

by Remi Pommarel

[permalink] [raw]
Subject: [PATCH v2 3/3] clk: bcm2835: Add PWM clock support

Register the pwm clock for bcm2835.

Signed-off-by: Remi Pommarel <[email protected]>
---
drivers/clk/bcm/clk-bcm2835.c | 14 ++++++++++++++
include/dt-bindings/clock/bcm2835.h | 3 ++-
2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 2b01a53..db378f3 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -39,6 +39,7 @@

#include <linux/clk-provider.h>
#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <linux/clk/bcm2835.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -807,6 +808,16 @@ static const struct bcm2835_clock_data bcm2835_clock_emmc_data = {
.frac_bits = 8,
};

+static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+ .name = "pwm",
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+ .parents = bcm2835_clock_per_parents,
+ .ctl_reg = CM_PWMCTL,
+ .div_reg = CM_PWMDIV,
+ .int_bits = 12,
+ .frac_bits = 12,
+};
+
struct bcm2835_pll {
struct clk_hw hw;
struct bcm2835_cprman *cprman;
@@ -1583,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
cprman->regs + CM_PERIICTL, CM_GATE_BIT,
0, &cprman->regs_lock);

+ clks[BCM2835_CLOCK_PWM] =
+ bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
+
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
&cprman->onecell);
}
diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h
index d323efa..61f1d20 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -43,5 +43,6 @@
#define BCM2835_CLOCK_TSENS 27
#define BCM2835_CLOCK_EMMC 28
#define BCM2835_CLOCK_PERI_IMAGE 29
+#define BCM2835_CLOCK_PWM 30

-#define BCM2835_CLOCK_COUNT 30
+#define BCM2835_CLOCK_COUNT 31
--
2.0.1

2015-11-18 18:25:51

by Eric Anholt

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

Remi Pommarel <[email protected]> writes:

> Make bcm2835_clock_choose_div always round up the chosen MASH divisor so that
> the resulting average rate will not be higher than the requested one.
>
> Signed-off-by: Remi Pommarel <[email protected]>
> ---
> drivers/clk/bcm/clk-bcm2835.c | 15 ++++++++-------
> 1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> index 39bf582..1237716 100644
> --- a/drivers/clk/bcm/clk-bcm2835.c
> +++ b/drivers/clk/bcm/clk-bcm2835.c
> @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
> {
> struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> const struct bcm2835_clock_data *data = clock->data;
> - u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> + u32 unused_frac_mask =
> + GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> + u64 rem;
> u32 div;
>
> - do_div(temp, rate);
> + rem = do_div(temp, rate);
> div = temp;
>
> - /* Round and mask off the unused bits */
> - if (unused_frac_mask != 0) {
> - div += unused_frac_mask >> 1;
> - div &= ~unused_frac_mask;
> - }
> + /* Round up and mask off the unused bits */
> + if ((div & unused_frac_mask) != 0 || rem != 0)
> + div += unused_frac_mask + 1;
> + div &= ~unused_frac_mask;

Suppose we've got 8 of our 12 frac bits populated. You've added a ">>
1" to the unused_frac_mask, so it's only 0x7 instead of 0xf. When you
say "round up", you add 0x8 (the high bit of the unused mask") then and
with ~0x7. If you started with 0x1 in the low bits of div, you'd end up
with 0x8, so you've set an unused bit instead of actually rounding up.

Did my logic work, here? I think you just want to drop the ">>1" in
unused_frac_mask.


Attachments:
signature.asc (818.00 B)

2015-11-18 18:30:22

by Eric Anholt

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

Remi Pommarel <[email protected]> writes:

> Some bcm2835 clocks used by hardware (like "PWM" or "H264") can have multiple
> parent clocks. These clocks divide the rate of a parent which can be selected by
> setting the proper bits in the clock control register.
>
> Previously all these parents where handled by a mux clock. But a mux clock
> cannot be used because updating clock control register to select parent needs a
> password to be xor'd with the parent index.
>
> This patch get rid of mux clock and make these clocks handle their own parent,
> allowing them to select the one to use.
>
> Signed-off-by: Remi Pommarel <[email protected]>
> ---
> drivers/clk/bcm/clk-bcm2835.c | 122 ++++++++++++++++++++++++++----------------
> 1 file changed, 77 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> index 1237716..2b01a53 100644
> --- a/drivers/clk/bcm/clk-bcm2835.c
> +++ b/drivers/clk/bcm/clk-bcm2835.c
> @@ -1198,16 +1198,6 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
> return temp;
> }
>
> -static long bcm2835_clock_round_rate(struct clk_hw *hw,
> - unsigned long rate,
> - unsigned long *parent_rate)
> -{
> - struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> - u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
> -
> - return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
> -}
> -
> static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
> unsigned long parent_rate)
> {
> @@ -1279,13 +1269,75 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
> return 0;
> }
>
> +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.

> + 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,

Reviewed-by: Eric Anholt <[email protected]>


Attachments:
signature.asc (818.00 B)

2015-11-18 18:32:59

by Eric Anholt

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] clk: bcm2835: Add PWM clock support

Remi Pommarel <[email protected]> writes:

> Register the pwm clock for bcm2835.
>
> Signed-off-by: Remi Pommarel <[email protected]>
> ---
> drivers/clk/bcm/clk-bcm2835.c | 14 ++++++++++++++
> include/dt-bindings/clock/bcm2835.h | 3 ++-
> 2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> index 2b01a53..db378f3 100644
> --- a/drivers/clk/bcm/clk-bcm2835.c
> +++ b/drivers/clk/bcm/clk-bcm2835.c
> @@ -39,6 +39,7 @@
>
> #include <linux/clk-provider.h>
> #include <linux/clkdev.h>
> +#include <linux/clk.h>

Stray new #include? With that dropped (assuming it's unnecessary),

Reviewed-by: Eric Anholt <[email protected]>


Attachments:
signature.asc (818.00 B)

2015-11-18 19:13:57

by Remi Pommarel

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

Hi,

On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
> Remi Pommarel <[email protected]> writes:
>
> > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so that
> > the resulting average rate will not be higher than the requested one.
> >
> > Signed-off-by: Remi Pommarel <[email protected]>
> > ---
> > drivers/clk/bcm/clk-bcm2835.c | 15 ++++++++-------
> > 1 file changed, 8 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > index 39bf582..1237716 100644
> > --- a/drivers/clk/bcm/clk-bcm2835.c
> > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
> > {
> > struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > const struct bcm2835_clock_data *data = clock->data;
> > - u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> > + u32 unused_frac_mask =
> > + GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> > u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> > + u64 rem;
> > u32 div;
> >
> > - do_div(temp, rate);
> > + rem = do_div(temp, rate);
> > div = temp;
> >
> > - /* Round and mask off the unused bits */
> > - if (unused_frac_mask != 0) {
> > - div += unused_frac_mask >> 1;
> > - div &= ~unused_frac_mask;
> > - }
> > + /* Round up and mask off the unused bits */
> > + if ((div & unused_frac_mask) != 0 || rem != 0)
> > + div += unused_frac_mask + 1;
> > + div &= ~unused_frac_mask;
>
> Suppose we've got 8 of our 12 frac bits populated. You've added a ">>
> 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf. When you
> say "round up", you add 0x8 (the high bit of the unused mask") then and
> with ~0x7. If you started with 0x1 in the low bits of div, you'd end up
> with 0x8, so you've set an unused bit instead of actually rounding up.
>
> Did my logic work, here? I think you just want to drop the ">>1" in
> unused_frac_mask.

I don't think so.

If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
be 0xf which is what we want here.

Thanks,

--
Remi Pommarel

2015-11-18 19:24:04

by Remi Pommarel

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

On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:

[...]

> > +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.

> > + 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().

Thanks,

--
RĂ©mi Pommarel

2015-11-18 19:25:50

by Remi Pommarel

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] clk: bcm2835: Add PWM clock support

On Wed, Nov 18, 2015 at 10:32:55AM -0800, Eric Anholt wrote:
> Remi Pommarel <[email protected]> writes:
>
> > Register the pwm clock for bcm2835.
> >
> > Signed-off-by: Remi Pommarel <[email protected]>
> > ---
> > drivers/clk/bcm/clk-bcm2835.c | 14 ++++++++++++++
> > include/dt-bindings/clock/bcm2835.h | 3 ++-
> > 2 files changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > index 2b01a53..db378f3 100644
> > --- a/drivers/clk/bcm/clk-bcm2835.c
> > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > @@ -39,6 +39,7 @@
> >
> > #include <linux/clk-provider.h>
> > #include <linux/clkdev.h>
> > +#include <linux/clk.h>
>
> Stray new #include? With that dropped (assuming it's unnecessary),

Good catch, will remove this. Thanks !

>
> Reviewed-by: Eric Anholt <[email protected]>
>

--
Remi Pommarel

2015-11-28 20:52:33

by Stefan Wahren

[permalink] [raw]
Subject: Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

Hi Remi,
hi Eric,

Am 11.11.2015 um 15:22 schrieb Remi Pommarel:
> Hi,
>
> This patchset adds support for pwm clock. At boot, this clock does not have a
> default parent nor a default rate set. Thus we should be able to change its
> parent to get this clock working. The current clock implementation is using a
> mux to select the parent, but these clocks need to add a password (0x5a) in
> higher register bits when changing parent. So a generic mux cannot be used
> here.
>
> The two first patches fix the clock parent selection, while the second one is
> actually adding the pwm clock registration.
>
> Changes since v1:
> - determine_rate now based its parent selection upon divided rate
> instead of the parent one
> - bcm2835_clock_choose_div has been modified to produce an avarage rate
> lower or equal to the requested one
> - devicetree modifications have removed to be send in another patch
>

i applied the series including the devicetree modification, but it
doesn't work for me.

First of all i get an ugly division by zero warning from the pwm driver.
The pwm driver still assume a fixed clock and doesn't handle the error
cases of clk_get_rate(). I attached a patch at the end.

The reason in my case why clk_get_rate() returns zero is that the pwm
clock is orphan ( pwm is listed under
/sys/kernel/debug/clk_orphan_summary ).

My suspicion is it has something to do with the clock manager driver.
The bcm2835_clock_per_parents contains only 8 entries. But according to
BCM2835-ARM-Peripherals.pdf [1] CM_GP0CTL SRC page 107 has 16 entries.
The upper 8 entries are all mapped to GND. It looks to me that the
driver doesn't take care of this and so the pwm clock isn't able to
determine it's parent.

Best regards
Stefan

[1] -
https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

---------------------------------->8------------------------------
diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index b4c7f95..49e28df 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -29,7 +29,6 @@
struct bcm2835_pwm {
struct pwm_chip chip;
struct device *dev;
- unsigned long scaler;
void __iomem *base;
struct clk *clk;
};
@@ -66,6 +65,15 @@ static int bcm2835_pwm_config(struct pwm_chip *chip,
struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
+ unsigned long rate = clk_get_rate(pc->clk);
+ unsigned long scaler;
+
+ if (rate <= 0) {
+ dev_err(pc->dev, "Invalid clock rate: %ld\n", rate);
+ return -EINVAL;
+ }
+
+ scaler = NSEC_PER_SEC / rate;

if (period_ns <= MIN_PERIOD) {
dev_err(pc->dev, "period %d not supported, minimum %d\n",
@@ -73,8 +81,8 @@ static int bcm2835_pwm_config(struct pwm_chip *chip,
struct pwm_device *pwm,
return -EINVAL;
}

- writel(duty_ns / pc->scaler, pc->base + DUTY(pwm->hwpwm));
- writel(period_ns / pc->scaler, pc->base + PERIOD(pwm->hwpwm));
+ writel(duty_ns / scaler, pc->base + DUTY(pwm->hwpwm));
+ writel(period_ns / scaler, pc->base + PERIOD(pwm->hwpwm));

return 0;
}
@@ -156,8 +164,6 @@ static int bcm2835_pwm_probe(struct platform_device
*pdev)
if (ret)
return ret;

- pc->scaler = NSEC_PER_SEC / clk_get_rate(pc->clk);
-
pc->chip.dev = &pdev->dev;
pc->chip.ops = &bcm2835_pwm_ops;
pc->chip.npwm = 2;


2015-11-29 00:33:44

by Remi Pommarel

[permalink] [raw]
Subject: Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

Hi Stefan,

On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
> i applied the series including the devicetree modification, but it
> doesn't work for me.
>
> First of all i get an ugly division by zero warning from the pwm
> driver. The pwm driver still assume a fixed clock and doesn't handle
> the error cases of clk_get_rate(). I attached a patch at the end.

Yes the devicetree patch from patchset version one does not work with
this version. I haven't sent the modified devicetree because Eric said
it is better to send it in a separate patchset. If you want to test it I
attached the working devicetree patch at the end.

But, yes, that would be nice if pwm driver was protected from this
division by zero.

>
> The reason in my case why clk_get_rate() returns zero is that the
> pwm clock is orphan ( pwm is listed under
> /sys/kernel/debug/clk_orphan_summary ).
>
> My suspicion is it has something to do with the clock manager driver.
> The bcm2835_clock_per_parents contains only 8 entries. But according to
> BCM2835-ARM-Peripherals.pdf [1] CM_GP0CTL SRC page 107 has 16
> entries. The upper 8 entries are all mapped to GND. It looks to me
> that the driver doesn't take care of this and so the pwm clock isn't
> able to determine it's parent.
>

In fact, default parent for pwm after boot up is GND (CM_GP0CTL SRC ==
0). Which means that the default pwm clock rate is 0. The clock appears
to be orphan because in the bcm2835 clock driver, the GND clock is not
registered.

So, IMHO, we have to set the default pwm rate from the devicetree, using
assigned-clock-rates. That what does the following dts patch.

This patch also set the gpio pin 18 to proper alternate function in order
to be able to get pwm output from this gpio.

Thanks

--
Remi

---------------------------------->8------------------------------
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index ff6b2d1..478aa79 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -13,5 +13,10 @@
};

&gpio {
- pinctrl-0 = <&gpioout &alt0 &alt3>;
+ pinctrl-0 = <&gpioout &alt0 &alt3 &gpiopwm>;
+
+ gpiopwm: pwm {
+ brcm,pins = <18>;
+ brcm,function = <BCM2835_FSEL_ALT5>;
+ };
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 3572f03..55801e0 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -60,3 +60,7 @@
status = "okay";
bus-width = <4>;
};
+
+&pwm {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index aef64de..567bd35 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -149,6 +149,15 @@
status = "disabled";
};

+ pwm: pwm@7e20c000 {
+ compatible = "brcm,bcm2835-pwm";
+ reg = <0x7e20c000 0x28>;
+ clocks = <&clocks BCM2835_CLOCK_PWM>;
+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
+ assigned-clock-rates = <9600000>;
+ status = "disabled";
+ };
+
sdhci: sdhci@7e300000 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;

2015-11-29 21:23:05

by Stefan Wahren

[permalink] [raw]
Subject: Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

Hi Remi,

Am 29.11.2015 um 01:31 schrieb Remi Pommarel:
> Hi Stefan,
>
> On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
>> i applied the series including the devicetree modification, but it
>> doesn't work for me.
>>
>> First of all i get an ugly division by zero warning from the pwm
>> driver. The pwm driver still assume a fixed clock and doesn't handle
>> the error cases of clk_get_rate(). I attached a patch at the end.
>
> Yes the devicetree patch from patchset version one does not work with
> this version.

thanks. I successfully tested the pwm with the led pwm driver.

> I haven't sent the modified devicetree because Eric said
> it is better to send it in a separate patchset. If you want to test it I
> attached the working devicetree patch at the end.

I don't think that he said that. He wanted you to send the devicetree
changes as a separate patch. So it should be okay if it's part of the
same patchset.

>
> But, yes, that would be nice if pwm driver was protected from this
> division by zero.

I will create a proper patch.

>
>>
>> The reason in my case why clk_get_rate() returns zero is that the
>> pwm clock is orphan ( pwm is listed under
>> /sys/kernel/debug/clk_orphan_summary ).
>>
>> My suspicion is it has something to do with the clock manager driver.
>> The bcm2835_clock_per_parents contains only 8 entries. But according to
>> BCM2835-ARM-Peripherals.pdf [1] CM_GP0CTL SRC page 107 has 16
>> entries. The upper 8 entries are all mapped to GND. It looks to me
>> that the driver doesn't take care of this and so the pwm clock isn't
>> able to determine it's parent.
>>
>
> In fact, default parent for pwm after boot up is GND (CM_GP0CTL SRC ==
> 0). Which means that the default pwm clock rate is 0. The clock appears
> to be orphan because in the bcm2835 clock driver, the GND clock is not
> registered.

Thanks for the explanation.

Best regards
Stefan

>
> So, IMHO, we have to set the default pwm rate from the devicetree, using
> assigned-clock-rates. That what does the following dts patch.
>
> This patch also set the gpio pin 18 to proper alternate function in order
> to be able to get pwm output from this gpio.
>
> Thanks
>

2015-11-29 22:25:25

by Remi Pommarel

[permalink] [raw]
Subject: Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

On Sun, Nov 29, 2015 at 10:22:40PM +0100, Stefan Wahren wrote:
> Hi Remi,
>
> Am 29.11.2015 um 01:31 schrieb Remi Pommarel:
> >Hi Stefan,
> >
> >On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
> >>i applied the series including the devicetree modification, but it
> >>doesn't work for me.
> >>
> >>First of all i get an ugly division by zero warning from the pwm
> >>driver. The pwm driver still assume a fixed clock and doesn't handle
> >>the error cases of clk_get_rate(). I attached a patch at the end.
> >
> >Yes the devicetree patch from patchset version one does not work with
> >this version.
>
> thanks. I successfully tested the pwm with the led pwm driver.
>

Good news, thank you.

> >I haven't sent the modified devicetree because Eric said
> >it is better to send it in a separate patchset. If you want to test it I
> >attached the working devicetree patch at the end.
>
> I don't think that he said that. He wanted you to send the
> devicetree changes as a separate patch. So it should be okay if it's
> part of the same patchset.
>

I could have misunderstood him, sorry about that. I will send a
devicetree separated patch with the next version if Eric agrees with the
GENMASK logic used in my first patch.

Best Regards,

--
Remi

2015-12-02 22:21:24

by Remi Pommarel

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

Hi Eric

On Wed, Nov 18, 2015 at 07:11:41PM -0100, Remi Pommarel wrote:
> On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
> > Remi Pommarel <[email protected]> writes:
> >
> > > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so that
> > > the resulting average rate will not be higher than the requested one.
> > >
> > > Signed-off-by: Remi Pommarel <[email protected]>
> > > ---
> > > drivers/clk/bcm/clk-bcm2835.c | 15 ++++++++-------
> > > 1 file changed, 8 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > > index 39bf582..1237716 100644
> > > --- a/drivers/clk/bcm/clk-bcm2835.c
> > > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
> > > {
> > > struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > > const struct bcm2835_clock_data *data = clock->data;
> > > - u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> > > + u32 unused_frac_mask =
> > > + GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> > > u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> > > + u64 rem;
> > > u32 div;
> > >
> > > - do_div(temp, rate);
> > > + rem = do_div(temp, rate);
> > > div = temp;
> > >
> > > - /* Round and mask off the unused bits */
> > > - if (unused_frac_mask != 0) {
> > > - div += unused_frac_mask >> 1;
> > > - div &= ~unused_frac_mask;
> > > - }
> > > + /* Round up and mask off the unused bits */
> > > + if ((div & unused_frac_mask) != 0 || rem != 0)
> > > + div += unused_frac_mask + 1;
> > > + div &= ~unused_frac_mask;
> >
> > Suppose we've got 8 of our 12 frac bits populated. You've added a ">>
> > 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf. When you
> > say "round up", you add 0x8 (the high bit of the unused mask") then and
> > with ~0x7. If you started with 0x1 in the low bits of div, you'd end up
> > with 0x8, so you've set an unused bit instead of actually rounding up.
> >
> > Did my logic work, here? I think you just want to drop the ">>1" in
> > unused_frac_mask.
>
> I don't think so.
>
> If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
> because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
> position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
> be 0xf which is what we want here.

Does my logic seems sensible to you or am I missing something ? I just
want to be sure we agree before I send another version for this
patchset.

Thanks.

Best Regards

--
Remi

2015-12-04 00:31:31

by Eric Anholt

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

Remi Pommarel <[email protected]> writes:

> Hi,
>
> On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
>> Remi Pommarel <[email protected]> writes:
>>
>> > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so that
>> > the resulting average rate will not be higher than the requested one.
>> >
>> > Signed-off-by: Remi Pommarel <[email protected]>
>> > ---
>> > drivers/clk/bcm/clk-bcm2835.c | 15 ++++++++-------
>> > 1 file changed, 8 insertions(+), 7 deletions(-)
>> >
>> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
>> > index 39bf582..1237716 100644
>> > --- a/drivers/clk/bcm/clk-bcm2835.c
>> > +++ b/drivers/clk/bcm/clk-bcm2835.c
>> > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
>> > {
>> > struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
>> > const struct bcm2835_clock_data *data = clock->data;
>> > - u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
>> > + u32 unused_frac_mask =
>> > + GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
>> > u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
>> > + u64 rem;
>> > u32 div;
>> >
>> > - do_div(temp, rate);
>> > + rem = do_div(temp, rate);
>> > div = temp;
>> >
>> > - /* Round and mask off the unused bits */
>> > - if (unused_frac_mask != 0) {
>> > - div += unused_frac_mask >> 1;
>> > - div &= ~unused_frac_mask;
>> > - }
>> > + /* Round up and mask off the unused bits */
>> > + if ((div & unused_frac_mask) != 0 || rem != 0)
>> > + div += unused_frac_mask + 1;
>> > + div &= ~unused_frac_mask;
>>
>> Suppose we've got 8 of our 12 frac bits populated. You've added a ">>
>> 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf. When you
>> say "round up", you add 0x8 (the high bit of the unused mask") then and
>> with ~0x7. If you started with 0x1 in the low bits of div, you'd end up
>> with 0x8, so you've set an unused bit instead of actually rounding up.
>>
>> Did my logic work, here? I think you just want to drop the ">>1" in
>> unused_frac_mask.
>
> I don't think so.
>
> If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
> because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
> position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
> be 0xf which is what we want here.

Oh, that was an existing bug you were fixing! You're right. I even got
the GENMASK call right at the end of the function, I'd just botched this
one.

Reviewed-by: Eric Anholt <[email protected]>


Attachments:
signature.asc (818.00 B)

2015-12-04 00:37:12

by Eric Anholt

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

Remi Pommarel <[email protected]> writes:

> On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:
>
> [...]
>
>> > +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.
>
>> > + 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).

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.


Attachments:
signature.asc (818.00 B)

2015-12-04 20:36:41

by Remi Pommarel

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

On Thu, Dec 03, 2015 at 04:37:07PM -0800, Eric Anholt wrote:
> Remi Pommarel <[email protected]> writes:
>
> > On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:
> >
> > [...]
> >
> >> > +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.
> >
> >> > + 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;
}

2015-12-06 00:19:20

by Eric Anholt

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

Remi Pommarel <[email protected]> writes:

> On Thu, Dec 03, 2015 at 04:37:07PM -0800, Eric Anholt wrote:
>> Remi Pommarel <[email protected]> writes:
>>
>> > On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:
>> >
>> > [...]
>> >
>> >> > +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.
>> >
>> >> > + 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 ?

Make "round_up" be bool and use true/false as its values, and it looks
good to me!


Attachments:
signature.asc (818.00 B)