2023-08-06 13:44:52

by Frank Oltmanns

[permalink] [raw]
Subject: [PATCH v5 00/11] clk: sunxi-ng: Consider alternative parent rates when determining NKM clock rate

This patchset enables NKM clocks to consider alternative parent rates
and utilize this new feature to adjust the pll-video0 clock on Allwinner
A64.

Furthermore, with this patchset pll-video0 considers rates that are
higher than the requested rate when finding the closest rate. In
consequence, higher rates are also considered by pll-video0's
descandents. In total, after applying this patchset, finding the closest
rate is supported by:
- ccu_nm
- ccu_nkm
- ccu_mux
- ccu_div

This allows us to achieve an optimal rate for driving the board's panel.

To provide some context, the clock structure involved in this process is
as follows:
clock clock type
--------------------------------------
pll-video0 ccu_nm
pll-mipi ccu_nkm
tcon0 ccu_mux
tcon-data-clock sun4i_dclk

The divider between tcon0 and tcon-data-clock is fixed at 4. Therefore,
in order to achieve a rate that closely matches the desired rate of the
panel, pll-mipi needs to operate at a specific rate.

Tests
=====
So far, this has been successfully tested on the A64-based Pinephone
using three different panel rates:

1. A panel rate that can be matched exactly by pll-video0.
2. A panel rate that requires pll-video0 to undershoot to get the
closest rate.
3. A panel rate that requires pll-video0 to overshoot to get the
closest rate.

Test records:

Re 1:
-----
Panel requests tcon-data-clock of 103500000 Hz, i.e., pll-mipi needs to
run at 414000000 Hz. This results in the following clock rates:
clock rate
-------------------------------------
pll-video0 207000000
hdmi-phy-clk 51750000
hdmi 207000000
tcon1 207000000
pll-mipi 414000000
tcon0 414000000
tcon-data-clock 103500000

The results of the find_best calls:
ccu_nkm_find_best_with_parent_adj: rate=414000000, best_rate=414000000, best_parent_rate=207000000, n=1, k=2, m=1
ccu_nkm_find_best_with_parent_adj: rate=414000000, best_rate=414000000, best_parent_rate=207000000, n=1, k=2, m=1
ccu_nkm_find_best_with_parent_adj: rate=414000000, best_rate=414000000, best_parent_rate=207000000, n=1, k=2, m=1
ccu_nkm_find_best_with_parent_adj: rate=414000000, best_rate=414000000, best_parent_rate=207000000, n=1, k=2, m=1
ccu_nkm_find_best: rate=414000000, best_rate=414000000, parent_rate=207000000, n=1, k=2, m=1

Re 2:
-----
Panel requests tcon-data-clock of 103650000 Hz, i.e., pll-mipi needs to
run at 414600000 Hz. This results in the following clock rates:
clock rate
-------------------------------------
pll-video0 282666666
hdmi-phy-clk 70666666
hdmi 282666666
tcon1 282666666
pll-mipi 414577776
tcon0 414577776
tcon-data-clock 103644444

The results of the find_best calls:
ccu_nkm_find_best_with_parent_adj: rate=414600000, best_rate=414577776, best_parent_rate=282666666, n=11, k=2, m=15
ccu_nkm_find_best_with_parent_adj: rate=414600000, best_rate=414577776, best_parent_rate=282666666, n=11, k=2, m=15
ccu_nkm_find_best_with_parent_adj: rate=414577776, best_rate=414577776, best_parent_rate=282666666, n=11, k=2, m=15
ccu_nkm_find_best_with_parent_adj: rate=414577776, best_rate=414577776, best_parent_rate=282666666, n=11, k=2, m=15
ccu_nkm_find_best: rate=414577776, best_rate=414577776, parent_rate=282666666, n=11, k=2, m=15

