From 4e7cf74fa3b28fcb43531ca6bc350bf8636e3de6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Aug 2021 20:00:22 +0300 Subject: [PATCH 1/4] clk: fractional-divider: Export approximation algorithm to the CCF users At least one user currently duplicates some functions that are provided by fractional divider module. Let's export approximation algorithm and replace the open-coded variant. As a bonus the exported function will get better documentation in place. Signed-off-by: Andy Shevchenko Tested-by: Heiko Stuebner Acked-by: Heiko Stuebner Link: https://lore.kernel.org/r/20210812170025.67074-1-andriy.shevchenko@linux.intel.com [sboyd@kernel.org: Add header guard because why not] Signed-off-by: Stephen Boyd --- drivers/clk/clk-fractional-divider.c | 11 +++++++---- drivers/clk/clk-fractional-divider.h | 13 +++++++++++++ drivers/clk/rockchip/clk.c | 17 +++-------------- 3 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 drivers/clk/clk-fractional-divider.h diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index b1e556f20911..535d299af646 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -14,6 +14,8 @@ #include #include +#include "clk-fractional-divider.h" + static inline u32 clk_fd_readl(struct clk_fractional_divider *fd) { if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) @@ -68,9 +70,10 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, return ret; } -static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate, - unsigned long *m, unsigned long *n) +void clk_fractional_divider_general_approximation(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate, + unsigned long *m, unsigned long *n) { struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long scale; @@ -102,7 +105,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, if (fd->approximation) fd->approximation(hw, rate, parent_rate, &m, &n); else - clk_fd_general_approximation(hw, rate, parent_rate, &m, &n); + clk_fractional_divider_general_approximation(hw, rate, parent_rate, &m, &n); ret = (u64)*parent_rate * m; do_div(ret, n); diff --git a/drivers/clk/clk-fractional-divider.h b/drivers/clk/clk-fractional-divider.h new file mode 100644 index 000000000000..a05649eceb17 --- /dev/null +++ b/drivers/clk/clk-fractional-divider.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CLK_FRACTIONAL_DIV_H +#define _CLK_FRACTIONAL_DIV_H + +struct clk_hw; + +void clk_fractional_divider_general_approximation(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate, + unsigned long *m, + unsigned long *n); + +#endif diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 049e5e0b64f6..b7be7e11b0df 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -22,6 +22,8 @@ #include #include #include + +#include "../clk-fractional-divider.h" #include "clk.h" /* @@ -178,10 +180,8 @@ static void rockchip_fractional_approximation(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate, unsigned long *m, unsigned long *n) { - struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long p_rate, p_parent_rate; struct clk_hw *p_parent; - unsigned long scale; p_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); if ((rate * 20 > p_rate) && (p_rate % rate != 0)) { @@ -190,18 +190,7 @@ static void rockchip_fractional_approximation(struct clk_hw *hw, *parent_rate = p_parent_rate; } - /* - * Get rate closer to *parent_rate to guarantee there is no overflow - * for m and n. In the result it will be the nearest rate left shifted - * by (scale - fd->nwidth) bits. - */ - scale = fls_long(*parent_rate / rate - 1); - if (scale > fd->nwidth) - rate <<= scale - fd->nwidth; - - rational_best_approximation(rate, *parent_rate, - GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), - m, n); + clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n); } static struct clk *rockchip_clk_register_frac_branch( From 928f9e2686110825262685b7aedc7b21b805fecd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Aug 2021 20:00:23 +0300 Subject: [PATCH 2/4] clk: fractional-divider: Hide clk_fractional_divider_ops from wide audience The providers are all located in drivers/clk/ and hence no need to export the clock operations to wider audience. Hide them by moving to drivers/clk/clk-fractional-divider.h. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210812170025.67074-2-andriy.shevchenko@linux.intel.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-fractional-divider.h | 2 ++ drivers/clk/imx/clk-composite-7ulp.c | 1 + include/linux/clk-provider.h | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-fractional-divider.h b/drivers/clk/clk-fractional-divider.h index a05649eceb17..f0f71d23797b 100644 --- a/drivers/clk/clk-fractional-divider.h +++ b/drivers/clk/clk-fractional-divider.h @@ -4,6 +4,8 @@ struct clk_hw; +extern const struct clk_ops clk_fractional_divider_ops; + void clk_fractional_divider_general_approximation(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate, diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c index 7c4f31b31eb0..d85ba78abbb1 100644 --- a/drivers/clk/imx/clk-composite-7ulp.c +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -10,6 +10,7 @@ #include #include +#include "../clk-fractional-divider.h" #include "clk.h" #define PCG_PCS_SHIFT 24 diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index d83b829305c0..acb8e10d2898 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1023,7 +1023,6 @@ struct clk_fractional_divider { #define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0) #define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1) -extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, From 82f53f9ee5770177eb102446cc3513bf07e2668a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Aug 2021 20:00:24 +0300 Subject: [PATCH 3/4] clk: fractional-divider: Introduce POWER_OF_TWO_PS flag The newly introduced POWER_OF_TWO_PS flag, when set, makes the flow to skip the assumption that the caller will use an additional 2^scale prescaler to get the desired clock rate. Reported-by: Liu Ying Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210812170025.67074-3-andriy.shevchenko@linux.intel.com Signed-off-by: Stephen Boyd --- drivers/acpi/acpi_lpss.c | 4 ++-- drivers/clk/clk-fractional-divider.c | 10 ++++++---- drivers/mfd/intel-lpss.c | 3 ++- include/linux/clk-provider.h | 7 +++++++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 894b7e6ae144..55c5e89d6a7b 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -434,8 +434,8 @@ static int register_device_clock(struct acpi_device *adev, if (!clk_name) return -ENOMEM; clk = clk_register_fractional_divider(NULL, clk_name, parent, - 0, prv_base, - 1, 15, 16, 15, 0, NULL); + CLK_FRAC_DIVIDER_POWER_OF_TWO_PS, + prv_base, 1, 15, 16, 15, 0, NULL); parent = clk_name; clk_name = kasprintf(GFP_KERNEL, "%s-update", devname); diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 535d299af646..6a3ed82fdae9 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -76,16 +76,18 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw, unsigned long *m, unsigned long *n) { struct clk_fractional_divider *fd = to_clk_fd(hw); - unsigned long scale; /* * Get rate closer to *parent_rate to guarantee there is no overflow * for m and n. In the result it will be the nearest rate left shifted * by (scale - fd->nwidth) bits. */ - scale = fls_long(*parent_rate / rate - 1); - if (scale > fd->nwidth) - rate <<= scale - fd->nwidth; + if (fd->flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS) { + unsigned long scale = fls_long(*parent_rate / rate - 1); + + if (scale > fd->nwidth) + rate <<= scale - fd->nwidth; + } rational_best_approximation(rate, *parent_rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index a9bf10bee796..0e15afc39f54 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -301,7 +301,8 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss, snprintf(name, sizeof(name), "%s-div", devname); tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp), - 0, lpss->priv, 1, 15, 16, 15, 0, + CLK_FRAC_DIVIDER_POWER_OF_TWO_PS, + lpss->priv, 1, 15, 16, 15, 0, NULL); if (IS_ERR(tmp)) return PTR_ERR(tmp); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index acb8e10d2898..d63d07fd251b 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1001,6 +1001,12 @@ struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev, * CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are * used for the divider register. Setting this flag makes the register * accesses big endian. + * CLK_FRAC_DIVIDER_POWER_OF_TWO_PS - By default the resulting fraction might + * be saturated and the caller will get quite far from the good enough + * approximation. Instead the caller may require, by setting this flag, + * to shift left by a few bits in case, when the asked one is quite small + * to satisfy the desired range of denominator. It assumes that on the + * caller's side the power-of-two capable prescaler exists. */ struct clk_fractional_divider { struct clk_hw hw; @@ -1022,6 +1028,7 @@ struct clk_fractional_divider { #define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0) #define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1) +#define CLK_FRAC_DIVIDER_POWER_OF_TWO_PS BIT(2) struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, From e81b917a78c7ed08007de5b502a14535daa106bf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Aug 2021 20:00:25 +0300 Subject: [PATCH 4/4] clk: fractional-divider: Document the arithmetics used behind the code It appears that some code lines raise the question why they are needed and how they are participated in the calculus of the resulting values. Document this in a form of the top comment in the module file. Reported-by: Liu Ying Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210812170025.67074-4-andriy.shevchenko@linux.intel.com [sboyd@kernel.org: Remove "die" as it isn't relevant] Signed-off-by: Stephen Boyd --- drivers/clk/clk-fractional-divider.c | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 6a3ed82fdae9..4274540327ce 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -3,8 +3,39 @@ * Copyright (C) 2014 Intel Corporation * * Adjustable fractional divider clock implementation. - * Output rate = (m / n) * parent_rate. * Uses rational best approximation algorithm. + * + * Output is calculated as + * + * rate = (m / n) * parent_rate (1) + * + * This is useful when we have a prescaler block which asks for + * m (numerator) and n (denominator) values to be provided to satisfy + * the (1) as much as possible. + * + * Since m and n have the limitation by a range, e.g. + * + * n >= 1, n < N_width, where N_width = 2^nwidth (2) + * + * for some cases the output may be saturated. Hence, from (1) and (2), + * assuming the worst case when m = 1, the inequality + * + * floor(log2(parent_rate / rate)) <= nwidth (3) + * + * may be derived. Thus, in cases when + * + * (parent_rate / rate) >> N_width (4) + * + * we might scale up the rate by 2^scale (see the description of + * CLK_FRAC_DIVIDER_POWER_OF_TWO_PS for additional information), where + * + * scale = floor(log2(parent_rate / rate)) - nwidth (5) + * + * and assume that the IP, that needs m and n, has also its own + * prescaler, which is capable to divide by 2^scale. In this way + * we get the denominator to satisfy the desired range (2) and + * at the same time much much better result of m and n than simple + * saturated values. */ #include @@ -81,6 +112,8 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw, * Get rate closer to *parent_rate to guarantee there is no overflow * for m and n. In the result it will be the nearest rate left shifted * by (scale - fd->nwidth) bits. + * + * For the detailed explanation see the top comment in this file. */ if (fd->flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS) { unsigned long scale = fls_long(*parent_rate / rate - 1);