On the 32-bit Amlogic Meson8/8b/8m2 SoCs we run into a problem with the
fast HDMI PLL and it's OD (post-dividers). This clock tree can run at
up to approx. 3GHz.
This however causes a problem, because these rates require BIT(31) to
be usable. Unfortunately this is not the case with clk_ops.round_rate
on 32-bit systems. BIT(31) is reserved for the sign (+ or -).
clk_ops.determine_rate does not suffer from this limitation. It uses
an int to signal any errors and can then take all availble 32 bits for
the clock rate.
Changes since v1 from [0]:
- reworked the first patch so the the existing
divider_{ro_}round_rate_parent implementations are using the new
divider_{ro_}determine_rate implementations to avoid code duplication
(thanks Jerome for the suggestion)
- added a patch to switch the default clk_divider_{ro_}ops to use
.determine_rate instead of .round_rate as suggested by Jerome
(thanks)
- dropped a patch for the Meson PLL ops as these are independent from
the divider patches and Jerome has applied that one directly (thanks)
- added Jerome's Reviewed-by to the meson clk-regmap patch (thanks!)
- dropped the RFC prefix
[0] https://patchwork.kernel.org/project/linux-clk/cover/[email protected]/
Martin Blumenstingl (3):
clk: divider: Add re-usable determine_rate implementations
clk: divider: Switch from .round_rate to .determine_rate by default
clk: meson: regmap: switch to determine_rate for the dividers
drivers/clk/clk-divider.c | 93 +++++++++++++++++++++++++---------
drivers/clk/meson/clk-regmap.c | 19 ++++---
include/linux/clk-provider.h | 6 +++
3 files changed, 85 insertions(+), 33 deletions(-)
--
2.31.1
This increases the maxmium supported frequency on 32-bit systems from
2^31 (signed long as used by clk_ops.round_rate, maximum value:
approx. 2.14GHz) to 2^32 (unsigned long as used by
clk_ops.determine_rate, maximum value: approx. 4.29GHz).
On Meson8/8b/8m2 the HDMI PLL and it's OD (post-dividers) are
capable of running at up to 2.97GHz. So switch the divider
implementation in clk-regmap to clk_ops.determine_rate to support these
higher frequencies on 32-bit systems.
Reviewed-by: Jerome Brunet <[email protected]>
Signed-off-by: Martin Blumenstingl <[email protected]>
---
drivers/clk/meson/clk-regmap.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c
index dcd1757cc5df..8ad8977cf1c2 100644
--- a/drivers/clk/meson/clk-regmap.c
+++ b/drivers/clk/meson/clk-regmap.c
@@ -75,8 +75,8 @@ static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
div->width);
}
-static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int clk_regmap_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
@@ -87,18 +87,17 @@ static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate,
if (div->flags & CLK_DIVIDER_READ_ONLY) {
ret = regmap_read(clk->map, div->offset, &val);
if (ret)
- /* Gives a hint that something is wrong */
- return 0;
+ return ret;
val >>= div->shift;
val &= clk_div_mask(div->width);
- return divider_ro_round_rate(hw, rate, prate, div->table,
- div->width, div->flags, val);
+ return divider_ro_determine_rate(hw, req, div->table,
+ div->width, div->flags, val);
}
- return divider_round_rate(hw, rate, prate, div->table, div->width,
- div->flags);
+ return divider_determine_rate(hw, req, div->table, div->width,
+ div->flags);
}
static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -123,14 +122,14 @@ static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops clk_regmap_divider_ops = {
.recalc_rate = clk_regmap_div_recalc_rate,
- .round_rate = clk_regmap_div_round_rate,
+ .determine_rate = clk_regmap_div_determine_rate,
.set_rate = clk_regmap_div_set_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
const struct clk_ops clk_regmap_divider_ro_ops = {
.recalc_rate = clk_regmap_div_recalc_rate,
- .round_rate = clk_regmap_div_round_rate,
+ .determine_rate = clk_regmap_div_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops);
--
2.31.1
These are useful when running on 32-bit systems to increase the upper
supported frequency limit. clk_ops.round_rate returns a signed long
which limits the maximum rate on 32-bit systems to 2^31 (or approx.
2.14GHz). clk_ops.determine_rate internally uses an unsigned long so
the maximum rate on 32-bit systems is 2^32 or approx. 4.29GHz.
To avoid code-duplication switch over divider_{ro_,}round_rate_parent
to use the new divider_{ro_,}determine_rate functions.
Signed-off-by: Martin Blumenstingl <[email protected]>
---
drivers/clk/clk-divider.c | 75 +++++++++++++++++++++++++++++-------
include/linux/clk-provider.h | 6 +++
2 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 344997203f0e..87ba4966b0e8 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -343,16 +343,63 @@ static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
return bestdiv;
}
+int divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
+{
+ int div;
+
+ div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate,
+ &req->best_parent_rate, table, width, flags);
+
+ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(divider_determine_rate);
+
+int divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags, unsigned int val)
+{
+ int div;
+
+ div = _get_div(table, val, flags, width);
+
+ /* Even a read-only clock can propagate a rate change */
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+ if (!req->best_parent_hw)
+ return -EINVAL;
+
+ req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw,
+ req->rate * div);
+ }
+
+ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(divider_ro_determine_rate);
+
long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long rate, unsigned long *prate,
const struct clk_div_table *table,
u8 width, unsigned long flags)
{
- int div;
+ struct clk_rate_request req = {
+ .rate = rate,
+ .best_parent_rate = *prate,
+ .best_parent_hw = parent,
+ };
+ int ret;
- div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags);
+ ret = divider_determine_rate(hw, &req, table, width, flags);
+ if (ret)
+ return ret;
- return DIV_ROUND_UP_ULL((u64)*prate, div);
+ *prate = req.best_parent_rate;
+
+ return req.rate;
}
EXPORT_SYMBOL_GPL(divider_round_rate_parent);
@@ -361,23 +408,23 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
const struct clk_div_table *table, u8 width,
unsigned long flags, unsigned int val)
{
- int div;
-
- div = _get_div(table, val, flags, width);
+ struct clk_rate_request req = {
+ .rate = rate,
+ .best_parent_rate = *prate,
+ .best_parent_hw = parent,
+ };
+ int ret;
- /* Even a read-only clock can propagate a rate change */
- if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
- if (!parent)
- return -EINVAL;
+ ret = divider_ro_determine_rate(hw, &req, table, width, flags, val);
+ if (ret)
+ return ret;
- *prate = clk_hw_round_rate(parent, rate * div);
- }
+ *prate = req.best_parent_rate;
- return DIV_ROUND_UP_ULL((u64)*prate, div);
+ return req.rate;
}
EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
-
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 162a2e5546a3..d83b829305c0 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -629,6 +629,12 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long rate, unsigned long *prate,
const struct clk_div_table *table, u8 width,
unsigned long flags, unsigned int val);
+int divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags);
+int divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags, unsigned int val);
int divider_get_val(unsigned long rate, unsigned long parent_rate,
const struct clk_div_table *table, u8 width,
unsigned long flags);
--
2.31.1
.determine_rate is meant to replace .round_rate. The former comes with a
benefit which is especially relevant on 32-bit systems: since
.determine_rate uses an "unsigned long" (compared to a "signed long"
which is used by .round_rate) the maximum value on 32-bit systems
increases from 2^31 (or approx. 2.14GHz) to 2^32 (or approx. 4.29GHz).
Switch to a .determine_rate implementation by default so 32-bit systems
can benefit from the increased maximum value as well as so we have one
fewer user of .round_rate.
Signed-off-by: Martin Blumenstingl <[email protected]>
---
drivers/clk/clk-divider.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 87ba4966b0e8..9e05e81116af 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -425,8 +425,8 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
}
EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
-static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int clk_divider_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_divider *divider = to_clk_divider(hw);
@@ -437,13 +437,13 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
val = clk_div_readl(divider) >> divider->shift;
val &= clk_div_mask(divider->width);
- return divider_ro_round_rate(hw, rate, prate, divider->table,
- divider->width, divider->flags,
- val);
+ return divider_ro_determine_rate(hw, req, divider->table,
+ divider->width,
+ divider->flags, val);
}
- return divider_round_rate(hw, rate, prate, divider->table,
- divider->width, divider->flags);
+ return divider_determine_rate(hw, req, divider->table, divider->width,
+ divider->flags);
}
int divider_get_val(unsigned long rate, unsigned long parent_rate,
@@ -500,14 +500,14 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops clk_divider_ops = {
.recalc_rate = clk_divider_recalc_rate,
- .round_rate = clk_divider_round_rate,
+ .determine_rate = clk_divider_determine_rate,
.set_rate = clk_divider_set_rate,
};
EXPORT_SYMBOL_GPL(clk_divider_ops);
const struct clk_ops clk_divider_ro_ops = {
.recalc_rate = clk_divider_recalc_rate,
- .round_rate = clk_divider_round_rate,
+ .determine_rate = clk_divider_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
--
2.31.1
Hi Jerome, Hi Stephen,
On Mon, May 24, 2021 at 12:37 PM Martin Blumenstingl
<[email protected]> wrote:
>
> On the 32-bit Amlogic Meson8/8b/8m2 SoCs we run into a problem with the
> fast HDMI PLL and it's OD (post-dividers). This clock tree can run at
> up to approx. 3GHz.
> This however causes a problem, because these rates require BIT(31) to
> be usable. Unfortunately this is not the case with clk_ops.round_rate
> on 32-bit systems. BIT(31) is reserved for the sign (+ or -).
>
> clk_ops.determine_rate does not suffer from this limitation. It uses
> an int to signal any errors and can then take all availble 32 bits for
> the clock rate.
>
> Changes since v1 from [0]:
> - reworked the first patch so the the existing
> divider_{ro_}round_rate_parent implementations are using the new
> divider_{ro_}determine_rate implementations to avoid code duplication
> (thanks Jerome for the suggestion)
> - added a patch to switch the default clk_divider_{ro_}ops to use
> .determine_rate instead of .round_rate as suggested by Jerome
> (thanks)
> - dropped a patch for the Meson PLL ops as these are independent from
> the divider patches and Jerome has applied that one directly (thanks)
> - added Jerome's Reviewed-by to the meson clk-regmap patch (thanks!)
> - dropped the RFC prefix
please let me know what you think about this v2
I am asking because clk-divider is widely used, so I'd appreciate if
this gets some time in linux-next (so for example Kernel CI can test
this and report issues if there are any).
Best regards,
Martin
On Fri 04 Jun 2021 at 19:18, Martin Blumenstingl <[email protected]> wrote:
> Hi Jerome, Hi Stephen,
>
> On Mon, May 24, 2021 at 12:37 PM Martin Blumenstingl
> <[email protected]> wrote:
>>
>> On the 32-bit Amlogic Meson8/8b/8m2 SoCs we run into a problem with the
>> fast HDMI PLL and it's OD (post-dividers). This clock tree can run at
>> up to approx. 3GHz.
>> This however causes a problem, because these rates require BIT(31) to
>> be usable. Unfortunately this is not the case with clk_ops.round_rate
>> on 32-bit systems. BIT(31) is reserved for the sign (+ or -).
>>
>> clk_ops.determine_rate does not suffer from this limitation. It uses
>> an int to signal any errors and can then take all availble 32 bits for
>> the clock rate.
>>
>> Changes since v1 from [0]:
>> - reworked the first patch so the the existing
>> divider_{ro_}round_rate_parent implementations are using the new
>> divider_{ro_}determine_rate implementations to avoid code duplication
>> (thanks Jerome for the suggestion)
>> - added a patch to switch the default clk_divider_{ro_}ops to use
>> .determine_rate instead of .round_rate as suggested by Jerome
>> (thanks)
>> - dropped a patch for the Meson PLL ops as these are independent from
>> the divider patches and Jerome has applied that one directly (thanks)
>> - added Jerome's Reviewed-by to the meson clk-regmap patch (thanks!)
>> - dropped the RFC prefix
> please let me know what you think about this v2
> I am asking because clk-divider is widely used, so I'd appreciate if
> this gets some time in linux-next (so for example Kernel CI can test
> this and report issues if there are any).
>
Looks good to me
Reviewed-by: Jerome Brunet <[email protected]>
>
> Best regards,
> Martin
Hi Stephen,
On Mon, Jun 7, 2021 at 9:04 AM Jerome Brunet <[email protected]> wrote:
>
>
> On Fri 04 Jun 2021 at 19:18, Martin Blumenstingl <[email protected]> wrote:
>
> > Hi Jerome, Hi Stephen,
> >
> > On Mon, May 24, 2021 at 12:37 PM Martin Blumenstingl
> > <[email protected]> wrote:
> >>
> >> On the 32-bit Amlogic Meson8/8b/8m2 SoCs we run into a problem with the
> >> fast HDMI PLL and it's OD (post-dividers). This clock tree can run at
> >> up to approx. 3GHz.
> >> This however causes a problem, because these rates require BIT(31) to
> >> be usable. Unfortunately this is not the case with clk_ops.round_rate
> >> on 32-bit systems. BIT(31) is reserved for the sign (+ or -).
> >>
> >> clk_ops.determine_rate does not suffer from this limitation. It uses
> >> an int to signal any errors and can then take all availble 32 bits for
> >> the clock rate.
> >>
> >> Changes since v1 from [0]:
> >> - reworked the first patch so the the existing
> >> divider_{ro_}round_rate_parent implementations are using the new
> >> divider_{ro_}determine_rate implementations to avoid code duplication
> >> (thanks Jerome for the suggestion)
> >> - added a patch to switch the default clk_divider_{ro_}ops to use
> >> .determine_rate instead of .round_rate as suggested by Jerome
> >> (thanks)
> >> - dropped a patch for the Meson PLL ops as these are independent from
> >> the divider patches and Jerome has applied that one directly (thanks)
> >> - added Jerome's Reviewed-by to the meson clk-regmap patch (thanks!)
> >> - dropped the RFC prefix
> > please let me know what you think about this v2
> > I am asking because clk-divider is widely used, so I'd appreciate if
> > this gets some time in linux-next (so for example Kernel CI can test
> > this and report issues if there are any).
Do you have any comments on this series?
I am fine with it skipping 5.14 as it's a change which affects
multiple platforms.
So I would like to use the time until the trees are opening for
patches targeting 5.15 to iron out code-review comments.
> Looks good to me
> Reviewed-by: Jerome Brunet <[email protected]>
Thanks Jerome - I'll add it to v3 once I send it (assuming nothing
major changes)
Best regards,
Martin
Quoting Martin Blumenstingl (2021-06-22 14:04:55)
> Hi Stephen,
>
> On Mon, Jun 7, 2021 at 9:04 AM Jerome Brunet <[email protected]> wrote:
> >
> >
> > On Fri 04 Jun 2021 at 19:18, Martin Blumenstingl <[email protected]> wrote:
> >
> > > Hi Jerome, Hi Stephen,
> > >
> > > On Mon, May 24, 2021 at 12:37 PM Martin Blumenstingl
> > > <[email protected]> wrote:
> > >>
> > >> On the 32-bit Amlogic Meson8/8b/8m2 SoCs we run into a problem with the
> > >> fast HDMI PLL and it's OD (post-dividers). This clock tree can run at
> > >> up to approx. 3GHz.
> > >> This however causes a problem, because these rates require BIT(31) to
> > >> be usable. Unfortunately this is not the case with clk_ops.round_rate
> > >> on 32-bit systems. BIT(31) is reserved for the sign (+ or -).
> > >>
> > >> clk_ops.determine_rate does not suffer from this limitation. It uses
> > >> an int to signal any errors and can then take all availble 32 bits for
> > >> the clock rate.
> > >>
> > >> Changes since v1 from [0]:
> > >> - reworked the first patch so the the existing
> > >> divider_{ro_}round_rate_parent implementations are using the new
> > >> divider_{ro_}determine_rate implementations to avoid code duplication
> > >> (thanks Jerome for the suggestion)
> > >> - added a patch to switch the default clk_divider_{ro_}ops to use
> > >> .determine_rate instead of .round_rate as suggested by Jerome
> > >> (thanks)
> > >> - dropped a patch for the Meson PLL ops as these are independent from
> > >> the divider patches and Jerome has applied that one directly (thanks)
> > >> - added Jerome's Reviewed-by to the meson clk-regmap patch (thanks!)
> > >> - dropped the RFC prefix
> > > please let me know what you think about this v2
> > > I am asking because clk-divider is widely used, so I'd appreciate if
> > > this gets some time in linux-next (so for example Kernel CI can test
> > > this and report issues if there are any).
> Do you have any comments on this series?
> I am fine with it skipping 5.14 as it's a change which affects
> multiple platforms.
> So I would like to use the time until the trees are opening for
> patches targeting 5.15 to iron out code-review comments.
>
> > Looks good to me
> > Reviewed-by: Jerome Brunet <[email protected]>
> Thanks Jerome - I'll add it to v3 once I send it (assuming nothing
> major changes)
Looks ok to me. Will you resend?