Re 3:
-----
Panel requests tcon-data-clock of 112266000 Hz, i.e., pll-mipi needs to
run at 449064000 Hz. This results in the following clock rates:
clock rate
-------------------------------------
pll-video0 207272727
hdmi-phy-clk 51818181
hdmi 207272727
tcon1 207272727
pll-mipi 449090908
tcon0 449090908
tcon-data-clock 112272727

The results of the find_best calls:
ccu_nkm_find_best_with_parent_adj: rate=449064000, best_rate=449090908, best_parent_rate=207272727, n=13, k=2, m=12
ccu_nkm_find_best_with_parent_adj: rate=449064000, best_rate=449090908, best_parent_rate=207272727, n=13, k=2, m=12
ccu_nkm_find_best_with_parent_adj: rate=449090908, best_rate=449090908, best_parent_rate=207272727, n=13, k=2, m=12
ccu_nkm_find_best_with_parent_adj: rate=449090908, best_rate=449090908, best_parent_rate=207272727, n=13, k=2, m=12
ccu_nkm_find_best: rate=449090908, best_rate=449090908, parent_rate=207272727, n=13, k=2, m=12

Changelog:
----------
Changes in v5:
- Remove the dedicated function for calculating the optimal parent rate
for nkm clocks that was introduced in v2 and again in v4. Instead use
a simple calculation and require the parent clock to select the
closest rate to achieve optimal results.
- Change the order of parameters of nkm_best_rate and
nkm_best_rate_with_parent_adj as requested my Maxime Ripard.
- Prefer to not reset the rate of the nkm clock's parent if the ideal
rate can be reached using the parent's current rate, copying the
behavior of ccu_mp.
- Link to v4: https://lore.kernel.org/r/[email protected]

Changes in v4:
- Re-introduce a dedicated function for calculating the optimal parent
rate for nkm clocks that was introduced in v2 and removed in v3. It
turned out that not having this functionality introduces a bug when
the parent does not support finding the closest rate:
https://lore.kernel.org/all/[email protected]/
- Incorporate review remarks:
- Correcting the parameter name for ccu_nkm_round_rate()'s parent HW
is now in a separate patch.
- Use correct parameter order in ccu_nkm_find_best_with_parent_adj.
- Add ccu_is_better_rate() and use it for determining the best rate
for nm and nkm, as well as ccu_mux_helper_determine_rate.
- Consistently introduce new macros for clock variants that support
finding the closest rate instead of updating existing macros.
- Use wrapper function for determining a ccu_mux's rate in order to
support finding the closest rate.
- Link to v3: https://lore.kernel.org/r/[email protected]

Changes in v3:
- Use dedicated function for finding the best rate in cases where an
nkm clock supports setting its parent's rate, streamlining it with
the structure that is used in other sunxi-ng ccus such as ccu_mp
(PATCH 1).
- Therefore, remove the now obsolete comments that were introduced in
v2 (PATCH 1).
- Remove the dedicated function for calculating the optimal parent rate
for nkm clocks that was introduced in v2. Instead use a simple
calculation and require the parent clock to select the closest rate to
achieve optimal results (PATCH 1).
- Therefore, add support to set the closest rate for nm clocks (because
pll-mipi's parent pll-video0 is an nm clock) and all clock types that
are descendants of a64's pll-video0, i.e., nkm, mux, and div (PATCH 3
et. seq.).
- Link to v2: https://lore.kernel.org/all/[email protected]/

Changes in V2:
- Move optimal parent rate calculation to dedicated function
- Choose a parent rate that does not to overshoot requested rate
- Add comments to ccu_nkm_find_best
- Make sure that best_parent_rate stays at original parent rate in the unlikely
case that all combinations overshoot.

Link to V1:
https://lore.kernel.org/lkml/[email protected]/

