2 * Port on Texas Instruments TMS320C6x architecture
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 * Author: Mark Salter <msalter@redhat.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #include <linux/kernel.h>
12 #include <linux/delay.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/ioport.h>
16 #include <linux/clkdev.h>
18 #include <linux/of_address.h>
20 #include <asm/clock.h>
21 #include <asm/setup.h>
25 * Common SoC clock support.
28 /* Default input for PLL1 */
31 .node
= LIST_HEAD_INIT(clkin1
.node
),
32 .children
= LIST_HEAD_INIT(clkin1
.children
),
33 .childnode
= LIST_HEAD_INIT(clkin1
.childnode
),
36 struct pll_data c6x_soc_pll1
= {
42 .pll_data
= &c6x_soc_pll1
,
46 .name
= "pll1_sysclk1",
47 .parent
= &c6x_soc_pll1
.sysclks
[0],
51 .name
= "pll1_sysclk2",
52 .parent
= &c6x_soc_pll1
.sysclks
[0],
56 .name
= "pll1_sysclk3",
57 .parent
= &c6x_soc_pll1
.sysclks
[0],
61 .name
= "pll1_sysclk4",
62 .parent
= &c6x_soc_pll1
.sysclks
[0],
66 .name
= "pll1_sysclk5",
67 .parent
= &c6x_soc_pll1
.sysclks
[0],
71 .name
= "pll1_sysclk6",
72 .parent
= &c6x_soc_pll1
.sysclks
[0],
76 .name
= "pll1_sysclk7",
77 .parent
= &c6x_soc_pll1
.sysclks
[0],
81 .name
= "pll1_sysclk8",
82 .parent
= &c6x_soc_pll1
.sysclks
[0],
86 .name
= "pll1_sysclk9",
87 .parent
= &c6x_soc_pll1
.sysclks
[0],
91 .name
= "pll1_sysclk10",
92 .parent
= &c6x_soc_pll1
.sysclks
[0],
96 .name
= "pll1_sysclk11",
97 .parent
= &c6x_soc_pll1
.sysclks
[0],
101 .name
= "pll1_sysclk12",
102 .parent
= &c6x_soc_pll1
.sysclks
[0],
106 .name
= "pll1_sysclk13",
107 .parent
= &c6x_soc_pll1
.sysclks
[0],
111 .name
= "pll1_sysclk14",
112 .parent
= &c6x_soc_pll1
.sysclks
[0],
116 .name
= "pll1_sysclk15",
117 .parent
= &c6x_soc_pll1
.sysclks
[0],
121 .name
= "pll1_sysclk16",
122 .parent
= &c6x_soc_pll1
.sysclks
[0],
129 struct clk c6x_core_clk
= {
133 /* miscellaneous IO clocks */
134 struct clk c6x_i2c_clk
= {
138 struct clk c6x_watchdog_clk
= {
142 struct clk c6x_mcbsp1_clk
= {
146 struct clk c6x_mcbsp2_clk
= {
150 struct clk c6x_mdio_clk
= {
155 #ifdef CONFIG_SOC_TMS320C6455
156 static struct clk_lookup c6455_clks
[] = {
157 CLK(NULL
, "pll1", &c6x_soc_pll1
.sysclks
[0]),
158 CLK(NULL
, "pll1_sysclk2", &c6x_soc_pll1
.sysclks
[2]),
159 CLK(NULL
, "pll1_sysclk3", &c6x_soc_pll1
.sysclks
[3]),
160 CLK(NULL
, "pll1_sysclk4", &c6x_soc_pll1
.sysclks
[4]),
161 CLK(NULL
, "pll1_sysclk5", &c6x_soc_pll1
.sysclks
[5]),
162 CLK(NULL
, "core", &c6x_core_clk
),
163 CLK("i2c_davinci.1", NULL
, &c6x_i2c_clk
),
164 CLK("watchdog", NULL
, &c6x_watchdog_clk
),
165 CLK("2c81800.mdio", NULL
, &c6x_mdio_clk
),
170 static void __init
c6455_setup_clocks(struct device_node
*node
)
172 struct pll_data
*pll
= &c6x_soc_pll1
;
173 struct clk
*sysclks
= pll
->sysclks
;
175 pll
->flags
= PLL_HAS_PRE
| PLL_HAS_MUL
;
177 sysclks
[2].flags
|= FIXED_DIV_PLL
;
179 sysclks
[3].flags
|= FIXED_DIV_PLL
;
181 sysclks
[4].div
= PLLDIV4
;
182 sysclks
[5].div
= PLLDIV5
;
184 c6x_core_clk
.parent
= &sysclks
[0];
185 c6x_i2c_clk
.parent
= &sysclks
[3];
186 c6x_watchdog_clk
.parent
= &sysclks
[3];
187 c6x_mdio_clk
.parent
= &sysclks
[3];
189 c6x_clks_init(c6455_clks
);
191 #endif /* CONFIG_SOC_TMS320C6455 */
193 #ifdef CONFIG_SOC_TMS320C6457
194 static struct clk_lookup c6457_clks
[] = {
195 CLK(NULL
, "pll1", &c6x_soc_pll1
.sysclks
[0]),
196 CLK(NULL
, "pll1_sysclk1", &c6x_soc_pll1
.sysclks
[1]),
197 CLK(NULL
, "pll1_sysclk2", &c6x_soc_pll1
.sysclks
[2]),
198 CLK(NULL
, "pll1_sysclk3", &c6x_soc_pll1
.sysclks
[3]),
199 CLK(NULL
, "pll1_sysclk4", &c6x_soc_pll1
.sysclks
[4]),
200 CLK(NULL
, "pll1_sysclk5", &c6x_soc_pll1
.sysclks
[5]),
201 CLK(NULL
, "core", &c6x_core_clk
),
202 CLK("i2c_davinci.1", NULL
, &c6x_i2c_clk
),
203 CLK("watchdog", NULL
, &c6x_watchdog_clk
),
204 CLK("2c81800.mdio", NULL
, &c6x_mdio_clk
),
208 static void __init
c6457_setup_clocks(struct device_node
*node
)
210 struct pll_data
*pll
= &c6x_soc_pll1
;
211 struct clk
*sysclks
= pll
->sysclks
;
213 pll
->flags
= PLL_HAS_MUL
| PLL_HAS_POST
;
215 sysclks
[1].flags
|= FIXED_DIV_PLL
;
217 sysclks
[2].flags
|= FIXED_DIV_PLL
;
219 sysclks
[3].flags
|= FIXED_DIV_PLL
;
221 sysclks
[4].div
= PLLDIV4
;
222 sysclks
[5].div
= PLLDIV5
;
224 c6x_core_clk
.parent
= &sysclks
[1];
225 c6x_i2c_clk
.parent
= &sysclks
[3];
226 c6x_watchdog_clk
.parent
= &sysclks
[5];
227 c6x_mdio_clk
.parent
= &sysclks
[5];
229 c6x_clks_init(c6457_clks
);
231 #endif /* CONFIG_SOC_TMS320C6455 */
233 #ifdef CONFIG_SOC_TMS320C6472
234 static struct clk_lookup c6472_clks
[] = {
235 CLK(NULL
, "pll1", &c6x_soc_pll1
.sysclks
[0]),
236 CLK(NULL
, "pll1_sysclk1", &c6x_soc_pll1
.sysclks
[1]),
237 CLK(NULL
, "pll1_sysclk2", &c6x_soc_pll1
.sysclks
[2]),
238 CLK(NULL
, "pll1_sysclk3", &c6x_soc_pll1
.sysclks
[3]),
239 CLK(NULL
, "pll1_sysclk4", &c6x_soc_pll1
.sysclks
[4]),
240 CLK(NULL
, "pll1_sysclk5", &c6x_soc_pll1
.sysclks
[5]),
241 CLK(NULL
, "pll1_sysclk6", &c6x_soc_pll1
.sysclks
[6]),
242 CLK(NULL
, "pll1_sysclk7", &c6x_soc_pll1
.sysclks
[7]),
243 CLK(NULL
, "pll1_sysclk8", &c6x_soc_pll1
.sysclks
[8]),
244 CLK(NULL
, "pll1_sysclk9", &c6x_soc_pll1
.sysclks
[9]),
245 CLK(NULL
, "pll1_sysclk10", &c6x_soc_pll1
.sysclks
[10]),
246 CLK(NULL
, "core", &c6x_core_clk
),
247 CLK("i2c_davinci.1", NULL
, &c6x_i2c_clk
),
248 CLK("watchdog", NULL
, &c6x_watchdog_clk
),
249 CLK("2c81800.mdio", NULL
, &c6x_mdio_clk
),
253 /* assumptions used for delay loop calculations */
254 #define MIN_CLKIN1_KHz 15625
255 #define MAX_CORE_KHz 700000
256 #define MIN_PLLOUT_KHz MIN_CLKIN1_KHz
258 static void __init
c6472_setup_clocks(struct device_node
*node
)
260 struct pll_data
*pll
= &c6x_soc_pll1
;
261 struct clk
*sysclks
= pll
->sysclks
;
264 pll
->flags
= PLL_HAS_MUL
;
266 for (i
= 1; i
<= 6; i
++) {
267 sysclks
[i
].flags
|= FIXED_DIV_PLL
;
271 sysclks
[7].flags
|= FIXED_DIV_PLL
;
273 sysclks
[8].flags
|= FIXED_DIV_PLL
;
275 sysclks
[9].flags
|= FIXED_DIV_PLL
;
277 sysclks
[10].div
= PLLDIV10
;
279 c6x_core_clk
.parent
= &sysclks
[get_coreid() + 1];
280 c6x_i2c_clk
.parent
= &sysclks
[8];
281 c6x_watchdog_clk
.parent
= &sysclks
[8];
282 c6x_mdio_clk
.parent
= &sysclks
[5];
284 c6x_clks_init(c6472_clks
);
286 #endif /* CONFIG_SOC_TMS320C6472 */
289 #ifdef CONFIG_SOC_TMS320C6474
290 static struct clk_lookup c6474_clks
[] = {
291 CLK(NULL
, "pll1", &c6x_soc_pll1
.sysclks
[0]),
292 CLK(NULL
, "pll1_sysclk7", &c6x_soc_pll1
.sysclks
[7]),
293 CLK(NULL
, "pll1_sysclk9", &c6x_soc_pll1
.sysclks
[9]),
294 CLK(NULL
, "pll1_sysclk10", &c6x_soc_pll1
.sysclks
[10]),
295 CLK(NULL
, "pll1_sysclk11", &c6x_soc_pll1
.sysclks
[11]),
296 CLK(NULL
, "pll1_sysclk12", &c6x_soc_pll1
.sysclks
[12]),
297 CLK(NULL
, "pll1_sysclk13", &c6x_soc_pll1
.sysclks
[13]),
298 CLK(NULL
, "core", &c6x_core_clk
),
299 CLK("i2c_davinci.1", NULL
, &c6x_i2c_clk
),
300 CLK("mcbsp.1", NULL
, &c6x_mcbsp1_clk
),
301 CLK("mcbsp.2", NULL
, &c6x_mcbsp2_clk
),
302 CLK("watchdog", NULL
, &c6x_watchdog_clk
),
303 CLK("2c81800.mdio", NULL
, &c6x_mdio_clk
),
307 static void __init
c6474_setup_clocks(struct device_node
*node
)
309 struct pll_data
*pll
= &c6x_soc_pll1
;
310 struct clk
*sysclks
= pll
->sysclks
;
312 pll
->flags
= PLL_HAS_MUL
;
314 sysclks
[7].flags
|= FIXED_DIV_PLL
;
316 sysclks
[9].flags
|= FIXED_DIV_PLL
;
318 sysclks
[10].flags
|= FIXED_DIV_PLL
;
321 sysclks
[11].div
= PLLDIV11
;
323 sysclks
[12].flags
|= FIXED_DIV_PLL
;
326 sysclks
[13].div
= PLLDIV13
;
328 c6x_core_clk
.parent
= &sysclks
[7];
329 c6x_i2c_clk
.parent
= &sysclks
[10];
330 c6x_watchdog_clk
.parent
= &sysclks
[10];
331 c6x_mcbsp1_clk
.parent
= &sysclks
[10];
332 c6x_mcbsp2_clk
.parent
= &sysclks
[10];
334 c6x_clks_init(c6474_clks
);
336 #endif /* CONFIG_SOC_TMS320C6474 */
338 static struct of_device_id c6x_clkc_match
[] __initdata
= {
339 #ifdef CONFIG_SOC_TMS320C6455
340 { .compatible
= "ti,c6455-pll", .data
= c6455_setup_clocks
},
342 #ifdef CONFIG_SOC_TMS320C6457
343 { .compatible
= "ti,c6457-pll", .data
= c6457_setup_clocks
},
345 #ifdef CONFIG_SOC_TMS320C6472
346 { .compatible
= "ti,c6472-pll", .data
= c6472_setup_clocks
},
348 #ifdef CONFIG_SOC_TMS320C6474
349 { .compatible
= "ti,c6474-pll", .data
= c6474_setup_clocks
},
351 { .compatible
= "ti,c64x+pll" },
355 void __init
c64x_setup_clocks(void)
357 void (*__setup_clocks
)(struct device_node
*np
);
358 struct pll_data
*pll
= &c6x_soc_pll1
;
359 struct device_node
*node
;
360 const struct of_device_id
*id
;
364 node
= of_find_matching_node(NULL
, c6x_clkc_match
);
368 pll
->base
= of_iomap(node
, 0);
372 err
= of_property_read_u32(node
, "clock-frequency", &val
);
373 if (err
|| val
== 0) {
374 pr_err("%s: no clock-frequency found! Using %dMHz\n",
375 node
->full_name
, (int)val
/ 1000000);
380 err
= of_property_read_u32(node
, "ti,c64x+pll-bypass-delay", &val
);
383 pll
->bypass_delay
= val
;
385 err
= of_property_read_u32(node
, "ti,c64x+pll-reset-delay", &val
);
388 pll
->reset_delay
= val
;
390 err
= of_property_read_u32(node
, "ti,c64x+pll-lock-delay", &val
);
393 pll
->lock_delay
= val
;
395 /* id->data is a pointer to SoC-specific setup */
396 id
= of_match_node(c6x_clkc_match
, node
);
397 if (id
&& id
->data
) {
398 __setup_clocks
= id
->data
;
399 __setup_clocks(node
);