f680a42e1fc55c3ce63a996c4ad52e5d56ed389e
[openwrt.git] / target / linux / sunxi / patches-3.12 / 103-clk-sunxi_add_pll5-6.patch
1 From cad227619badf2a0ff2593d9935fedc84d5ef1ef Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
3 Date: Sun, 26 May 2013 14:23:50 -0300
4 Subject: [PATCH] clk: sunxi: add PLL5 and PLL6 support
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 This commit implements PLL5 and PLL6 support on the sunxi clock driver.
10 These PLLs use a similar factor clock, but differ on their outputs.
11
12 Signed-off-by: Emilio López <emilio@elopez.com.ar>
13 ---
14  Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
15  drivers/clk/sunxi/clk-sunxi.c                     | 182 +++++++++++++++++++++-
16  2 files changed, 177 insertions(+), 7 deletions(-)
17
18 diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
19 index 7d9245f..773f3ae 100644
20 --- a/Documentation/devicetree/bindings/clock/sunxi.txt
21 +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
22 @@ -9,6 +9,8 @@ Required properties:
23         "allwinner,sun4i-osc-clk" - for a gatable oscillator
24         "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4
25         "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
26 +       "allwinner,sun4i-pll5-clk" - for the PLL5 clock
27 +       "allwinner,sun4i-pll6-clk" - for the PLL6 clock
28         "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
29         "allwinner,sun4i-axi-clk" - for the AXI clock
30         "allwinner,sun4i-axi-gates-clk" - for the AXI gates
31 diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
32 index c0b0675..6947ba9 100644
33 --- a/drivers/clk/sunxi/clk-sunxi.c
34 +++ b/drivers/clk/sunxi/clk-sunxi.c
35 @@ -210,6 +210,40 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
36  }
37  
38  /**
39 + * sun4i_get_pll5_factors() - calculates n, k factors for PLL5
40 + * PLL5 rate is calculated as follows
41 + * rate = parent_rate * n * (k + 1)
42 + * parent_rate is always 24Mhz
43 + */
44 +
45 +static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
46 +                                  u8 *n, u8 *k, u8 *m, u8 *p)
47 +{
48 +       u8 div;
49 +
50 +       /* Normalize value to a 24M multiple */
51 +       div = *freq / 24000000;
52 +       *freq = 24000000 * div;
53 +
54 +       /* we were called to round the frequency, we can now return */
55 +       if (n == NULL)
56 +               return;
57 +
58 +       if (div < 31)
59 +               *k = 0;
60 +       else if (div / 2 < 31)
61 +               *k = 1;
62 +       else if (div / 3 < 31)
63 +               *k = 2;
64 +       else
65 +               *k = 3;
66 +
67 +       *n = DIV_ROUND_UP(div, (*k+1));
68 +}
69 +
70 +
71 +
72 +/**
73   * sun4i_get_apb1_factors() - calculates m, p factors for APB1
74   * APB1 rate is calculated as follows
75   * rate = (parent_rate >> p) / (m + 1);
76 @@ -285,6 +319,13 @@ struct factors_data {
77         .mwidth = 2,
78  };
79  
80 +static struct clk_factors_config sun4i_pll5_config = {
81 +       .nshift = 8,
82 +       .nwidth = 5,
83 +       .kshift = 4,
84 +       .kwidth = 2,
85 +};
86 +
87  static struct clk_factors_config sun4i_apb1_config = {
88         .mshift = 0,
89         .mwidth = 5,
90 @@ -304,13 +345,19 @@ struct factors_data {
91         .getter = sun6i_a31_get_pll1_factors,
92  };
93  
94 +static const struct factors_data sun4i_pll5_data __initconst = {
95 +       .enable = 31,
96 +       .table = &sun4i_pll5_config,
97 +       .getter = sun4i_get_pll5_factors,
98 +};
99 +
100  static const struct factors_data sun4i_apb1_data __initconst = {
101         .table = &sun4i_apb1_config,
102         .getter = sun4i_get_apb1_factors,
103  };
104  
105 -static void __init sunxi_factors_clk_setup(struct device_node *node,
106 -                                          struct factors_data *data)
107 +static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
108 +                                               const struct factors_data *data)
109  {
110         struct clk *clk;
111         struct clk_factors *factors;
112 @@ -321,6 +368,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
113         const char *clk_name = node->name;
114         const char *parents[5];
115         void *reg;
116 +       unsigned long flags;
117         int i = 0;
118  
119         reg = of_iomap(node, 0);
120 @@ -331,14 +379,14 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
121  
122         factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
123         if (!factors)
124 -               return;
125 +               return NULL;
126  
127         /* Add a gate if this factor clock can be gated */
128         if (data->enable) {
129                 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
130                 if (!gate) {
131                         kfree(factors);
132 -                       return;
133 +                       return NULL;
134                 }
135  
136                 /* set up gate properties */
137 @@ -354,7 +402,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
138                 if (!mux) {
139                         kfree(factors);
140                         kfree(gate);
141 -                       return;
142 +                       return NULL;
143                 }
144  
145                 /* set up gate properties */
146 @@ -371,17 +419,21 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
147         factors->get_factors = data->getter;
148         factors->lock = &clk_lock;
149  
150 +       /* We should not disable pll5, it powers the RAM */
151 +       flags = !strcmp("pll5", clk_name) ? CLK_IGNORE_UNUSED : 0;
152 +
153         clk = clk_register_composite(NULL, clk_name,
154                         parents, i,
155                         mux_hw, &clk_mux_ops,
156                         &factors->hw, &clk_factors_ops,
157 -                       gate_hw, &clk_gate_ops,
158 -                       i ? 0 : CLK_IS_ROOT);
159 +                       gate_hw, &clk_gate_ops, flags);
160  
161         if (!IS_ERR(clk)) {
162                 of_clk_add_provider(node, of_clk_src_simple_get, clk);
163                 clk_register_clkdev(clk, clk_name, NULL);
164         }
165 +
166 +       return clk;
167  }
168  
169  
170 @@ -616,6 +668,112 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
171         of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
172  }
173  
174 +
175 +
176 +/**
177 + * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks
178 + */
179 +
180 +#define SUNXI_DIVS_MAX_QTY     2
181 +#define SUNXI_DIVISOR_WIDTH    2
182 +
183 +struct divs_data {
184 +       const struct factors_data *factors; /* data for the factor clock */
185 +       struct {
186 +               u8 fixed; /* is it a fixed divisor? if not... */
187 +               struct clk_div_table *table; /* is it a table based divisor? */
188 +               u8 shift; /* otherwise it's a normal divisor with this shift */
189 +               u8 pow;   /* is it power-of-two based? */
190 +       } div[SUNXI_DIVS_MAX_QTY];
191 +};
192 +
193 +static struct clk_div_table pll6_sata_table[] = {
194 +       { .val = 0, .div = 6, },
195 +       { .val = 1, .div = 12, },
196 +       { .val = 2, .div = 18, },
197 +       { .val = 3, .div = 24, },
198 +       { } /* sentinel */
199 +};
200 +
201 +static const struct divs_data pll5_divs_data __initconst = {
202 +       .factors = &sun4i_pll5_data,
203 +       .div = {
204 +               { .shift = 0, .pow = 0, }, /* M, DDR */
205 +               { .shift = 16, .pow = 1, }, /* P, other */
206 +       }
207 +};
208 +
209 +static const struct divs_data pll6_divs_data __initconst = {
210 +       .factors = &sun4i_pll5_data,
211 +       .div = {
212 +               { .shift = 0, .table = pll6_sata_table }, /* M, SATA */
213 +               { .fixed = 2 }, /* P, other */
214 +       }
215 +};
216 +
217 +static void __init sunxi_divs_clk_setup(struct device_node *node,
218 +                                       struct divs_data *data)
219 +{
220 +       struct clk_onecell_data *clk_data;
221 +       const char *parent  = node->name;
222 +       const char *clk_name;
223 +       struct clk **clks, *pclk;
224 +       void *reg;
225 +       int i = 0;
226 +       int flags, clkflags;
227 +
228 +       /* Set up factor clock that we will be dividing */
229 +       pclk = sunxi_factors_clk_setup(node, data->factors);
230 +
231 +       reg = of_iomap(node, 0);
232 +
233 +       clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
234 +       if (!clk_data)
235 +               return;
236 +       clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL);
237 +       if (!clks) {
238 +               kfree(clk_data);
239 +               return;
240 +       }
241 +       clk_data->clks = clks;
242 +
243 +       /* It's not a good idea to have automatic reparenting changing
244 +        * our RAM clock! */
245 +       clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT;
246 +
247 +       for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) {
248 +               if (of_property_read_string_index(node, "clock-output-names",
249 +                                                 i, &clk_name) != 0)
250 +                       break;
251 +
252 +               if (data->div[i].fixed) {
253 +                       clks[i] = clk_register_fixed_factor(NULL, clk_name,
254 +                                               parent, clkflags,
255 +                                               1, data->div[i].fixed);
256 +               } else {
257 +                       flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0;
258 +                       clks[i] = clk_register_divider_table(NULL, clk_name,
259 +                                               parent, clkflags, reg,
260 +                                               data->div[i].shift,
261 +                                               SUNXI_DIVISOR_WIDTH, flags,
262 +                                               data->div[i].table, &clk_lock);
263 +               }
264 +
265 +               WARN_ON(IS_ERR(clk_data->clks[i]));
266 +               clk_register_clkdev(clks[i], clk_name, NULL);
267 +       }
268 +
269 +       /* The last clock available on the getter is the parent */
270 +       clks[i++] = pclk;
271 +
272 +       /* Adjust to the real max */
273 +       clk_data->clk_num = i;
274 +
275 +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
276 +}
277 +
278 +
279 +
280  /* Matches for factors clocks */
281  static const struct of_device_id clk_factors_match[] __initconst = {
282         {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
283 @@ -633,6 +791,13 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
284         {}
285  };
286  
287 +/* Matches for divided outputs */
288 +static const struct of_device_id clk_divs_match[] __initconst = {
289 +       {.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,},
290 +       {.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,},
291 +       {}
292 +};
293 +
294  /* Matches for mux clocks */
295  static const struct of_device_id clk_mux_match[] __initconst = {
296         {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
297 @@ -688,6 +853,9 @@ void __init sunxi_init_clocks(void)
298         /* Register divider clocks */
299         of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup);
300  
301 +       /* Register divided output clocks */
302 +       of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup);
303 +
304         /* Register mux clocks */
305         of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
306  
307 -- 
308 1.8.4
309