---
Frank Oltmanns (11):
clk: sunxi-ng: nkm: Use correct parameter name for parent HW
clk: sunxi-ng: nkm: consider alternative parent rates when determining rate
clk: sunxi-ng: a64: allow pll-mipi to set parent's rate
clk: sunxi-ng: Add feature to find closest rate
clk: sunxi-ng: Add helper function to find closest rate
clk: sunxi-ng: nm: Support finding closest rate
clk: sunxi-ng: nkm: Support finding closest rate
clk: sunxi-ng: mux: Support finding closest rate
clk: sunxi-ng: div: Support finding closest rate
clk: sunxi-ng: a64: select closest rate for pll-video0
clk: sunxi-ng: nkm: Prefer current parent rate

drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 36 ++++++++++------------
drivers/clk/sunxi-ng/ccu_common.c | 12 ++++++++
drivers/clk/sunxi-ng/ccu_common.h | 6 ++++
drivers/clk/sunxi-ng/ccu_div.h | 30 +++++++++++++++++++
drivers/clk/sunxi-ng/ccu_mux.c | 15 ++++++++--
drivers/clk/sunxi-ng/ccu_mux.h | 38 +++++++++++++++++-------
drivers/clk/sunxi-ng/ccu_nkm.c | 56 ++++++++++++++++++++++++++++++-----
drivers/clk/sunxi-ng/ccu_nm.c | 13 ++++----
drivers/clk/sunxi-ng/ccu_nm.h | 48 ++++++++++++++++++++++++++++--
9 files changed, 203 insertions(+), 51 deletions(-)
---
base-commit: 6995e2de6891c724bfeb2db33d7b87775f913ad1
change-id: 20230626-pll-mipi_set_rate_parent-3363fc0d6e6f

Best regards,
--
Frank Oltmanns <[email protected]>



2023-08-06 14:27:13

by Frank Oltmanns

[permalink] [raw]
Subject: [PATCH v5 08/11] clk: sunxi-ng: mux: Support finding closest rate

When finding the best rate for a mux clock, consider rates that are
higher than the requested rate when CCU_FEATURE_ROUND_CLOSEST is used.
Furthermore, introduce an initialization macro that sets this flag.

Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Frank Oltmanns <[email protected]>
---
drivers/clk/sunxi-ng/ccu_mux.c | 13 ++++++++++++-
drivers/clk/sunxi-ng/ccu_mux.h | 38 +++++++++++++++++++++++++++-----------
2 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
index 3ca695439620..5edc63b46651 100644
--- a/drivers/clk/sunxi-ng/ccu_mux.c
+++ b/drivers/clk/sunxi-ng/ccu_mux.c
@@ -242,6 +242,17 @@ static int ccu_mux_set_parent(struct clk_hw *hw, u8 index)
return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index);
}

+static int ccu_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct ccu_mux *cm = hw_to_ccu_mux(hw);
+
+ if (cm->common.features & CCU_FEATURE_CLOSEST_RATE)
+ return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST);
+
+ return clk_mux_determine_rate_flags(hw, req, 0);
+}
+
static unsigned long ccu_mux_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -259,7 +270,7 @@ const struct clk_ops ccu_mux_ops = {
.get_parent = ccu_mux_get_parent,
.set_parent = ccu_mux_set_parent,

- .determine_rate = __clk_mux_determine_rate,
+ .determine_rate = ccu_mux_determine_rate,
.recalc_rate = ccu_mux_recalc_rate,
};
EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU);
diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h
index 2c1811a445b0..eb1172ebbd94 100644
--- a/drivers/clk/sunxi-ng/ccu_mux.h
+++ b/drivers/clk/sunxi-ng/ccu_mux.h
@@ -46,20 +46,36 @@ struct ccu_mux {
struct ccu_common common;
};

