From: emilio@elopez.com.ar (Emilio López)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 04/10] clk: sunxi: add PLL5 and PLL6 support
Date: Mon, 30 Sep 2013 20:29:30 -0300 [thread overview]
Message-ID: <524A095A.9050306@elopez.com.ar> (raw)
In-Reply-To: <20130930172137.GE5287@lukather>
Hi Maxime,
El 30/09/13 14:21, Maxime Ripard escribi?:
> Hi Emilio,
>
> On Sun, Sep 29, 2013 at 12:49:33AM -0300, Emilio L?pez wrote:
>> This commit implements PLL5 and PLL6 support on the sunxi clock driver.
>> These PLLs use a similar factor clock, but differ on their outputs.
>>
>> Signed-off-by: Emilio L?pez <emilio@elopez.com.ar>
>> ---
>> Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
>> drivers/clk/sunxi/clk-sunxi.c | 182 +++++++++++++++++++++-
>> 2 files changed, 177 insertions(+), 7 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
>> index 7d9245f..773f3ae 100644
>> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
>> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
>> @@ -9,6 +9,8 @@ Required properties:
>> "allwinner,sun4i-osc-clk" - for a gatable oscillator
>> "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4
>> "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
>> + "allwinner,sun4i-pll5-clk" - for the PLL5 clock
>> + "allwinner,sun4i-pll6-clk" - for the PLL6 clock
>> "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
>> "allwinner,sun4i-axi-clk" - for the AXI clock
>> "allwinner,sun4i-axi-gates-clk" - for the AXI gates
>> diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
>> index 77b9f57..b1210f3 100644
>> --- a/drivers/clk/sunxi/clk-sunxi.c
>> +++ b/drivers/clk/sunxi/clk-sunxi.c
>> @@ -210,6 +210,40 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
>> }
>>
>> /**
>> + * sun4i_get_pll5_factors() - calculates n, k factors for PLL5
>> + * PLL5 rate is calculated as follows
>> + * rate = parent_rate * n * (k + 1)
>> + * parent_rate is always 24Mhz
>> + */
>> +
>> +static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
>> + u8 *n, u8 *k, u8 *m, u8 *p)
>> +{
>> + u8 div;
>> +
>> + /* Normalize value to a 24M multiple */
>> + div = *freq / 24000000;
>> + *freq = 24000000 * div;
>
> parent_rate here maybe ?
I'll change it, makes sense even if parent is always 24M.
>> +
>> + /* we were called to round the frequency, we can now return */
>> + if (n == NULL)
>> + return;
>> +
>> + if (div < 31)
>> + *k = 0;
>> + else if (div / 2 < 31)
>> + *k = 1;
>> + else if (div / 3 < 31)
>> + *k = 2;
>> + else
>> + *k = 3;
>> +
>> + *n = DIV_ROUND_UP(div, (*k+1));
>> +}
>> +
>> +
>> +
>> +/**
>> * sun4i_get_apb1_factors() - calculates m, p factors for APB1
>> * APB1 rate is calculated as follows
>> * rate = (parent_rate >> p) / (m + 1);
>> @@ -285,6 +319,13 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
>> .mwidth = 2,
>> };
>>
>> +static struct clk_factors_config sun4i_pll5_config = {
>> + .nshift = 8,
>> + .nwidth = 5,
>> + .kshift = 4,
>> + .kwidth = 2,
>> +};
>> +
>
> The spacing between your functions and structures looks odd. You were
> using 3 newlines the change just above, and now just one?
I'll review the spacing, I use one newline in between elements of the
same set, and three to separate blocks (eg factor related code from
divisor related code)
>> static struct clk_factors_config sun4i_apb1_config = {
>> .mshift = 0,
>> .mwidth = 5,
>> @@ -304,13 +345,19 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = {
>> .getter = sun6i_a31_get_pll1_factors,
>> };
>>
>> +static const struct factors_data sun4i_pll5_data __initconst = {
>> + .enable = 31,
>> + .table = &sun4i_pll5_config,
>> + .getter = sun4i_get_pll5_factors,
>> +};
>> +
>> static const struct factors_data sun4i_apb1_data __initconst = {
>> .table = &sun4i_apb1_config,
>> .getter = sun4i_get_apb1_factors,
>> };
>>
>> -static void __init sunxi_factors_clk_setup(struct device_node *node,
>> - struct factors_data *data)
>> +static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
>> + const struct factors_data *data)
>
> While this change is probably useful, I don't see how it relates to the
> change described in your commit log. Either split these patches, or
> explain why it's needed.
I'll split this into another patch. The change is needed to run
sunxi_factors_clk_setup() in sunxi_divs_clk_setup() while being able to
get the struct clk *
>
>> {
>> struct clk *clk;
>> struct clk_factors *factors;
>> @@ -321,6 +368,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
>> const char *clk_name = node->name;
>> const char *parents[5];
>> void *reg;
>> + unsigned long flags;
>> int i = 0;
>>
>> reg = of_iomap(node, 0);
>> @@ -331,14 +379,14 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
>>
>> factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
>> if (!factors)
>> - return;
>> + return NULL;
>>
>> /* Add a gate if this factor clock can be gated */
>> if (data->enable) {
>> gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
>> if (!gate) {
>> kfree(factors);
>> - return;
>> + return NULL;
>> }
>>
>> /* set up gate properties */
>> @@ -354,7 +402,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
>> if (!mux) {
>> kfree(factors);
>> kfree(gate);
>> - return;
>> + return NULL;
>> }
>>
>> /* set up gate properties */
>> @@ -371,17 +419,21 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
>> factors->get_factors = data->getter;
>> factors->lock = &clk_lock;
>>
>> + /* We should not disable pll5, it powers the RAM */
>> + flags = !strcmp("pll5", clk_name) ? CLK_IGNORE_UNUSED : 0;
>> +
>> clk = clk_register_composite(NULL, clk_name,
>> parents, i,
>> mux_hw, &clk_mux_ops,
>> &factors->hw, &clk_factors_ops,
>> - gate_hw, &clk_gate_ops,
>> - i ? 0 : CLK_IS_ROOT);
>> + gate_hw, &clk_gate_ops, flags);
>>
>> if (!IS_ERR(clk)) {
>> of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> clk_register_clkdev(clk, clk_name, NULL);
>> }
>> +
>> + return clk;
>> }
>>
>>
>> @@ -616,6 +668,112 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
>> of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
>> }
>>
>> +
>> +
>> +/**
>> + * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks
>> + */
>
> This comment doesn't seem to be at the right place in your code.
I use these comments as kind of a delimiter too, all the struct
definitions done below are used on sunxi_divs_clk_setup, which is
immediately after. Factors, mux, dividers and gates have the comment
that way too.
>> +#define SUNXI_DIVS_MAX_QTY 2
>> +#define SUNXI_DIVISOR_WIDTH 2
>> +
>> +struct divs_data {
>> + const struct factors_data *factors; /* data for the factor clock */
>> + struct {
>> + u8 fixed; /* is it a fixed divisor? if not... */
>> + struct clk_div_table *table; /* is it a table based divisor? */
>> + u8 shift; /* otherwise it's a normal divisor with this shift */
>> + u8 pow; /* is it power-of-two based? */
>> + } div[SUNXI_DIVS_MAX_QTY];
>> +};
>> +
>> +static struct clk_div_table pll6_sata_table[] = {
>> + { .val = 0, .div = 6, },
>> + { .val = 1, .div = 12, },
>> + { .val = 2, .div = 18, },
>> + { .val = 3, .div = 24, },
>> + { } /* sentinel */
>> +};
>> +
>> +static const struct divs_data pll5_divs_data __initconst = {
>> + .factors = &sun4i_pll5_data,
>> + .div = {
>> + { .shift = 0, .pow = 0, }, /* M, DDR */
>> + { .shift = 16, .pow = 1, }, /* P, other */
>> + }
>> +};
>> +
>> +static const struct divs_data pll6_divs_data __initconst = {
>> + .factors = &sun4i_pll5_data,
>> + .div = {
>> + { .shift = 0, .table = pll6_sata_table }, /* M, SATA */
>> + { .fixed = 2 }, /* P, other */
>> + }
>> +};
>> +
>> +static void __init sunxi_divs_clk_setup(struct device_node *node,
>> + struct divs_data *data)
>> +{
>> + struct clk_onecell_data *clk_data;
>> + const char *parent = node->name;
>> + const char *clk_name;
>> + struct clk **clks, *pclk;
>> + void *reg;
>> + int i = 0;
>> + int flags, clkflags;
>> +
>> + /* Set up factor clock that we will be dividing */
>> + pclk = sunxi_factors_clk_setup(node, data->factors);
>> +
>> + reg = of_iomap(node, 0);
>> +
>> + clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
>> + if (!clk_data)
>> + return;
>
> An extra newline would be great here.
Ok
>> + clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL);
>> + if (!clks) {
>> + kfree(clk_data);
>> + return;
>> + }
>> + clk_data->clks = clks;
>> +
>> + /* It's not a good idea to have automatic reparenting changing
>> + * our RAM clock! */
>> + clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT;
>> +
>> + for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) {
>> + if (of_property_read_string_index(node, "clock-output-names",
>> + i, &clk_name) != 0)
>> + break;
>> +
>> + if (data->div[i].fixed) {
>> + clks[i] = clk_register_fixed_factor(NULL, clk_name,
>> + parent, clkflags,
>> + 1, data->div[i].fixed);
>> + } else {
>> + flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0;
>> + clks[i] = clk_register_divider_table(NULL, clk_name,
>> + parent, clkflags, reg,
>> + data->div[i].shift,
>> + SUNXI_DIVISOR_WIDTH, flags,
>> + data->div[i].table, &clk_lock);
>> + }
>
> Hmmm, I don't get why you were calling sunxi_clk_factors_setup
> unconditionally, and now you put a condition on the registration?
The factor clock is the 'parent' part and the condition is there to
decide which kind of divisor gets registered under it. For example
PLL6 CLOCK
________________________
| ___pll6_sata---|----> to consumer
osc24M->--| pll6--/___pll6_other--|----> to consumer
| \_______________|____> to consumer
|________________________|
pll6 is the factor part, pll6_sata is a table divider, and pll6_other is
a fixed factor
> (Plus, your indentation here looks a bit odd.)
If I align the parameters with the starting (, I can fit at most 1
parameter per line and I end up with a pile of mostly unreadable
parameters which uses a lot of lines (and still some don't fit in under
80 cols). I thought using one tab less was a good compromise, and
preferable to going over 80 chars. If you have any better suggestion,
I'm all ears :)
>> +
>> + WARN_ON(IS_ERR(clk_data->clks[i]));
>> + clk_register_clkdev(clks[i], clk_name, NULL);
>> + }
>> +
>> + /* The last clock available on the getter is the parent */
>> + clks[i++] = pclk;
>> +
>> + /* Adjust to the real max */
>> + clk_data->clk_num = i;
>> +
>> + of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
>> +}
>> +
>> +
>> +
>> /* Matches for factors clocks */
>> static const struct of_device_id clk_factors_match[] __initconst = {
>> {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
>> @@ -633,6 +791,13 @@ static const struct of_device_id clk_div_match[] __initconst = {
>> {}
>> };
>>
>> +/* Matches for divided outputs */
>> +static const struct of_device_id clk_divs_match[] __initconst = {
>> + {.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,},
>> + {.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,},
>> + {}
>> +};
>> +
>> /* Matches for mux clocks */
>> static const struct of_device_id clk_mux_match[] __initconst = {
>> {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
>> @@ -713,6 +878,9 @@ void __init sunxi_init_clocks(void)
>> /* Register divider clocks */
>> of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup);
>>
>> + /* Register divided output clocks */
>> + of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup);
>> +
>> /* Register mux clocks */
>> of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
>>
>> --
>> 1.8.4
>>
Thanks for reviewing this!
Emilio
next prev parent reply other threads:[~2013-09-30 23:29 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-29 3:49 [PATCH 00/10] clk: sunxi: PLL4/5/6, mod0 and mbus support Emilio López
2013-09-29 3:49 ` [PATCH 01/10] clk: sunxi: register factors clocks behind composite Emilio López
2013-09-30 17:03 ` Maxime Ripard
2013-09-29 3:49 ` [PATCH 02/10] clk: sunxi: add gating support to PLL1 Emilio López
2013-09-30 17:05 ` Maxime Ripard
2013-09-29 3:49 ` [PATCH 03/10] ARM: sunxi: add PLL4 support Emilio López
2013-09-29 3:49 ` [PATCH 04/10] clk: sunxi: add PLL5 and PLL6 support Emilio López
2013-09-30 17:21 ` Maxime Ripard
2013-09-30 23:29 ` Emilio López [this message]
2013-10-03 10:32 ` Maxime Ripard
2013-09-29 3:49 ` [PATCH 05/10] ARM: " Emilio López
2013-09-29 3:49 ` [PATCH 06/10] clk: sunxi: mod0 support Emilio López
2013-09-30 17:35 ` Maxime Ripard
2013-09-30 23:37 ` Emilio López
2013-10-02 14:38 ` Maxime Ripard
2013-09-29 3:49 ` [PATCH 07/10] ARM: sun4i: dt: mod0 clocks Emilio López
2013-09-29 3:49 ` [PATCH 08/10] ARM: sun5i: " Emilio López
2013-09-29 3:49 ` [PATCH 09/10] ARM: sun7i: " Emilio López
2013-09-29 3:49 ` [PATCH 10/10] ARM: sunxi: dt: add nodes for the mbus clock Emilio López
2013-09-30 17:38 ` [PATCH 00/10] clk: sunxi: PLL4/5/6, mod0 and mbus support Maxime Ripard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=524A095A.9050306@elopez.com.ar \
--to=emilio@elopez.com.ar \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.