* [PATCH linux dev-5.8 0/4] AST2600 clock and FSI: Add APLL to control FSI clock @ 2020-08-24 22:10 Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock Eddie James ` (3 more replies) 0 siblings, 4 replies; 9+ messages in thread From: Eddie James @ 2020-08-24 22:10 UTC (permalink / raw) To: openbmc; +Cc: joel, andrew Add functionality to control the APLL clock on the AST2600. The APLL provides the clock for the FSI master on the AST2600. Then add a devicetree property to set the AST2600 FSI master clock frequency. Eddie James (4): clk: ast2600: Add functionality to the APLL clock dt-bindings: fsi: Aspeed master: Add clock-frequency property fsi: Aspeed master: Set clock frequency from devicetree ARM: dts: Aspeed: Rainier: Set FSI clock frequency .../bindings/fsi/fsi-master-aspeed.txt | 1 + arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 1 + drivers/clk/clk-ast2600.c | 177 ++++++++++++++++-- drivers/fsi/fsi-master-aspeed.c | 6 + include/dt-bindings/clock/ast2600-clock.h | 1 + 5 files changed, 174 insertions(+), 12 deletions(-) -- 2.26.2 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock 2020-08-24 22:10 [PATCH linux dev-5.8 0/4] AST2600 clock and FSI: Add APLL to control FSI clock Eddie James @ 2020-08-24 22:10 ` Eddie James 2020-09-01 6:36 ` Joel Stanley 2020-08-24 22:10 ` [PATCH linux dev-5.8 2/4] dt-bindings: fsi: Aspeed master: Add clock-frequency property Eddie James ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: Eddie James @ 2020-08-24 22:10 UTC (permalink / raw) To: openbmc; +Cc: joel, andrew Register a clock with it's own operations to describe the APLL on the AST2600. The clock is controlled by an SCU register containing a multiplier and divider of the 25MHz input clock. The functionality to change the APLL is necessary to finely control the FSI clock. Signed-off-by: Eddie James <eajames@linux.ibm.com> --- drivers/clk/clk-ast2600.c | 177 ++++++++++++++++++++-- include/dt-bindings/clock/ast2600-clock.h | 1 + 2 files changed, 166 insertions(+), 12 deletions(-) diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c index bbacaccad554..975677491f09 100644 --- a/drivers/clk/clk-ast2600.c +++ b/drivers/clk/clk-ast2600.c @@ -4,6 +4,7 @@ #define pr_fmt(fmt) "clk-ast2600: " fmt +#include <linux/kernel.h> #include <linux/mfd/syscon.h> #include <linux/of_address.h> #include <linux/of_device.h> @@ -15,7 +16,7 @@ #include "clk-aspeed.h" -#define ASPEED_G6_NUM_CLKS 71 +#define ASPEED_G6_NUM_CLKS 72 #define ASPEED_G6_SILICON_REV 0x004 @@ -31,6 +32,7 @@ #define ASPEED_G6_CLK_SELECTION1 0x300 #define ASPEED_G6_CLK_SELECTION2 0x304 #define ASPEED_G6_CLK_SELECTION4 0x310 +#define ASPEED_G6_CLK_SELECTION5 0x314 #define ASPEED_HPLL_PARAM 0x200 #define ASPEED_APLL_PARAM 0x210 @@ -116,7 +118,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uartx", 0 }, /* UART11 */ [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uartx", 0 }, /* UART12 */ [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uartx", 0 }, /* UART13 */ - [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", NULL, 0 }, /* FSI */ + [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", "aplln", CLK_SET_RATE_PARENT }, /* FSI */ }; static const struct clk_div_table ast2600_eclk_div_table[] = { @@ -187,24 +189,166 @@ static struct clk_hw *ast2600_calc_pll(const char *name, u32 val) mult, div); }; -static struct clk_hw *ast2600_calc_apll(const char *name, u32 val) +/* + * APLL Frequency: F = 25MHz * (2 - od) * [(m + 2) / (n + 1)] + */ +static void ast2600_apll_get_params(unsigned int *div, unsigned int *mul) { - unsigned int mult, div; + u32 val = readl(scu_g6_base + ASPEED_APLL_PARAM); if (val & BIT(20)) { /* Pass through mode */ - mult = div = 1; + *mul = *div = 1; } else { - /* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */ u32 m = (val >> 5) & 0x3f; u32 od = (val >> 4) & 0x1; u32 n = val & 0xf; - mult = (2 - od) * (m + 2); - div = n + 1; + *mul = (2 - od) * (m + 2); + *div = n + 1; } - return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, - mult, div); +} + +static long ast2600_apll_best(unsigned long ul_rate, unsigned long ul_prate, + unsigned int *out_div, unsigned int *out_mul, + unsigned int *output_divider) +{ +#define min_mult 2ULL +#define max_mult 65ULL +#define min_div 1ULL +#define max_div 16ULL + int i; + unsigned int bod = 0; + unsigned long long rem = 1ULL; + unsigned long long brem = ~(0ULL); + unsigned long long bdiv = 1ULL; + unsigned long long tdiv; + unsigned long long bmul = 16ULL; + unsigned long long tmul; + long brate = -ERANGE; + unsigned long long trate; + unsigned long long rate = ul_rate; + unsigned long long prate = ul_prate; + + for (i = 0; i < 2; ++i, prate *= 2ULL) { + for (tdiv = min_div; tdiv <= max_div; ++tdiv) { + tmul = DIV_ROUND_CLOSEST_ULL(rate * tdiv, prate); + if (tmul < min_mult || tmul > max_mult) + continue; + + trate = DIV_ROUND_CLOSEST_ULL(prate * tmul, tdiv); + if (trate > rate) + rem = trate - rate; + else + rem = rate - trate; + + if (rem < brem) { + bod = !i; + brem = rem; + bdiv = tdiv; + bmul = tmul; + brate = (long)trate; + } + + if (!rem) + break; + } + + if (!rem) + break; + } + + if (out_div) + *out_div = (unsigned int)bdiv; + + if (out_mul) + *out_mul = (unsigned int)bmul; + + if (output_divider) + *output_divider = bod; + + return brate; +#undef min_mult +#undef max_mult +#undef min_div +#undef max_div +} + +static unsigned long ast2600_apll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned int div; + unsigned int mul; + unsigned long long rate; + unsigned long long prate = (unsigned long long)parent_rate; + + ast2600_apll_get_params(&div, &mul); + + rate = DIV_ROUND_CLOSEST_ULL(prate * (unsigned long long)mul, div); + return (unsigned long)rate; +} + +static long ast2600_apll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return ast2600_apll_best(rate, *parent_rate, NULL, NULL, NULL); +} + +static int ast2600_apll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u32 val; + unsigned int od; + unsigned int div; + unsigned int mul; + long brate = ast2600_apll_best(rate, parent_rate, &div, &mul, &od); + + if (brate < 0) + return brate; + + val = readl(scu_g6_base + ASPEED_APLL_PARAM); + val &= ~0x7ff; + val |= (div - 1) & 0xf; + val |= ((mul - 2) & 0x3f) << 5; + if (od) + val |= 0x10; + writel(val, scu_g6_base + ASPEED_APLL_PARAM); + + return 0; +} + +static const struct clk_ops ast2600_apll_ops = { + .recalc_rate = ast2600_apll_recalc_rate, + .round_rate = ast2600_apll_round_rate, + .set_rate = ast2600_apll_set_rate, +}; + +static struct clk_hw *ast2600_create_apll(void) +{ + int rc; + const char *parent = "clkin"; + struct clk_init_data init = { + .name = "apll", + .ops = &ast2600_apll_ops, + .parent_names = &parent, + .parent_data = NULL, + .parent_hws = NULL, + .num_parents = 1, + .flags = 0, + }; + struct clk_hw *clk = kzalloc(sizeof(*clk), GFP_KERNEL); + + if (!clk) + return ERR_PTR(-ENOMEM); + + clk->init = &init; + rc = of_clk_hw_register(NULL, clk); + if (rc) { + kfree(clk); + clk = ERR_PTR(rc); + } + + return clk; }; static u32 get_bit(u8 idx) @@ -630,6 +774,16 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev) return PTR_ERR(hw); aspeed_g6_clk_data->hws[ASPEED_CLK_ECLK] = hw; + hw = clk_hw_register_divider_table(dev, "aplln", "apll", + CLK_SET_RATE_PARENT, + scu_g6_base + ASPEED_G6_CLK_SELECTION5, + 28, 3, CLK_DIVIDER_READ_ONLY, + ast2600_eclk_div_table, + &aspeed_g6_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_g6_clk_data->hws[ASPEED_CLK_APLLN] = hw; + for (i = 0; i < ARRAY_SIZE(aspeed_g6_gates); i++) { const struct aspeed_gate_data *gd = &aspeed_g6_gates[i]; u32 gate_flags; @@ -710,8 +864,7 @@ static void __init aspeed_g6_cc(struct regmap *map) regmap_read(map, ASPEED_EPLL_PARAM, &val); aspeed_g6_clk_data->hws[ASPEED_CLK_EPLL] = ast2600_calc_pll("epll", val); - regmap_read(map, ASPEED_APLL_PARAM, &val); - aspeed_g6_clk_data->hws[ASPEED_CLK_APLL] = ast2600_calc_apll("apll", val); + aspeed_g6_clk_data->hws[ASPEED_CLK_APLL] = ast2600_create_apll(); /* Strap bits 12:11 define the AXI/AHB clock frequency ratio (aka HCLK)*/ regmap_read(map, ASPEED_G6_STRAP1, &val); diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h index 62b9520a00fd..a286d63de399 100644 --- a/include/dt-bindings/clock/ast2600-clock.h +++ b/include/dt-bindings/clock/ast2600-clock.h @@ -87,6 +87,7 @@ #define ASPEED_CLK_MAC2RCLK 68 #define ASPEED_CLK_MAC3RCLK 69 #define ASPEED_CLK_MAC4RCLK 70 +#define ASPEED_CLK_APLLN 71 /* Only list resets here that are not part of a gate */ #define ASPEED_RESET_ADC 55 -- 2.26.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock 2020-08-24 22:10 ` [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock Eddie James @ 2020-09-01 6:36 ` Joel Stanley 2020-09-02 15:28 ` Eddie James 0 siblings, 1 reply; 9+ messages in thread From: Joel Stanley @ 2020-09-01 6:36 UTC (permalink / raw) To: Eddie James; +Cc: OpenBMC Maillist, Andrew Jeffery On Mon, 24 Aug 2020 at 22:11, Eddie James <eajames@linux.ibm.com> wrote: > > Register a clock with it's own operations to describe the APLL on > the AST2600. The clock is controlled by an SCU register containing > a multiplier and divider of the 25MHz input clock. > The functionality to change the APLL is necessary to finely control > the FSI clock. I thought the FSI clock could be sourced from either the APLL or another PLL. Should we go to the effort of modelling that in the clock driver? > > Signed-off-by: Eddie James <eajames@linux.ibm.com> > --- > drivers/clk/clk-ast2600.c | 177 ++++++++++++++++++++-- > include/dt-bindings/clock/ast2600-clock.h | 1 + > 2 files changed, 166 insertions(+), 12 deletions(-) > > diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c > index bbacaccad554..975677491f09 100644 > --- a/drivers/clk/clk-ast2600.c > +++ b/drivers/clk/clk-ast2600.c > @@ -4,6 +4,7 @@ > > #define pr_fmt(fmt) "clk-ast2600: " fmt > > +#include <linux/kernel.h> > #include <linux/mfd/syscon.h> > #include <linux/of_address.h> > #include <linux/of_device.h> > @@ -15,7 +16,7 @@ > > #include "clk-aspeed.h" > > -#define ASPEED_G6_NUM_CLKS 71 > +#define ASPEED_G6_NUM_CLKS 72 > > #define ASPEED_G6_SILICON_REV 0x004 > > @@ -31,6 +32,7 @@ > #define ASPEED_G6_CLK_SELECTION1 0x300 > #define ASPEED_G6_CLK_SELECTION2 0x304 > #define ASPEED_G6_CLK_SELECTION4 0x310 > +#define ASPEED_G6_CLK_SELECTION5 0x314 > > #define ASPEED_HPLL_PARAM 0x200 > #define ASPEED_APLL_PARAM 0x210 > @@ -116,7 +118,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { > [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uartx", 0 }, /* UART11 */ > [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uartx", 0 }, /* UART12 */ > [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uartx", 0 }, /* UART13 */ > - [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", NULL, 0 }, /* FSI */ > + [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", "aplln", CLK_SET_RATE_PARENT }, /* FSI */ > }; > > static const struct clk_div_table ast2600_eclk_div_table[] = { > @@ -187,24 +189,166 @@ static struct clk_hw *ast2600_calc_pll(const char *name, u32 val) > mult, div); > }; > > -static struct clk_hw *ast2600_calc_apll(const char *name, u32 val) > +/* > + * APLL Frequency: F = 25MHz * (2 - od) * [(m + 2) / (n + 1)] > + */ > +static void ast2600_apll_get_params(unsigned int *div, unsigned int *mul) > { > - unsigned int mult, div; > + u32 val = readl(scu_g6_base + ASPEED_APLL_PARAM); > > if (val & BIT(20)) { > /* Pass through mode */ > - mult = div = 1; > + *mul = *div = 1; > } else { > - /* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */ > u32 m = (val >> 5) & 0x3f; > u32 od = (val >> 4) & 0x1; > u32 n = val & 0xf; > > - mult = (2 - od) * (m + 2); > - div = n + 1; > + *mul = (2 - od) * (m + 2); > + *div = n + 1; > } > - return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, > - mult, div); > +} > + > +static long ast2600_apll_best(unsigned long ul_rate, unsigned long ul_prate, > + unsigned int *out_div, unsigned int *out_mul, > + unsigned int *output_divider) > +{ > +#define min_mult 2ULL > +#define max_mult 65ULL > +#define min_div 1ULL > +#define max_div 16ULL > + int i; > + unsigned int bod = 0; > + unsigned long long rem = 1ULL; > + unsigned long long brem = ~(0ULL); > + unsigned long long bdiv = 1ULL; > + unsigned long long tdiv; > + unsigned long long bmul = 16ULL; > + unsigned long long tmul; > + long brate = -ERANGE; > + unsigned long long trate; > + unsigned long long rate = ul_rate; > + unsigned long long prate = ul_prate; This is pretty full on. Can you take a look at some other clock drivers and see how they solve it? Can we hardcode a few known configurations, and select the closest? If we have to do a search, take a look at something like rational_best_approximation in include/linux/rational.h Importantly, send the changes to the clk driver upstream for review instead of doing a v2 on the openbmc list. > + > + for (i = 0; i < 2; ++i, prate *= 2ULL) { > + for (tdiv = min_div; tdiv <= max_div; ++tdiv) { > + tmul = DIV_ROUND_CLOSEST_ULL(rate * tdiv, prate); > + if (tmul < min_mult || tmul > max_mult) > + continue; > + > + trate = DIV_ROUND_CLOSEST_ULL(prate * tmul, tdiv); > + if (trate > rate) > + rem = trate - rate; > + else > + rem = rate - trate; > + > + if (rem < brem) { > + bod = !i; > + brem = rem; > + bdiv = tdiv; > + bmul = tmul; > + brate = (long)trate; > + } > + > + if (!rem) > + break; > + } > + > + if (!rem) > + break; > + } > + > + if (out_div) > + *out_div = (unsigned int)bdiv; > + > + if (out_mul) > + *out_mul = (unsigned int)bmul; > + > + if (output_divider) > + *output_divider = bod; > + > + return brate; > +#undef min_mult > +#undef max_mult > +#undef min_div > +#undef max_div > +} > + > +static unsigned long ast2600_apll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + unsigned int div; > + unsigned int mul; > + unsigned long long rate; > + unsigned long long prate = (unsigned long long)parent_rate; > + > + ast2600_apll_get_params(&div, &mul); > + > + rate = DIV_ROUND_CLOSEST_ULL(prate * (unsigned long long)mul, div); > + return (unsigned long)rate; > +} > + > +static long ast2600_apll_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ > + return ast2600_apll_best(rate, *parent_rate, NULL, NULL, NULL); > +} > + > +static int ast2600_apll_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + u32 val; > + unsigned int od; > + unsigned int div; > + unsigned int mul; > + long brate = ast2600_apll_best(rate, parent_rate, &div, &mul, &od); > + > + if (brate < 0) > + return brate; > + > + val = readl(scu_g6_base + ASPEED_APLL_PARAM); > + val &= ~0x7ff; > + val |= (div - 1) & 0xf; > + val |= ((mul - 2) & 0x3f) << 5; > + if (od) > + val |= 0x10; > + writel(val, scu_g6_base + ASPEED_APLL_PARAM); > + > + return 0; > +} > + > +static const struct clk_ops ast2600_apll_ops = { > + .recalc_rate = ast2600_apll_recalc_rate, > + .round_rate = ast2600_apll_round_rate, > + .set_rate = ast2600_apll_set_rate, > +}; > + > +static struct clk_hw *ast2600_create_apll(void) > +{ > + int rc; > + const char *parent = "clkin"; > + struct clk_init_data init = { const? > + .name = "apll", > + .ops = &ast2600_apll_ops, > + .parent_names = &parent, > + .parent_data = NULL, > + .parent_hws = NULL, > + .num_parents = 1, > + .flags = 0, > + }; > + struct clk_hw *clk = kzalloc(sizeof(*clk), GFP_KERNEL); > + > + if (!clk) > + return ERR_PTR(-ENOMEM); > + > + clk->init = &init; > + rc = of_clk_hw_register(NULL, clk); > + if (rc) { > + kfree(clk); > + clk = ERR_PTR(rc); > + } > + > + return clk; > }; > > static u32 get_bit(u8 idx) > @@ -630,6 +774,16 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev) > return PTR_ERR(hw); > aspeed_g6_clk_data->hws[ASPEED_CLK_ECLK] = hw; > > + hw = clk_hw_register_divider_table(dev, "aplln", "apll", > + CLK_SET_RATE_PARENT, > + scu_g6_base + ASPEED_G6_CLK_SELECTION5, > + 28, 3, CLK_DIVIDER_READ_ONLY, > + ast2600_eclk_div_table, > + &aspeed_g6_clk_lock); > + if (IS_ERR(hw)) > + return PTR_ERR(hw); > + aspeed_g6_clk_data->hws[ASPEED_CLK_APLLN] = hw; > + > for (i = 0; i < ARRAY_SIZE(aspeed_g6_gates); i++) { > const struct aspeed_gate_data *gd = &aspeed_g6_gates[i]; > u32 gate_flags; > @@ -710,8 +864,7 @@ static void __init aspeed_g6_cc(struct regmap *map) > regmap_read(map, ASPEED_EPLL_PARAM, &val); > aspeed_g6_clk_data->hws[ASPEED_CLK_EPLL] = ast2600_calc_pll("epll", val); > > - regmap_read(map, ASPEED_APLL_PARAM, &val); > - aspeed_g6_clk_data->hws[ASPEED_CLK_APLL] = ast2600_calc_apll("apll", val); > + aspeed_g6_clk_data->hws[ASPEED_CLK_APLL] = ast2600_create_apll(); > > /* Strap bits 12:11 define the AXI/AHB clock frequency ratio (aka HCLK)*/ > regmap_read(map, ASPEED_G6_STRAP1, &val); > diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h > index 62b9520a00fd..a286d63de399 100644 > --- a/include/dt-bindings/clock/ast2600-clock.h > +++ b/include/dt-bindings/clock/ast2600-clock.h > @@ -87,6 +87,7 @@ > #define ASPEED_CLK_MAC2RCLK 68 > #define ASPEED_CLK_MAC3RCLK 69 > #define ASPEED_CLK_MAC4RCLK 70 > +#define ASPEED_CLK_APLLN 71 > > /* Only list resets here that are not part of a gate */ > #define ASPEED_RESET_ADC 55 > -- > 2.26.2 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock 2020-09-01 6:36 ` Joel Stanley @ 2020-09-02 15:28 ` Eddie James 0 siblings, 0 replies; 9+ messages in thread From: Eddie James @ 2020-09-02 15:28 UTC (permalink / raw) To: Joel Stanley; +Cc: OpenBMC Maillist, Andrew Jeffery On 9/1/20 1:36 AM, Joel Stanley wrote: > On Mon, 24 Aug 2020 at 22:11, Eddie James <eajames@linux.ibm.com> wrote: >> Register a clock with it's own operations to describe the APLL on >> the AST2600. The clock is controlled by an SCU register containing >> a multiplier and divider of the 25MHz input clock. >> The functionality to change the APLL is necessary to finely control >> the FSI clock. > I thought the FSI clock could be sourced from either the APLL or > another PLL. Should we go to the effort of modelling that in the clock > driver? Hm, I don't see that in the specification? Thanks, Eddie > >> Signed-off-by: Eddie James <eajames@linux.ibm.com> >> --- >> drivers/clk/clk-ast2600.c | 177 ++++++++++++++++++++-- >> include/dt-bindings/clock/ast2600-clock.h | 1 + >> 2 files changed, 166 insertions(+), 12 deletions(-) >> >> diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c >> index bbacaccad554..975677491f09 100644 >> --- a/drivers/clk/clk-ast2600.c >> +++ b/drivers/clk/clk-ast2600.c >> @@ -4,6 +4,7 @@ >> >> #define pr_fmt(fmt) "clk-ast2600: " fmt >> >> +#include <linux/kernel.h> >> #include <linux/mfd/syscon.h> >> #include <linux/of_address.h> >> #include <linux/of_device.h> >> @@ -15,7 +16,7 @@ >> >> #include "clk-aspeed.h" >> >> -#define ASPEED_G6_NUM_CLKS 71 >> +#define ASPEED_G6_NUM_CLKS 72 >> >> #define ASPEED_G6_SILICON_REV 0x004 >> >> @@ -31,6 +32,7 @@ >> #define ASPEED_G6_CLK_SELECTION1 0x300 >> #define ASPEED_G6_CLK_SELECTION2 0x304 >> #define ASPEED_G6_CLK_SELECTION4 0x310 >> +#define ASPEED_G6_CLK_SELECTION5 0x314 >> >> #define ASPEED_HPLL_PARAM 0x200 >> #define ASPEED_APLL_PARAM 0x210 >> @@ -116,7 +118,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { >> [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uartx", 0 }, /* UART11 */ >> [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uartx", 0 }, /* UART12 */ >> [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uartx", 0 }, /* UART13 */ >> - [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", NULL, 0 }, /* FSI */ >> + [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", "aplln", CLK_SET_RATE_PARENT }, /* FSI */ >> }; >> >> static const struct clk_div_table ast2600_eclk_div_table[] = { >> @@ -187,24 +189,166 @@ static struct clk_hw *ast2600_calc_pll(const char *name, u32 val) >> mult, div); >> }; >> >> -static struct clk_hw *ast2600_calc_apll(const char *name, u32 val) >> +/* >> + * APLL Frequency: F = 25MHz * (2 - od) * [(m + 2) / (n + 1)] >> + */ >> +static void ast2600_apll_get_params(unsigned int *div, unsigned int *mul) >> { >> - unsigned int mult, div; >> + u32 val = readl(scu_g6_base + ASPEED_APLL_PARAM); >> >> if (val & BIT(20)) { >> /* Pass through mode */ >> - mult = div = 1; >> + *mul = *div = 1; >> } else { >> - /* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */ >> u32 m = (val >> 5) & 0x3f; >> u32 od = (val >> 4) & 0x1; >> u32 n = val & 0xf; >> >> - mult = (2 - od) * (m + 2); >> - div = n + 1; >> + *mul = (2 - od) * (m + 2); >> + *div = n + 1; >> } >> - return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, >> - mult, div); >> +} >> + >> +static long ast2600_apll_best(unsigned long ul_rate, unsigned long ul_prate, >> + unsigned int *out_div, unsigned int *out_mul, >> + unsigned int *output_divider) >> +{ >> +#define min_mult 2ULL >> +#define max_mult 65ULL >> +#define min_div 1ULL >> +#define max_div 16ULL >> + int i; >> + unsigned int bod = 0; >> + unsigned long long rem = 1ULL; >> + unsigned long long brem = ~(0ULL); >> + unsigned long long bdiv = 1ULL; >> + unsigned long long tdiv; >> + unsigned long long bmul = 16ULL; >> + unsigned long long tmul; >> + long brate = -ERANGE; >> + unsigned long long trate; >> + unsigned long long rate = ul_rate; >> + unsigned long long prate = ul_prate; > This is pretty full on. Can you take a look at some other clock > drivers and see how they solve it? > > Can we hardcode a few known configurations, and select the closest? > > If we have to do a search, take a look at something like > rational_best_approximation in include/linux/rational.h > > Importantly, send the changes to the clk driver upstream for review > instead of doing a v2 on the openbmc list. > >> + >> + for (i = 0; i < 2; ++i, prate *= 2ULL) { >> + for (tdiv = min_div; tdiv <= max_div; ++tdiv) { >> + tmul = DIV_ROUND_CLOSEST_ULL(rate * tdiv, prate); >> + if (tmul < min_mult || tmul > max_mult) >> + continue; >> + >> + trate = DIV_ROUND_CLOSEST_ULL(prate * tmul, tdiv); >> + if (trate > rate) >> + rem = trate - rate; >> + else >> + rem = rate - trate; >> + >> + if (rem < brem) { >> + bod = !i; >> + brem = rem; >> + bdiv = tdiv; >> + bmul = tmul; >> + brate = (long)trate; >> + } >> + >> + if (!rem) >> + break; >> + } >> + >> + if (!rem) >> + break; >> + } >> + >> + if (out_div) >> + *out_div = (unsigned int)bdiv; >> + >> + if (out_mul) >> + *out_mul = (unsigned int)bmul; >> + >> + if (output_divider) >> + *output_divider = bod; >> + >> + return brate; >> +#undef min_mult >> +#undef max_mult >> +#undef min_div >> +#undef max_div >> +} >> + >> +static unsigned long ast2600_apll_recalc_rate(struct clk_hw *hw, >> + unsigned long parent_rate) >> +{ >> + unsigned int div; >> + unsigned int mul; >> + unsigned long long rate; >> + unsigned long long prate = (unsigned long long)parent_rate; >> + >> + ast2600_apll_get_params(&div, &mul); >> + >> + rate = DIV_ROUND_CLOSEST_ULL(prate * (unsigned long long)mul, div); >> + return (unsigned long)rate; >> +} >> + >> +static long ast2600_apll_round_rate(struct clk_hw *hw, unsigned long rate, >> + unsigned long *parent_rate) >> +{ >> + return ast2600_apll_best(rate, *parent_rate, NULL, NULL, NULL); >> +} >> + >> +static int ast2600_apll_set_rate(struct clk_hw *hw, unsigned long rate, >> + unsigned long parent_rate) >> +{ >> + u32 val; >> + unsigned int od; >> + unsigned int div; >> + unsigned int mul; >> + long brate = ast2600_apll_best(rate, parent_rate, &div, &mul, &od); >> + >> + if (brate < 0) >> + return brate; >> + >> + val = readl(scu_g6_base + ASPEED_APLL_PARAM); >> + val &= ~0x7ff; >> + val |= (div - 1) & 0xf; >> + val |= ((mul - 2) & 0x3f) << 5; >> + if (od) >> + val |= 0x10; >> + writel(val, scu_g6_base + ASPEED_APLL_PARAM); >> + >> + return 0; >> +} >> + >> +static const struct clk_ops ast2600_apll_ops = { >> + .recalc_rate = ast2600_apll_recalc_rate, >> + .round_rate = ast2600_apll_round_rate, >> + .set_rate = ast2600_apll_set_rate, >> +}; >> + >> +static struct clk_hw *ast2600_create_apll(void) >> +{ >> + int rc; >> + const char *parent = "clkin"; >> + struct clk_init_data init = { > const? > >> + .name = "apll", >> + .ops = &ast2600_apll_ops, >> + .parent_names = &parent, >> + .parent_data = NULL, >> + .parent_hws = NULL, >> + .num_parents = 1, >> + .flags = 0, >> + }; >> + struct clk_hw *clk = kzalloc(sizeof(*clk), GFP_KERNEL); >> + >> + if (!clk) >> + return ERR_PTR(-ENOMEM); >> + >> + clk->init = &init; >> + rc = of_clk_hw_register(NULL, clk); >> + if (rc) { >> + kfree(clk); >> + clk = ERR_PTR(rc); >> + } >> + >> + return clk; >> }; >> >> static u32 get_bit(u8 idx) >> @@ -630,6 +774,16 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev) >> return PTR_ERR(hw); >> aspeed_g6_clk_data->hws[ASPEED_CLK_ECLK] = hw; >> >> + hw = clk_hw_register_divider_table(dev, "aplln", "apll", >> + CLK_SET_RATE_PARENT, >> + scu_g6_base + ASPEED_G6_CLK_SELECTION5, >> + 28, 3, CLK_DIVIDER_READ_ONLY, >> + ast2600_eclk_div_table, >> + &aspeed_g6_clk_lock); >> + if (IS_ERR(hw)) >> + return PTR_ERR(hw); >> + aspeed_g6_clk_data->hws[ASPEED_CLK_APLLN] = hw; >> + >> for (i = 0; i < ARRAY_SIZE(aspeed_g6_gates); i++) { >> const struct aspeed_gate_data *gd = &aspeed_g6_gates[i]; >> u32 gate_flags; >> @@ -710,8 +864,7 @@ static void __init aspeed_g6_cc(struct regmap *map) >> regmap_read(map, ASPEED_EPLL_PARAM, &val); >> aspeed_g6_clk_data->hws[ASPEED_CLK_EPLL] = ast2600_calc_pll("epll", val); >> >> - regmap_read(map, ASPEED_APLL_PARAM, &val); >> - aspeed_g6_clk_data->hws[ASPEED_CLK_APLL] = ast2600_calc_apll("apll", val); >> + aspeed_g6_clk_data->hws[ASPEED_CLK_APLL] = ast2600_create_apll(); >> >> /* Strap bits 12:11 define the AXI/AHB clock frequency ratio (aka HCLK)*/ >> regmap_read(map, ASPEED_G6_STRAP1, &val); >> diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h >> index 62b9520a00fd..a286d63de399 100644 >> --- a/include/dt-bindings/clock/ast2600-clock.h >> +++ b/include/dt-bindings/clock/ast2600-clock.h >> @@ -87,6 +87,7 @@ >> #define ASPEED_CLK_MAC2RCLK 68 >> #define ASPEED_CLK_MAC3RCLK 69 >> #define ASPEED_CLK_MAC4RCLK 70 >> +#define ASPEED_CLK_APLLN 71 >> >> /* Only list resets here that are not part of a gate */ >> #define ASPEED_RESET_ADC 55 >> -- >> 2.26.2 >> ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH linux dev-5.8 2/4] dt-bindings: fsi: Aspeed master: Add clock-frequency property 2020-08-24 22:10 [PATCH linux dev-5.8 0/4] AST2600 clock and FSI: Add APLL to control FSI clock Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock Eddie James @ 2020-08-24 22:10 ` Eddie James 2020-09-01 6:38 ` Joel Stanley 2020-08-24 22:10 ` [PATCH linux dev-5.8 3/4] fsi: Aspeed master: Set clock frequency from devicetree Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 4/4] ARM: dts: Aspeed: Rainier: Set FSI clock frequency Eddie James 3 siblings, 1 reply; 9+ messages in thread From: Eddie James @ 2020-08-24 22:10 UTC (permalink / raw) To: openbmc; +Cc: joel, andrew Document the clock-frequency property. Signed-off-by: Eddie James <eajames@linux.ibm.com> --- Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt index a513e65ec0c9..f10abef837e6 100644 --- a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt +++ b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt @@ -17,6 +17,7 @@ Optional properties: - fsi-routing-gpios: GPIO for setting the FSI mux (internal or cabled) - fsi-mux-gpios: GPIO for detecting the desired FSI mux state + - clock-frequency: the frequency of the FSI clock Examples: -- 2.26.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH linux dev-5.8 2/4] dt-bindings: fsi: Aspeed master: Add clock-frequency property 2020-08-24 22:10 ` [PATCH linux dev-5.8 2/4] dt-bindings: fsi: Aspeed master: Add clock-frequency property Eddie James @ 2020-09-01 6:38 ` Joel Stanley 0 siblings, 0 replies; 9+ messages in thread From: Joel Stanley @ 2020-09-01 6:38 UTC (permalink / raw) To: Eddie James; +Cc: OpenBMC Maillist, Andrew Jeffery On Mon, 24 Aug 2020 at 22:11, Eddie James <eajames@linux.ibm.com> wrote: > > Document the clock-frequency property. > > Signed-off-by: Eddie James <eajames@linux.ibm.com> > --- > Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt > index a513e65ec0c9..f10abef837e6 100644 > --- a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt > +++ b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt > @@ -17,6 +17,7 @@ Optional properties: > > - fsi-routing-gpios: GPIO for setting the FSI mux (internal or cabled) > - fsi-mux-gpios: GPIO for detecting the desired FSI mux state > + - clock-frequency: the frequency of the FSI clock If we follow the example of i2c, they call the frequency of the i2c bus the bus-frequency. This stops us from confusing it with the input clock of the AHB or OPB or whatever peripheral bus is inside the SoC. > > > Examples: > -- > 2.26.2 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH linux dev-5.8 3/4] fsi: Aspeed master: Set clock frequency from devicetree 2020-08-24 22:10 [PATCH linux dev-5.8 0/4] AST2600 clock and FSI: Add APLL to control FSI clock Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 2/4] dt-bindings: fsi: Aspeed master: Add clock-frequency property Eddie James @ 2020-08-24 22:10 ` Eddie James 2020-09-01 6:39 ` Joel Stanley 2020-08-24 22:10 ` [PATCH linux dev-5.8 4/4] ARM: dts: Aspeed: Rainier: Set FSI clock frequency Eddie James 3 siblings, 1 reply; 9+ messages in thread From: Eddie James @ 2020-08-24 22:10 UTC (permalink / raw) To: openbmc; +Cc: joel, andrew Set the FSI clock frequency based on the value encoded in the devicetree, if present. Signed-off-by: Eddie James <eajames@linux.ibm.com> --- drivers/fsi/fsi-master-aspeed.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index c006ec008a1a..aedcc9be48ca 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -515,6 +515,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) struct fsi_master_aspeed *aspeed; struct resource *res; int rc, links, reg; + u32 clk_freq; __be32 raw; rc = tacoma_cabled_fsi_fixup(&pdev->dev); @@ -539,6 +540,11 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) dev_err(aspeed->dev, "couldn't get clock\n"); return PTR_ERR(aspeed->clk); } + + if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &clk_freq)) + clk_set_rate(aspeed->clk, clk_freq); + rc = clk_prepare_enable(aspeed->clk); if (rc) { dev_err(aspeed->dev, "couldn't enable clock\n"); -- 2.26.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH linux dev-5.8 3/4] fsi: Aspeed master: Set clock frequency from devicetree 2020-08-24 22:10 ` [PATCH linux dev-5.8 3/4] fsi: Aspeed master: Set clock frequency from devicetree Eddie James @ 2020-09-01 6:39 ` Joel Stanley 0 siblings, 0 replies; 9+ messages in thread From: Joel Stanley @ 2020-09-01 6:39 UTC (permalink / raw) To: Eddie James; +Cc: OpenBMC Maillist, Andrew Jeffery On Mon, 24 Aug 2020 at 22:11, Eddie James <eajames@linux.ibm.com> wrote: > > Set the FSI clock frequency based on the value encoded in the > devicetree, if present. Should we default it to 166 if it's not present? Reviewed-by: Joel Stanley <joel@jms.id.au> > > Signed-off-by: Eddie James <eajames@linux.ibm.com> > --- > drivers/fsi/fsi-master-aspeed.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c > index c006ec008a1a..aedcc9be48ca 100644 > --- a/drivers/fsi/fsi-master-aspeed.c > +++ b/drivers/fsi/fsi-master-aspeed.c > @@ -515,6 +515,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) > struct fsi_master_aspeed *aspeed; > struct resource *res; > int rc, links, reg; > + u32 clk_freq; > __be32 raw; > > rc = tacoma_cabled_fsi_fixup(&pdev->dev); > @@ -539,6 +540,11 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) > dev_err(aspeed->dev, "couldn't get clock\n"); > return PTR_ERR(aspeed->clk); > } > + > + if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", > + &clk_freq)) > + clk_set_rate(aspeed->clk, clk_freq); > + > rc = clk_prepare_enable(aspeed->clk); > if (rc) { > dev_err(aspeed->dev, "couldn't enable clock\n"); > -- > 2.26.2 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH linux dev-5.8 4/4] ARM: dts: Aspeed: Rainier: Set FSI clock frequency 2020-08-24 22:10 [PATCH linux dev-5.8 0/4] AST2600 clock and FSI: Add APLL to control FSI clock Eddie James ` (2 preceding siblings ...) 2020-08-24 22:10 ` [PATCH linux dev-5.8 3/4] fsi: Aspeed master: Set clock frequency from devicetree Eddie James @ 2020-08-24 22:10 ` Eddie James 3 siblings, 0 replies; 9+ messages in thread From: Eddie James @ 2020-08-24 22:10 UTC (permalink / raw) To: openbmc; +Cc: joel, andrew Set the FSI clock frequency to 166MHz. Signed-off-by: Eddie James <eajames@linux.ibm.com> --- arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts index cbc64a1d14d1..8a1d04feecb0 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts @@ -237,6 +237,7 @@ &emmc { &fsim0 { status = "okay"; + clock-frequency = <166666666>; #address-cells = <2>; #size-cells = <0>; -- 2.26.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2020-09-02 15:28 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-08-24 22:10 [PATCH linux dev-5.8 0/4] AST2600 clock and FSI: Add APLL to control FSI clock Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 1/4] clk: ast2600: Add functionality to the APLL clock Eddie James 2020-09-01 6:36 ` Joel Stanley 2020-09-02 15:28 ` Eddie James 2020-08-24 22:10 ` [PATCH linux dev-5.8 2/4] dt-bindings: fsi: Aspeed master: Add clock-frequency property Eddie James 2020-09-01 6:38 ` Joel Stanley 2020-08-24 22:10 ` [PATCH linux dev-5.8 3/4] fsi: Aspeed master: Set clock frequency from devicetree Eddie James 2020-09-01 6:39 ` Joel Stanley 2020-08-24 22:10 ` [PATCH linux dev-5.8 4/4] ARM: dts: Aspeed: Rainier: Set FSI clock frequency Eddie James
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.