+#define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table, \
+ _reg, _shift, _width, _gate, \
+ _flags, _features) \
+ struct ccu_mux _struct = { \
+ .enable = _gate, \
+ .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = CLK_HW_INIT_PARENTS(_name, \
+ _parents, \
+ &ccu_mux_ops, \
+ _flags), \
+ .features = _features, \
+ } \
+ }
+
+#define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents, \
+ _table, _reg, _shift, \
+ _width, _gate, _flags) \
+ SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \
+ _table, _reg, _shift, \
+ _width, _gate, _flags, \
+ CCU_FEATURE_CLOSEST_RATE)
+
#define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table, \
_reg, _shift, _width, _gate, \
_flags) \
- struct ccu_mux _struct = { \
- .enable = _gate, \
- .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \
- .common = { \
- .reg = _reg, \
- .hw.init = CLK_HW_INIT_PARENTS(_name, \
- _parents, \
- &ccu_mux_ops, \
- _flags), \
- } \
- }
+ SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \
+ _table, _reg, _shift, \
+ _width, _gate, _flags, 0)

#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \
_shift, _width, _gate, _flags) \

--
2.41.0


2023-08-06 15:01:15

by Frank Oltmanns

[permalink] [raw]
Subject: [PATCH v5 11/11] clk: sunxi-ng: nkm: Prefer current parent rate

Similar to ccu_mp, if the current parent rate allows getting the ideal
rate, prefer to not change the parent clock's rate.

Signed-off-by: Frank Oltmanns <[email protected]>
---
drivers/clk/sunxi-ng/ccu_nkm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
index 896bb1ef8642..1e49444817cf 100644
--- a/drivers/clk/sunxi-ng/ccu_nkm.c
+++ b/drivers/clk/sunxi-ng/ccu_nkm.c
@@ -35,7 +35,8 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common

tmp_rate = tmp_parent * _n * _k / _m;

- if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
+ if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) ||
+ (tmp_parent == *parent && tmp_rate == best_rate)) {
best_rate = tmp_rate;
best_parent_rate = tmp_parent;
best_n = _n;

--
2.41.0


2023-08-06 15:04:00

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v5 08/11] clk: sunxi-ng: mux: Support finding closest rate

Dne nedelja, 06. avgust 2023 ob 15:06:53 CEST je Frank Oltmanns napisal(a):
> When finding the best rate for a mux clock, consider rates that are
> higher than the requested rate when CCU_FEATURE_ROUND_CLOSEST is used.
> Furthermore, introduce an initialization macro that sets this flag.
>
> Acked-by: Maxime Ripard <[email protected]>
> Signed-off-by: Frank Oltmanns <[email protected]>

