OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From 82a391a067491f4c46b75d0dfe2bf9e5a11aca8e Mon Sep 17 00:00:00 2001 |
2 | From: Yangbo Lu <yangbo.lu@nxp.com> |
||
3 | Date: Wed, 17 Jan 2018 15:15:44 +0800 |
||
4 | Subject: [PATCH 14/30] clk: support layerscape |
||
5 | |||
6 | This is an integrated patch for layerscape clock support. |
||
7 | |||
8 | Signed-off-by: Yuantian Tang <andy.tang@nxp.com> |
||
9 | Signed-off-by: Mingkai Hu <mingkai.hu@nxp.com> |
||
10 | Signed-off-by: Scott Wood <oss@buserror.net> |
||
11 | Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> |
||
12 | --- |
||
13 | drivers/clk/clk-qoriq.c | 179 ++++++++++++++++++++++++++++++++++++++++++++---- |
||
14 | 1 file changed, 164 insertions(+), 15 deletions(-) |
||
15 | |||
16 | --- a/drivers/clk/clk-qoriq.c |
||
17 | +++ b/drivers/clk/clk-qoriq.c |
||
18 | @@ -12,6 +12,7 @@ |
||
19 | |||
20 | #include <linux/clk.h> |
||
21 | #include <linux/clk-provider.h> |
||
22 | +#include <linux/clkdev.h> |
||
23 | #include <linux/fsl/guts.h> |
||
24 | #include <linux/io.h> |
||
25 | #include <linux/kernel.h> |
||
26 | @@ -40,7 +41,7 @@ struct clockgen_pll_div { |
||
27 | }; |
||
28 | |||
29 | struct clockgen_pll { |
||
30 | - struct clockgen_pll_div div[4]; |
||
31 | + struct clockgen_pll_div div[8]; |
||
32 | }; |
||
33 | |||
34 | #define CLKSEL_VALID 1 |
||
35 | @@ -87,7 +88,7 @@ struct clockgen { |
||
36 | struct device_node *node; |
||
37 | void __iomem *regs; |
||
38 | struct clockgen_chipinfo info; /* mutable copy */ |
||
39 | - struct clk *sysclk; |
||
40 | + struct clk *sysclk, *coreclk; |
||
41 | struct clockgen_pll pll[6]; |
||
42 | struct clk *cmux[NUM_CMUX]; |
||
43 | struct clk *hwaccel[NUM_HWACCEL]; |
||
44 | @@ -266,6 +267,39 @@ static const struct clockgen_muxinfo ls1 |
||
45 | }, |
||
46 | }; |
||
47 | |||
48 | +static const struct clockgen_muxinfo ls1046a_hwa1 = { |
||
49 | + { |
||
50 | + {}, |
||
51 | + {}, |
||
52 | + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, |
||
53 | + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, |
||
54 | + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, |
||
55 | + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, |
||
56 | + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, |
||
57 | + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, |
||
58 | + }, |
||
59 | +}; |
||
60 | + |
||
61 | +static const struct clockgen_muxinfo ls1046a_hwa2 = { |
||
62 | + { |
||
63 | + {}, |
||
64 | + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, |
||
65 | + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, |
||
66 | + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, |
||
67 | + {}, |
||
68 | + {}, |
||
69 | + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, |
||
70 | + }, |
||
71 | +}; |
||
72 | + |
||
73 | +static const struct clockgen_muxinfo ls1012a_cmux = { |
||
74 | + { |
||
75 | + [0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, |
||
76 | + {}, |
||
77 | + [2] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, |
||
78 | + } |
||
79 | +}; |
||
80 | + |
||
81 | static const struct clockgen_muxinfo t1023_hwa1 = { |
||
82 | { |
||
83 | {}, |
||
84 | @@ -489,6 +523,42 @@ static const struct clockgen_chipinfo ch |
||
85 | .flags = CG_PLL_8BIT, |
||
86 | }, |
||
87 | { |
||
88 | + .compat = "fsl,ls1046a-clockgen", |
||
89 | + .init_periph = t2080_init_periph, |
||
90 | + .cmux_groups = { |
||
91 | + &t1040_cmux |
||
92 | + }, |
||
93 | + .hwaccel = { |
||
94 | + &ls1046a_hwa1, &ls1046a_hwa2 |
||
95 | + }, |
||
96 | + .cmux_to_group = { |
||
97 | + 0, -1 |
||
98 | + }, |
||
99 | + .pll_mask = 0x07, |
||
100 | + .flags = CG_PLL_8BIT, |
||
101 | + }, |
||
102 | + { |
||
103 | + .compat = "fsl,ls1088a-clockgen", |
||
104 | + .cmux_groups = { |
||
105 | + &clockgen2_cmux_cga12 |
||
106 | + }, |
||
107 | + .cmux_to_group = { |
||
108 | + 0, 0, -1 |
||
109 | + }, |
||
110 | + .pll_mask = 0x07, |
||
111 | + .flags = CG_VER3 | CG_LITTLE_ENDIAN, |
||
112 | + }, |
||
113 | + { |
||
114 | + .compat = "fsl,ls1012a-clockgen", |
||
115 | + .cmux_groups = { |
||
116 | + &ls1012a_cmux |
||
117 | + }, |
||
118 | + .cmux_to_group = { |
||
119 | + 0, -1 |
||
120 | + }, |
||
121 | + .pll_mask = 0x03, |
||
122 | + }, |
||
123 | + { |
||
124 | .compat = "fsl,ls2080a-clockgen", |
||
125 | .cmux_groups = { |
||
126 | &clockgen2_cmux_cga12, &clockgen2_cmux_cgb |
||
127 | @@ -846,7 +916,12 @@ static void __init create_muxes(struct c |
||
128 | |||
129 | static void __init clockgen_init(struct device_node *np); |
||
130 | |||
131 | -/* Legacy nodes may get probed before the parent clockgen node */ |
||
132 | +/* |
||
133 | + * Legacy nodes may get probed before the parent clockgen node. |
||
134 | + * It is assumed that device trees with legacy nodes will not |
||
135 | + * contain a "clocks" property -- otherwise the input clocks may |
||
136 | + * not be initialized at this point. |
||
137 | + */ |
||
138 | static void __init legacy_init_clockgen(struct device_node *np) |
||
139 | { |
||
140 | if (!clockgen.node) |
||
141 | @@ -887,18 +962,13 @@ static struct clk __init |
||
142 | return clk_register_fixed_rate(NULL, name, NULL, 0, rate); |
||
143 | } |
||
144 | |||
145 | -static struct clk *sysclk_from_parent(const char *name) |
||
146 | +static struct clk __init *input_clock(const char *name, struct clk *clk) |
||
147 | { |
||
148 | - struct clk *clk; |
||
149 | - const char *parent_name; |
||
150 | - |
||
151 | - clk = of_clk_get(clockgen.node, 0); |
||
152 | - if (IS_ERR(clk)) |
||
153 | - return clk; |
||
154 | + const char *input_name; |
||
155 | |||
156 | /* Register the input clock under the desired name. */ |
||
157 | - parent_name = __clk_get_name(clk); |
||
158 | - clk = clk_register_fixed_factor(NULL, name, parent_name, |
||
159 | + input_name = __clk_get_name(clk); |
||
160 | + clk = clk_register_fixed_factor(NULL, name, input_name, |
||
161 | 0, 1, 1); |
||
162 | if (IS_ERR(clk)) |
||
163 | pr_err("%s: Couldn't register %s: %ld\n", __func__, name, |
||
164 | @@ -907,6 +977,29 @@ static struct clk *sysclk_from_parent(co |
||
165 | return clk; |
||
166 | } |
||
167 | |||
168 | +static struct clk __init *input_clock_by_name(const char *name, |
||
169 | + const char *dtname) |
||
170 | +{ |
||
171 | + struct clk *clk; |
||
172 | + |
||
173 | + clk = of_clk_get_by_name(clockgen.node, dtname); |
||
174 | + if (IS_ERR(clk)) |
||
175 | + return clk; |
||
176 | + |
||
177 | + return input_clock(name, clk); |
||
178 | +} |
||
179 | + |
||
180 | +static struct clk __init *input_clock_by_index(const char *name, int idx) |
||
181 | +{ |
||
182 | + struct clk *clk; |
||
183 | + |
||
184 | + clk = of_clk_get(clockgen.node, 0); |
||
185 | + if (IS_ERR(clk)) |
||
186 | + return clk; |
||
187 | + |
||
188 | + return input_clock(name, clk); |
||
189 | +} |
||
190 | + |
||
191 | static struct clk * __init create_sysclk(const char *name) |
||
192 | { |
||
193 | struct device_node *sysclk; |
||
194 | @@ -916,7 +1009,11 @@ static struct clk * __init create_sysclk |
||
195 | if (!IS_ERR(clk)) |
||
196 | return clk; |
||
197 | |||
198 | - clk = sysclk_from_parent(name); |
||
199 | + clk = input_clock_by_name(name, "sysclk"); |
||
200 | + if (!IS_ERR(clk)) |
||
201 | + return clk; |
||
202 | + |
||
203 | + clk = input_clock_by_index(name, 0); |
||
204 | if (!IS_ERR(clk)) |
||
205 | return clk; |
||
206 | |||
207 | @@ -927,7 +1024,27 @@ static struct clk * __init create_sysclk |
||
208 | return clk; |
||
209 | } |
||
210 | |||
211 | - pr_err("%s: No input clock\n", __func__); |
||
212 | + pr_err("%s: No input sysclk\n", __func__); |
||
213 | + return NULL; |
||
214 | +} |
||
215 | + |
||
216 | +static struct clk * __init create_coreclk(const char *name) |
||
217 | +{ |
||
218 | + struct clk *clk; |
||
219 | + |
||
220 | + clk = input_clock_by_name(name, "coreclk"); |
||
221 | + if (!IS_ERR(clk)) |
||
222 | + return clk; |
||
223 | + |
||
224 | + /* |
||
225 | + * This indicates a mix of legacy nodes with the new coreclk |
||
226 | + * mechanism, which should never happen. If this error occurs, |
||
227 | + * don't use the wrong input clock just because coreclk isn't |
||
228 | + * ready yet. |
||
229 | + */ |
||
230 | + if (WARN_ON(PTR_ERR(clk) == -EPROBE_DEFER)) |
||
231 | + return clk; |
||
232 | + |
||
233 | return NULL; |
||
234 | } |
||
235 | |||
236 | @@ -950,11 +1067,19 @@ static void __init create_one_pll(struct |
||
237 | u32 __iomem *reg; |
||
238 | u32 mult; |
||
239 | struct clockgen_pll *pll = &cg->pll[idx]; |
||
240 | + const char *input = "cg-sysclk"; |
||
241 | int i; |
||
242 | |||
243 | if (!(cg->info.pll_mask & (1 << idx))) |
||
244 | return; |
||
245 | |||
246 | + if (cg->coreclk && idx != PLATFORM_PLL) { |
||
247 | + if (IS_ERR(cg->coreclk)) |
||
248 | + return; |
||
249 | + |
||
250 | + input = "cg-coreclk"; |
||
251 | + } |
||
252 | + |
||
253 | if (cg->info.flags & CG_VER3) { |
||
254 | switch (idx) { |
||
255 | case PLATFORM_PLL: |
||
256 | @@ -1000,12 +1125,20 @@ static void __init create_one_pll(struct |
||
257 | |||
258 | for (i = 0; i < ARRAY_SIZE(pll->div); i++) { |
||
259 | struct clk *clk; |
||
260 | + int ret; |
||
261 | + |
||
262 | + /* |
||
263 | + * For platform PLL, there are 8 divider clocks. |
||
264 | + * For core PLL, there are 4 divider clocks at most. |
||
265 | + */ |
||
266 | + if (idx != 0 && i >= 4) |
||
267 | + break; |
||
268 | |||
269 | snprintf(pll->div[i].name, sizeof(pll->div[i].name), |
||
270 | "cg-pll%d-div%d", idx, i + 1); |
||
271 | |||
272 | clk = clk_register_fixed_factor(NULL, |
||
273 | - pll->div[i].name, "cg-sysclk", 0, mult, i + 1); |
||
274 | + pll->div[i].name, input, 0, mult, i + 1); |
||
275 | if (IS_ERR(clk)) { |
||
276 | pr_err("%s: %s: register failed %ld\n", |
||
277 | __func__, pll->div[i].name, PTR_ERR(clk)); |
||
278 | @@ -1013,6 +1146,11 @@ static void __init create_one_pll(struct |
||
279 | } |
||
280 | |||
281 | pll->div[i].clk = clk; |
||
282 | + ret = clk_register_clkdev(clk, pll->div[i].name, NULL); |
||
283 | + if (ret != 0) |
||
284 | + pr_err("%s: %s: register to lookup table failed %ld\n", |
||
285 | + __func__, pll->div[i].name, PTR_ERR(clk)); |
||
286 | + |
||
287 | } |
||
288 | } |
||
289 | |||
290 | @@ -1142,6 +1280,13 @@ static struct clk *clockgen_clk_get(stru |
||
291 | goto bad_args; |
||
292 | clk = pll->div[idx].clk; |
||
293 | break; |
||
294 | + case 5: |
||
295 | + if (idx != 0) |
||
296 | + goto bad_args; |
||
297 | + clk = cg->coreclk; |
||
298 | + if (IS_ERR(clk)) |
||
299 | + clk = NULL; |
||
300 | + break; |
||
301 | default: |
||
302 | goto bad_args; |
||
303 | } |
||
304 | @@ -1253,6 +1398,7 @@ static void __init clockgen_init(struct |
||
305 | clockgen.info.flags |= CG_CMUX_GE_PLAT; |
||
306 | |||
307 | clockgen.sysclk = create_sysclk("cg-sysclk"); |
||
308 | + clockgen.coreclk = create_coreclk("cg-coreclk"); |
||
309 | create_plls(&clockgen); |
||
310 | create_muxes(&clockgen); |
||
311 | |||
312 | @@ -1273,8 +1419,11 @@ err: |
||
313 | |||
314 | CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init); |
||
315 | CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init); |
||
316 | +CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init); |
||
317 | CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init); |
||
318 | CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init); |
||
319 | +CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init); |
||
320 | +CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init); |
||
321 | CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init); |
||
322 | |||
323 | /* Legacy nodes */ |