Reviewed-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> drivers/clk/sunxi-ng/ccu_mux.c | 13 ++++++++++++-
> drivers/clk/sunxi-ng/ccu_mux.h | 38 +++++++++++++++++++++++++++-----------
> 2 files changed, 39 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
> index 3ca695439620..5edc63b46651 100644
> --- a/drivers/clk/sunxi-ng/ccu_mux.c
> +++ b/drivers/clk/sunxi-ng/ccu_mux.c
> @@ -242,6 +242,17 @@ static int ccu_mux_set_parent(struct clk_hw *hw, u8
> index) return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index);
> }
>
> +static int ccu_mux_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + struct ccu_mux *cm = hw_to_ccu_mux(hw);
> +
> + if (cm->common.features & CCU_FEATURE_CLOSEST_RATE)
> + return clk_mux_determine_rate_flags(hw, req,
CLK_MUX_ROUND_CLOSEST);
> +
> + return clk_mux_determine_rate_flags(hw, req, 0);
> +}
> +
> static unsigned long ccu_mux_recalc_rate(struct clk_hw *hw,
> unsigned long
parent_rate)
> {
> @@ -259,7 +270,7 @@ const struct clk_ops ccu_mux_ops = {
> .get_parent = ccu_mux_get_parent,
> .set_parent = ccu_mux_set_parent,
>
> - .determine_rate = __clk_mux_determine_rate,
> + .determine_rate = ccu_mux_determine_rate,
> .recalc_rate = ccu_mux_recalc_rate,
> };
> EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU);
> diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h
> index 2c1811a445b0..eb1172ebbd94 100644
> --- a/drivers/clk/sunxi-ng/ccu_mux.h
> +++ b/drivers/clk/sunxi-ng/ccu_mux.h
> @@ -46,20 +46,36 @@ struct ccu_mux {
> struct ccu_common common;
> };
>
> +#define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,
> _table, \ + _reg, _shift,
_width, _gate, \
> + _flags, _features)
\
> + struct ccu_mux _struct = {
\
> + .enable = _gate,
\
> + .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width,
_table), \
> + .common = {
\
> + .reg = _reg,
\
> + .hw.init = CLK_HW_INIT_PARENTS(_name,
\
> +
_parents, \
> +
&ccu_mux_ops, \
> +
_flags), \
> + .features = _features,
\
> + }
\
> + }
> +
> +#define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents,
\
> + _table, _reg,
_shift, \
> + _width, _gate,
_flags) \
> + SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,
\
> + _table, _reg,
_shift, \
> + _width, _gate,
_flags, \
> +
CCU_FEATURE_CLOSEST_RATE)
> +
> #define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table,
\
> _reg, _shift, _width, _gate,
\
> _flags)
\
> - struct ccu_mux _struct = {
\
> - .enable = _gate,
\
> - .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width,
_table), \
> - .common = {
\
> - .reg = _reg,
\
> - .hw.init = CLK_HW_INIT_PARENTS(_name,
\
> -
_parents, \
> -
&ccu_mux_ops, \
> -
_flags), \
> - }
\
> - }
> + SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,
\
> + _table, _reg,
_shift, \
> + _width, _gate,
_flags, 0)
>
> #define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg,
\
> _shift, _width, _gate, _flags)
\





2023-08-06 15:11:09

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v5 11/11] clk: sunxi-ng: nkm: Prefer current parent rate

Dne nedelja, 06. avgust 2023 ob 15:06:56 CEST je Frank Oltmanns napisal(a):
> Similar to ccu_mp, if the current parent rate allows getting the ideal
> rate, prefer to not change the parent clock's rate.
>
> Signed-off-by: Frank Oltmanns <[email protected]>

Reviewed-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> drivers/clk/sunxi-ng/ccu_nkm.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
> index 896bb1ef8642..1e49444817cf 100644
> --- a/drivers/clk/sunxi-ng/ccu_nkm.c
> +++ b/drivers/clk/sunxi-ng/ccu_nkm.c
> @@ -35,7 +35,8 @@ static unsigned long
> ccu_nkm_find_best_with_parent_adj(struct ccu_common *common
>
> tmp_rate = tmp_parent * _n * _k /
_m;
>
> - if (ccu_is_better_rate(common,
rate, tmp_rate, best_rate)) {
> + if (ccu_is_better_rate(common,
rate, tmp_rate, best_rate) ||
> + (tmp_parent == *parent &&
tmp_rate == best_rate)) {
> best_rate = tmp_rate;
> best_parent_rate =
tmp_parent;
> best_n = _n;





2023-08-06 15:16:24

by Frank Oltmanns

[permalink] [raw]
Subject: [PATCH v5 07/11] clk: sunxi-ng: nkm: Support finding closest rate

When finding the best rate for a NKM clock, consider rates that are
higher than the requested rate, if the CCU_FEATURE_CLOSEST_RATE flag is
set by using the helper function ccu_is_better_rate().

Accommodate ccu_mux_helper_determine_rate to this change.

Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Frank Oltmanns <[email protected]>
---
drivers/clk/sunxi-ng/ccu_mux.c | 2 +-
drivers/clk/sunxi-ng/ccu_nkm.c | 20 +++++++++-----------
2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
index 1d557e323169..3ca695439620 100644
--- a/drivers/clk/sunxi-ng/ccu_mux.c
+++ b/drivers/clk/sunxi-ng/ccu_mux.c
@@ -139,7 +139,7 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common,
goto out;
}

- if ((req->rate - tmp_rate) < (req->rate - best_rate)) {
+ if (ccu_is_better_rate(common, req->rate, tmp_rate, best_rate)) {
best_rate = tmp_rate;
best_parent_rate = parent_rate;
best_parent = parent;
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
index ea1b77e9b57f..896bb1ef8642 100644
--- a/drivers/clk/sunxi-ng/ccu_nkm.c
+++ b/drivers/clk/sunxi-ng/ccu_nkm.c
@@ -17,7 +17,8 @@ struct _ccu_nkm {
unsigned long m, min_m, max_m;
};

-static unsigned long ccu_nkm_find_best_with_parent_adj(struct clk_hw *parent_hw,
+static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common,
+ struct clk_hw *parent_hw,
unsigned long *parent, unsigned long rate,
struct _ccu_nkm *nkm)
{
@@ -33,10 +34,8 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct clk_hw *parent_hw,
tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k));

tmp_rate = tmp_parent * _n * _k / _m;
- if (tmp_rate > rate)
- continue;

- if ((rate - tmp_rate) < (rate - best_rate)) {
+ if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
best_rate = tmp_rate;
best_parent_rate = tmp_parent;
best_n = _n;
@@ -57,7 +56,7 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct clk_hw *parent_hw,
}

static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nkm *nkm)
+ struct _ccu_nkm *nkm, struct ccu_common *common)
{
unsigned long best_rate = 0;
unsigned long best_n = 0, best_k = 0, best_m = 0;
@@ -70,9 +69,7 @@ static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,

tmp_rate = parent * _n * _k / _m;

- if (tmp_rate > rate)
- continue;
- if ((rate - tmp_rate) < (rate - best_rate)) {
+ if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
best_rate = tmp_rate;
best_n = _n;
best_k = _k;
@@ -165,9 +162,10 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
rate *= nkm->fixed_post_div;

if (!clk_hw_can_set_rate_parent(&nkm->common.hw))
- rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm);
+ rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm, &nkm->common);
else
- rate = ccu_nkm_find_best_with_parent_adj(parent_hw, parent_rate, rate, &_nkm);
+ rate = ccu_nkm_find_best_with_parent_adj(&nkm->common, parent_hw, parent_rate, rate,
+ &_nkm);

if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nkm->fixed_post_div;
@@ -202,7 +200,7 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
_nkm.min_m = 1;
_nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;

- ccu_nkm_find_best(parent_rate, rate, &_nkm);
+ ccu_nkm_find_best(parent_rate, rate, &_nkm, &nkm->common);

spin_lock_irqsave(nkm->common.lock, flags);


--
2.41.0


2023-08-06 15:32:38

by Frank Oltmanns

[permalink] [raw]
Subject: [PATCH v5 06/11] clk: sunxi-ng: nm: Support finding closest rate

Use the helper function ccu_is_better_rate() to determine the rate that
is closest to the requested rate, thereby supporting rates that are
higher than the requested rate if the clock uses the
CCU_FEATURE_CLOSEST_RATE.

Add the macro SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST which
sets CCU_FEATURE_CLOSEST_RATE.

To avoid code duplication, add the macros
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT that allows selecting
arbitrary features and use it in the original
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX as well as the newly introduced
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST macros.

Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Frank Oltmanns <[email protected]>
---
drivers/clk/sunxi-ng/ccu_nm.c | 13 +++++-------
drivers/clk/sunxi-ng/ccu_nm.h | 48 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index c1fd11542c45..ffac3deb89d6 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent,
return rate;
}

-static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nm *nm)
+static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned long parent,
+ unsigned long rate, struct _ccu_nm *nm)
{
unsigned long best_rate = 0;
unsigned long best_n = 0, best_m = 0;
@@ -39,10 +39,7 @@ static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
unsigned long tmp_rate = ccu_nm_calc_rate(parent,
_n, _m);

- if (tmp_rate > rate)
- continue;
-
- if ((rate - tmp_rate) < (rate - best_rate)) {
+ if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
best_rate = tmp_rate;
best_n = _n;
best_m = _m;
@@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
_nm.min_m = 1;
_nm.max_m = nm->m.max ?: 1 << nm->m.width;

- rate = ccu_nm_find_best(*parent_rate, rate, &_nm);
+ rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm);

if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nm->fixed_post_div;
@@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
&_nm.m, &_nm.n);
} else {
ccu_sdm_helper_disable(&nm->common, &nm->sdm);
- ccu_nm_find_best(parent_rate, rate, &_nm);
+ ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm);
}

spin_lock_irqsave(nm->common.lock, flags);
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
index 2904e67f05a8..93c11693574f 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.h
+++ b/drivers/clk/sunxi-ng/ccu_nm.h
@@ -108,7 +108,7 @@ struct ccu_nm {
}, \
}

-#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
_parent, _reg, \
_min_rate, _max_rate, \
_nshift, _nwidth, \
@@ -116,7 +116,8 @@ struct ccu_nm {
_frac_en, _frac_sel, \
_frac_rate_0, \
_frac_rate_1, \
- _gate, _lock, _flags) \
+ _gate, _lock, _flags, \
+ _features) \
struct ccu_nm _struct = { \
.enable = _gate, \
.lock = _lock, \
@@ -129,7 +130,7 @@ struct ccu_nm {
.max_rate = _max_rate, \
.common = { \
.reg = _reg, \
- .features = CCU_FEATURE_FRACTIONAL, \
+ .features = _features, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nm_ops, \
@@ -137,6 +138,47 @@ struct ccu_nm {
}, \
}

+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags) \
+ SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags, \
+ CCU_FEATURE_FRACTIONAL)
+
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags) \
+ SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags, \
+ CCU_FEATURE_FRACTIONAL |\
+ CCU_FEATURE_CLOSEST_RATE)
+
#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_mshift, _mwidth, \

--
2.41.0


2023-08-06 16:57:53

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v5 06/11] clk: sunxi-ng: nm: Support finding closest rate

Dne nedelja, 06. avgust 2023 ob 15:06:51 CEST je Frank Oltmanns napisal(a):
> Use the helper function ccu_is_better_rate() to determine the rate that
> is closest to the requested rate, thereby supporting rates that are
> higher than the requested rate if the clock uses the
> CCU_FEATURE_CLOSEST_RATE.
>
> Add the macro SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST which
> sets CCU_FEATURE_CLOSEST_RATE.
>
> To avoid code duplication, add the macros
> SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT that allows selecting
> arbitrary features and use it in the original
> SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX as well as the newly introduced
> SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST macros.
>
> Acked-by: Maxime Ripard <[email protected]>
> Signed-off-by: Frank Oltmanns <[email protected]>

Reviewed-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> drivers/clk/sunxi-ng/ccu_nm.c | 13 +++++-------
> drivers/clk/sunxi-ng/ccu_nm.h | 48
> ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 50
> insertions(+), 11 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
> index c1fd11542c45..ffac3deb89d6 100644
> --- a/drivers/clk/sunxi-ng/ccu_nm.c
> +++ b/drivers/clk/sunxi-ng/ccu_nm.c
> @@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long
> parent, return rate;
> }
>
> -static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long
> rate, - struct _ccu_nm *nm)
> +static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned
> long parent, + unsigned long
rate, struct _ccu_nm *nm)
> {
> unsigned long best_rate = 0;
> unsigned long best_n = 0, best_m = 0;
> @@ -39,10 +39,7 @@ static unsigned long ccu_nm_find_best(unsigned long
> parent, unsigned long rate, unsigned long tmp_rate =
> ccu_nm_calc_rate(parent,
>
_n, _m);
>
> - if (tmp_rate > rate)
> - continue;
> -
> - if ((rate - tmp_rate) < (rate - best_rate))
{
> + if (ccu_is_better_rate(common, rate,
tmp_rate, best_rate)) {
> best_rate = tmp_rate;
> best_n = _n;
> best_m = _m;
> @@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw,
> unsigned long rate, _nm.min_m = 1;
> _nm.max_m = nm->m.max ?: 1 << nm->m.width;
>
> - rate = ccu_nm_find_best(*parent_rate, rate, &_nm);
> + rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm);
>
> if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
> rate /= nm->fixed_post_div;
> @@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned
> long rate, &_nm.m, &_nm.n);
> } else {
> ccu_sdm_helper_disable(&nm->common, &nm->sdm);
> - ccu_nm_find_best(parent_rate, rate, &_nm);
> + ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm);
> }
>
> spin_lock_irqsave(nm->common.lock, flags);
> diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
> index 2904e67f05a8..93c11693574f 100644
> --- a/drivers/clk/sunxi-ng/ccu_nm.h
> +++ b/drivers/clk/sunxi-ng/ccu_nm.h
> @@ -108,7 +108,7 @@ struct ccu_nm {
> },
\
> }
>
> -#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
> +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
> _parent,
_reg, \
> _min_rate,
_max_rate, \
> _nshift,
_nwidth, \
> @@ -116,7 +116,8 @@ struct ccu_nm {
> _frac_en,
_frac_sel, \
>
_frac_rate_0, \
>
_frac_rate_1, \
> - _gate,
_lock, _flags) \
> + _gate,
_lock, _flags, \
> + _features)
\
> struct ccu_nm _struct = {
\
> .enable = _gate,
\
> .lock = _lock,
\
> @@ -129,7 +130,7 @@ struct ccu_nm {
> .max_rate = _max_rate,
\
> .common = {
\
> .reg = _reg,
\
> - .features = CCU_FEATURE_FRACTIONAL,
\
> + .features = _features,
\
> .hw.init = CLK_HW_INIT(_name,
\
>
_parent, \
>
&ccu_nm_ops, \
> @@ -137,6 +138,47 @@ struct ccu_nm {
> },
\
> }
>
> +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
> + _parent,
_reg, \
> + _min_rate,
_max_rate, \
> + _nshift,
_nwidth, \
> + _mshift,
_mwidth, \
> + _frac_en,
_frac_sel, \
> +
_frac_rate_0, \
> +
_frac_rate_1, \
> + _gate,
_lock, _flags) \
> + SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
> + _parent,
_reg, \
> + _min_rate,
_max_rate, \
> + _nshift,
_nwidth, \
> + _mshift,
_mwidth, \
> + _frac_en,
_frac_sel, \
> +
_frac_rate_0, \
> +
_frac_rate_1, \
> + _gate,
_lock, _flags, \
> +
CCU_FEATURE_FRACTIONAL)
> +
> +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(_struct, _name, \
> + _parent,
_reg, \
> + _min_rate,
_max_rate, \
> + _nshift,
_nwidth, \
> + _mshift,
_mwidth, \
> + _frac_en,
_frac_sel, \
> +
_frac_rate_0, \
> +
_frac_rate_1, \
> + _gate,
_lock, _flags) \
> + SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \
> + _parent,
_reg, \
> + _min_rate,
_max_rate, \
> + _nshift,
_nwidth, \
> + _mshift,
_mwidth, \
> + _frac_en,
_frac_sel, \
> +
_frac_rate_0, \
> +
_frac_rate_1, \
> + _gate,
_lock, _flags, \
> +
CCU_FEATURE_FRACTIONAL |\
> +
CCU_FEATURE_CLOSEST_RATE)
> +
> #define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
> _nshift, _nwidth,
\
> _mshift, _mwidth,
\