diff options
Diffstat (limited to 'arch/powerpc/platforms/512x')
-rw-r--r-- | arch/powerpc/platforms/512x/Kconfig | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/Makefile | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/clock.c | 729 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.c | 69 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.h | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 204 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_generic.c | 58 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc512x.h | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc512x_shared.c | 83 |
9 files changed, 1137 insertions, 60 deletions
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 4c0da0c079e..c62f893ede1 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig | |||
@@ -2,18 +2,29 @@ config PPC_MPC512x | |||
2 | bool | 2 | bool |
3 | select FSL_SOC | 3 | select FSL_SOC |
4 | select IPIC | 4 | select IPIC |
5 | default n | 5 | select PPC_CLOCK |
6 | 6 | ||
7 | config PPC_MPC5121 | 7 | config PPC_MPC5121 |
8 | bool | 8 | bool |
9 | select PPC_MPC512x | 9 | select PPC_MPC512x |
10 | default n | ||
11 | 10 | ||
12 | config MPC5121_ADS | 11 | config MPC5121_ADS |
13 | bool "Freescale MPC5121E ADS" | 12 | bool "Freescale MPC5121E ADS" |
14 | depends on PPC_MULTIPLATFORM && PPC32 | 13 | depends on PPC_MULTIPLATFORM && PPC32 |
15 | select DEFAULT_UIMAGE | 14 | select DEFAULT_UIMAGE |
16 | select PPC_MPC5121 | 15 | select PPC_MPC5121 |
16 | select MPC5121_ADS_CPLD | ||
17 | help | 17 | help |
18 | This option enables support for the MPC5121E ADS board. | 18 | This option enables support for the MPC5121E ADS board. |
19 | default n | 19 | |
20 | config MPC5121_GENERIC | ||
21 | bool "Generic support for simple MPC5121 based boards" | ||
22 | depends on PPC_MULTIPLATFORM && PPC32 | ||
23 | select DEFAULT_UIMAGE | ||
24 | select PPC_MPC5121 | ||
25 | help | ||
26 | This option enables support for simple MPC5121 based boards | ||
27 | which do not need custom platform specific setup. | ||
28 | |||
29 | Compatible boards include: Protonic LVT base boards (ZANMCU | ||
30 | and VICVT2). | ||
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 232c89f2039..90be2f5717e 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the Freescale PowerPC 512x linux kernel. | 2 | # Makefile for the Freescale PowerPC 512x linux kernel. |
3 | # | 3 | # |
4 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o | 4 | obj-y += clock.o mpc512x_shared.o |
5 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o | ||
6 | obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o | ||
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c new file mode 100644 index 00000000000..f416014ee72 --- /dev/null +++ b/arch/powerpc/platforms/512x/clock.c | |||
@@ -0,0 +1,729 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: John Rigby <jrigby@freescale.com> | ||
5 | * | ||
6 | * Implements the clk api defined in include/linux/clk.h | ||
7 | * | ||
8 | * Original based on linux/arch/arm/mach-integrator/clock.c | ||
9 | * | ||
10 | * Copyright (C) 2004 ARM Limited. | ||
11 | * Written by Deep Blue Solutions Limited. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <linux/of_platform.h> | ||
27 | #include <asm/mpc512x.h> | ||
28 | #include <asm/clk_interface.h> | ||
29 | |||
30 | #undef CLK_DEBUG | ||
31 | |||
32 | static int clocks_initialized; | ||
33 | |||
34 | #define CLK_HAS_RATE 0x1 /* has rate in MHz */ | ||
35 | #define CLK_HAS_CTRL 0x2 /* has control reg and bit */ | ||
36 | |||
37 | struct clk { | ||
38 | struct list_head node; | ||
39 | char name[32]; | ||
40 | int flags; | ||
41 | struct device *dev; | ||
42 | unsigned long rate; | ||
43 | struct module *owner; | ||
44 | void (*calc) (struct clk *); | ||
45 | struct clk *parent; | ||
46 | int reg, bit; /* CLK_HAS_CTRL */ | ||
47 | int div_shift; /* only used by generic_div_clk_calc */ | ||
48 | }; | ||
49 | |||
50 | static LIST_HEAD(clocks); | ||
51 | static DEFINE_MUTEX(clocks_mutex); | ||
52 | |||
53 | static struct clk *mpc5121_clk_get(struct device *dev, const char *id) | ||
54 | { | ||
55 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
56 | int dev_match = 0; | ||
57 | int id_match = 0; | ||
58 | |||
59 | if (dev == NULL && id == NULL) | ||
60 | return NULL; | ||
61 | |||
62 | mutex_lock(&clocks_mutex); | ||
63 | list_for_each_entry(p, &clocks, node) { | ||
64 | if (dev && dev == p->dev) | ||
65 | dev_match++; | ||
66 | if (strcmp(id, p->name) == 0) | ||
67 | id_match++; | ||
68 | if ((dev_match || id_match) && try_module_get(p->owner)) { | ||
69 | clk = p; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | mutex_unlock(&clocks_mutex); | ||
74 | |||
75 | return clk; | ||
76 | } | ||
77 | |||
78 | #ifdef CLK_DEBUG | ||
79 | static void dump_clocks(void) | ||
80 | { | ||
81 | struct clk *p; | ||
82 | |||
83 | mutex_lock(&clocks_mutex); | ||
84 | printk(KERN_INFO "CLOCKS:\n"); | ||
85 | list_for_each_entry(p, &clocks, node) { | ||
86 | printk(KERN_INFO " %s %ld", p->name, p->rate); | ||
87 | if (p->parent) | ||
88 | printk(KERN_INFO " %s %ld", p->parent->name, | ||
89 | p->parent->rate); | ||
90 | if (p->flags & CLK_HAS_CTRL) | ||
91 | printk(KERN_INFO " reg/bit %d/%d", p->reg, p->bit); | ||
92 | printk("\n"); | ||
93 | } | ||
94 | mutex_unlock(&clocks_mutex); | ||
95 | } | ||
96 | #define DEBUG_CLK_DUMP() dump_clocks() | ||
97 | #else | ||
98 | #define DEBUG_CLK_DUMP() | ||
99 | #endif | ||
100 | |||
101 | |||
102 | static void mpc5121_clk_put(struct clk *clk) | ||
103 | { | ||
104 | module_put(clk->owner); | ||
105 | } | ||
106 | |||
107 | #define NRPSC 12 | ||
108 | |||
109 | struct mpc512x_clockctl { | ||
110 | u32 spmr; /* System PLL Mode Reg */ | ||
111 | u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ | ||
112 | u32 scfr1; /* System Clk Freq Reg 1 */ | ||
113 | u32 scfr2; /* System Clk Freq Reg 2 */ | ||
114 | u32 reserved; | ||
115 | u32 bcr; /* Bread Crumb Reg */ | ||
116 | u32 pccr[NRPSC]; /* PSC Clk Ctrl Reg 0-11 */ | ||
117 | u32 spccr; /* SPDIF Clk Ctrl Reg */ | ||
118 | u32 cccr; /* CFM Clk Ctrl Reg */ | ||
119 | u32 dccr; /* DIU Clk Cnfg Reg */ | ||
120 | }; | ||
121 | |||
122 | struct mpc512x_clockctl __iomem *clockctl; | ||
123 | |||
124 | static int mpc5121_clk_enable(struct clk *clk) | ||
125 | { | ||
126 | unsigned int mask; | ||
127 | |||
128 | if (clk->flags & CLK_HAS_CTRL) { | ||
129 | mask = in_be32(&clockctl->sccr[clk->reg]); | ||
130 | mask |= 1 << clk->bit; | ||
131 | out_be32(&clockctl->sccr[clk->reg], mask); | ||
132 | } | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void mpc5121_clk_disable(struct clk *clk) | ||
137 | { | ||
138 | unsigned int mask; | ||
139 | |||
140 | if (clk->flags & CLK_HAS_CTRL) { | ||
141 | mask = in_be32(&clockctl->sccr[clk->reg]); | ||
142 | mask &= ~(1 << clk->bit); | ||
143 | out_be32(&clockctl->sccr[clk->reg], mask); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static unsigned long mpc5121_clk_get_rate(struct clk *clk) | ||
148 | { | ||
149 | if (clk->flags & CLK_HAS_RATE) | ||
150 | return clk->rate; | ||
151 | else | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate) | ||
156 | { | ||
157 | return rate; | ||
158 | } | ||
159 | |||
160 | static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate) | ||
161 | { | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int clk_register(struct clk *clk) | ||
166 | { | ||
167 | mutex_lock(&clocks_mutex); | ||
168 | list_add(&clk->node, &clocks); | ||
169 | mutex_unlock(&clocks_mutex); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static unsigned long spmf_mult(void) | ||
174 | { | ||
175 | /* | ||
176 | * Convert spmf to multiplier | ||
177 | */ | ||
178 | static int spmf_to_mult[] = { | ||
179 | 68, 1, 12, 16, | ||
180 | 20, 24, 28, 32, | ||
181 | 36, 40, 44, 48, | ||
182 | 52, 56, 60, 64 | ||
183 | }; | ||
184 | int spmf = (clockctl->spmr >> 24) & 0xf; | ||
185 | return spmf_to_mult[spmf]; | ||
186 | } | ||
187 | |||
188 | static unsigned long sysdiv_div_x_2(void) | ||
189 | { | ||
190 | /* | ||
191 | * Convert sysdiv to divisor x 2 | ||
192 | * Some divisors have fractional parts so | ||
193 | * multiply by 2 then divide by this value | ||
194 | */ | ||
195 | static int sysdiv_to_div_x_2[] = { | ||
196 | 4, 5, 6, 7, | ||
197 | 8, 9, 10, 14, | ||
198 | 12, 16, 18, 22, | ||
199 | 20, 24, 26, 30, | ||
200 | 28, 32, 34, 38, | ||
201 | 36, 40, 42, 46, | ||
202 | 44, 48, 50, 54, | ||
203 | 52, 56, 58, 62, | ||
204 | 60, 64, 66, | ||
205 | }; | ||
206 | int sysdiv = (clockctl->scfr2 >> 26) & 0x3f; | ||
207 | return sysdiv_to_div_x_2[sysdiv]; | ||
208 | } | ||
209 | |||
210 | static unsigned long ref_to_sys(unsigned long rate) | ||
211 | { | ||
212 | rate *= spmf_mult(); | ||
213 | rate *= 2; | ||
214 | rate /= sysdiv_div_x_2(); | ||
215 | |||
216 | return rate; | ||
217 | } | ||
218 | |||
219 | static unsigned long sys_to_ref(unsigned long rate) | ||
220 | { | ||
221 | rate *= sysdiv_div_x_2(); | ||
222 | rate /= 2; | ||
223 | rate /= spmf_mult(); | ||
224 | |||
225 | return rate; | ||
226 | } | ||
227 | |||
228 | static long ips_to_ref(unsigned long rate) | ||
229 | { | ||
230 | int ips_div = (clockctl->scfr1 >> 23) & 0x7; | ||
231 | |||
232 | rate *= ips_div; /* csb_clk = ips_clk * ips_div */ | ||
233 | rate *= 2; /* sys_clk = csb_clk * 2 */ | ||
234 | return sys_to_ref(rate); | ||
235 | } | ||
236 | |||
237 | static unsigned long devtree_getfreq(char *clockname) | ||
238 | { | ||
239 | struct device_node *np; | ||
240 | const unsigned int *prop; | ||
241 | unsigned int val = 0; | ||
242 | |||
243 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr"); | ||
244 | if (np) { | ||
245 | prop = of_get_property(np, clockname, NULL); | ||
246 | if (prop) | ||
247 | val = *prop; | ||
248 | of_node_put(np); | ||
249 | } | ||
250 | return val; | ||
251 | } | ||
252 | |||
253 | static void ref_clk_calc(struct clk *clk) | ||
254 | { | ||
255 | unsigned long rate; | ||
256 | |||
257 | rate = devtree_getfreq("bus-frequency"); | ||
258 | if (rate == 0) { | ||
259 | printk(KERN_ERR "No bus-frequency in dev tree\n"); | ||
260 | clk->rate = 0; | ||
261 | return; | ||
262 | } | ||
263 | clk->rate = ips_to_ref(rate); | ||
264 | } | ||
265 | |||
266 | static struct clk ref_clk = { | ||
267 | .name = "ref_clk", | ||
268 | .calc = ref_clk_calc, | ||
269 | }; | ||
270 | |||
271 | |||
272 | static void sys_clk_calc(struct clk *clk) | ||
273 | { | ||
274 | clk->rate = ref_to_sys(ref_clk.rate); | ||
275 | } | ||
276 | |||
277 | static struct clk sys_clk = { | ||
278 | .name = "sys_clk", | ||
279 | .calc = sys_clk_calc, | ||
280 | }; | ||
281 | |||
282 | static void diu_clk_calc(struct clk *clk) | ||
283 | { | ||
284 | int diudiv_x_2 = clockctl->scfr1 & 0xff; | ||
285 | unsigned long rate; | ||
286 | |||
287 | rate = sys_clk.rate; | ||
288 | |||
289 | rate *= 2; | ||
290 | rate /= diudiv_x_2; | ||
291 | |||
292 | clk->rate = rate; | ||
293 | } | ||
294 | |||
295 | static void half_clk_calc(struct clk *clk) | ||
296 | { | ||
297 | clk->rate = clk->parent->rate / 2; | ||
298 | } | ||
299 | |||
300 | static void generic_div_clk_calc(struct clk *clk) | ||
301 | { | ||
302 | int div = (clockctl->scfr1 >> clk->div_shift) & 0x7; | ||
303 | |||
304 | clk->rate = clk->parent->rate / div; | ||
305 | } | ||
306 | |||
307 | static void unity_clk_calc(struct clk *clk) | ||
308 | { | ||
309 | clk->rate = clk->parent->rate; | ||
310 | } | ||
311 | |||
312 | static struct clk csb_clk = { | ||
313 | .name = "csb_clk", | ||
314 | .calc = half_clk_calc, | ||
315 | .parent = &sys_clk, | ||
316 | }; | ||
317 | |||
318 | static void e300_clk_calc(struct clk *clk) | ||
319 | { | ||
320 | int spmf = (clockctl->spmr >> 16) & 0xf; | ||
321 | int ratex2 = clk->parent->rate * spmf; | ||
322 | |||
323 | clk->rate = ratex2 / 2; | ||
324 | } | ||
325 | |||
326 | static struct clk e300_clk = { | ||
327 | .name = "e300_clk", | ||
328 | .calc = e300_clk_calc, | ||
329 | .parent = &csb_clk, | ||
330 | }; | ||
331 | |||
332 | static struct clk ips_clk = { | ||
333 | .name = "ips_clk", | ||
334 | .calc = generic_div_clk_calc, | ||
335 | .parent = &csb_clk, | ||
336 | .div_shift = 23, | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * Clocks controlled by SCCR1 (.reg = 0) | ||
341 | */ | ||
342 | static struct clk lpc_clk = { | ||
343 | .name = "lpc_clk", | ||
344 | .flags = CLK_HAS_CTRL, | ||
345 | .reg = 0, | ||
346 | .bit = 30, | ||
347 | .calc = generic_div_clk_calc, | ||
348 | .parent = &ips_clk, | ||
349 | .div_shift = 11, | ||
350 | }; | ||
351 | |||
352 | static struct clk nfc_clk = { | ||
353 | .name = "nfc_clk", | ||
354 | .flags = CLK_HAS_CTRL, | ||
355 | .reg = 0, | ||
356 | .bit = 29, | ||
357 | .calc = generic_div_clk_calc, | ||
358 | .parent = &ips_clk, | ||
359 | .div_shift = 8, | ||
360 | }; | ||
361 | |||
362 | static struct clk pata_clk = { | ||
363 | .name = "pata_clk", | ||
364 | .flags = CLK_HAS_CTRL, | ||
365 | .reg = 0, | ||
366 | .bit = 28, | ||
367 | .calc = unity_clk_calc, | ||
368 | .parent = &ips_clk, | ||
369 | }; | ||
370 | |||
371 | /* | ||
372 | * PSC clocks (bits 27 - 16) | ||
373 | * are setup elsewhere | ||
374 | */ | ||
375 | |||
376 | static struct clk sata_clk = { | ||
377 | .name = "sata_clk", | ||
378 | .flags = CLK_HAS_CTRL, | ||
379 | .reg = 0, | ||
380 | .bit = 14, | ||
381 | .calc = unity_clk_calc, | ||
382 | .parent = &ips_clk, | ||
383 | }; | ||
384 | |||
385 | static struct clk fec_clk = { | ||
386 | .name = "fec_clk", | ||
387 | .flags = CLK_HAS_CTRL, | ||
388 | .reg = 0, | ||
389 | .bit = 13, | ||
390 | .calc = unity_clk_calc, | ||
391 | .parent = &ips_clk, | ||
392 | }; | ||
393 | |||
394 | static struct clk pci_clk = { | ||
395 | .name = "pci_clk", | ||
396 | .flags = CLK_HAS_CTRL, | ||
397 | .reg = 0, | ||
398 | .bit = 11, | ||
399 | .calc = generic_div_clk_calc, | ||
400 | .parent = &csb_clk, | ||
401 | .div_shift = 20, | ||
402 | }; | ||
403 | |||
404 | /* | ||
405 | * Clocks controlled by SCCR2 (.reg = 1) | ||
406 | */ | ||
407 | static struct clk diu_clk = { | ||
408 | .name = "diu_clk", | ||
409 | .flags = CLK_HAS_CTRL, | ||
410 | .reg = 1, | ||
411 | .bit = 31, | ||
412 | .calc = diu_clk_calc, | ||
413 | }; | ||
414 | |||
415 | static struct clk axe_clk = { | ||
416 | .name = "axe_clk", | ||
417 | .flags = CLK_HAS_CTRL, | ||
418 | .reg = 1, | ||
419 | .bit = 30, | ||
420 | .calc = unity_clk_calc, | ||
421 | .parent = &csb_clk, | ||
422 | }; | ||
423 | |||
424 | static struct clk usb1_clk = { | ||
425 | .name = "usb1_clk", | ||
426 | .flags = CLK_HAS_CTRL, | ||
427 | .reg = 1, | ||
428 | .bit = 28, | ||
429 | .calc = unity_clk_calc, | ||
430 | .parent = &csb_clk, | ||
431 | }; | ||
432 | |||
433 | static struct clk usb2_clk = { | ||
434 | .name = "usb2_clk", | ||
435 | .flags = CLK_HAS_CTRL, | ||
436 | .reg = 1, | ||
437 | .bit = 27, | ||
438 | .calc = unity_clk_calc, | ||
439 | .parent = &csb_clk, | ||
440 | }; | ||
441 | |||
442 | static struct clk i2c_clk = { | ||
443 | .name = "i2c_clk", | ||
444 | .flags = CLK_HAS_CTRL, | ||
445 | .reg = 1, | ||
446 | .bit = 26, | ||
447 | .calc = unity_clk_calc, | ||
448 | .parent = &ips_clk, | ||
449 | }; | ||
450 | |||
451 | static struct clk mscan_clk = { | ||
452 | .name = "mscan_clk", | ||
453 | .flags = CLK_HAS_CTRL, | ||
454 | .reg = 1, | ||
455 | .bit = 25, | ||
456 | .calc = unity_clk_calc, | ||
457 | .parent = &ips_clk, | ||
458 | }; | ||
459 | |||
460 | static struct clk sdhc_clk = { | ||
461 | .name = "sdhc_clk", | ||
462 | .flags = CLK_HAS_CTRL, | ||
463 | .reg = 1, | ||
464 | .bit = 24, | ||
465 | .calc = unity_clk_calc, | ||
466 | .parent = &ips_clk, | ||
467 | }; | ||
468 | |||
469 | static struct clk mbx_bus_clk = { | ||
470 | .name = "mbx_bus_clk", | ||
471 | .flags = CLK_HAS_CTRL, | ||
472 | .reg = 1, | ||
473 | .bit = 22, | ||
474 | .calc = half_clk_calc, | ||
475 | .parent = &csb_clk, | ||
476 | }; | ||
477 | |||
478 | static struct clk mbx_clk = { | ||
479 | .name = "mbx_clk", | ||
480 | .flags = CLK_HAS_CTRL, | ||
481 | .reg = 1, | ||
482 | .bit = 21, | ||
483 | .calc = unity_clk_calc, | ||
484 | .parent = &csb_clk, | ||
485 | }; | ||
486 | |||
487 | static struct clk mbx_3d_clk = { | ||
488 | .name = "mbx_3d_clk", | ||
489 | .flags = CLK_HAS_CTRL, | ||
490 | .reg = 1, | ||
491 | .bit = 20, | ||
492 | .calc = generic_div_clk_calc, | ||
493 | .parent = &mbx_bus_clk, | ||
494 | .div_shift = 14, | ||
495 | }; | ||
496 | |||
497 | static void psc_mclk_in_calc(struct clk *clk) | ||
498 | { | ||
499 | clk->rate = devtree_getfreq("psc_mclk_in"); | ||
500 | if (!clk->rate) | ||
501 | clk->rate = 25000000; | ||
502 | } | ||
503 | |||
504 | static struct clk psc_mclk_in = { | ||
505 | .name = "psc_mclk_in", | ||
506 | .calc = psc_mclk_in_calc, | ||
507 | }; | ||
508 | |||
509 | static struct clk spdif_txclk = { | ||
510 | .name = "spdif_txclk", | ||
511 | .flags = CLK_HAS_CTRL, | ||
512 | .reg = 1, | ||
513 | .bit = 23, | ||
514 | }; | ||
515 | |||
516 | static struct clk spdif_rxclk = { | ||
517 | .name = "spdif_rxclk", | ||
518 | .flags = CLK_HAS_CTRL, | ||
519 | .reg = 1, | ||
520 | .bit = 23, | ||
521 | }; | ||
522 | |||
523 | static void ac97_clk_calc(struct clk *clk) | ||
524 | { | ||
525 | /* ac97 bit clock is always 24.567 MHz */ | ||
526 | clk->rate = 24567000; | ||
527 | } | ||
528 | |||
529 | static struct clk ac97_clk = { | ||
530 | .name = "ac97_clk_in", | ||
531 | .calc = ac97_clk_calc, | ||
532 | }; | ||
533 | |||
534 | struct clk *rate_clks[] = { | ||
535 | &ref_clk, | ||
536 | &sys_clk, | ||
537 | &diu_clk, | ||
538 | &csb_clk, | ||
539 | &e300_clk, | ||
540 | &ips_clk, | ||
541 | &fec_clk, | ||
542 | &sata_clk, | ||
543 | &pata_clk, | ||
544 | &nfc_clk, | ||
545 | &lpc_clk, | ||
546 | &mbx_bus_clk, | ||
547 | &mbx_clk, | ||
548 | &mbx_3d_clk, | ||
549 | &axe_clk, | ||
550 | &usb1_clk, | ||
551 | &usb2_clk, | ||
552 | &i2c_clk, | ||
553 | &mscan_clk, | ||
554 | &sdhc_clk, | ||
555 | &pci_clk, | ||
556 | &psc_mclk_in, | ||
557 | &spdif_txclk, | ||
558 | &spdif_rxclk, | ||
559 | &ac97_clk, | ||
560 | NULL | ||
561 | }; | ||
562 | |||
563 | static void rate_clk_init(struct clk *clk) | ||
564 | { | ||
565 | if (clk->calc) { | ||
566 | clk->calc(clk); | ||
567 | clk->flags |= CLK_HAS_RATE; | ||
568 | clk_register(clk); | ||
569 | } else { | ||
570 | printk(KERN_WARNING | ||
571 | "Could not initialize clk %s without a calc routine\n", | ||
572 | clk->name); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | static void rate_clks_init(void) | ||
577 | { | ||
578 | struct clk **cpp, *clk; | ||
579 | |||
580 | cpp = rate_clks; | ||
581 | while ((clk = *cpp++)) | ||
582 | rate_clk_init(clk); | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * There are two clk enable registers with 32 enable bits each | ||
587 | * psc clocks and device clocks are all stored in dev_clks | ||
588 | */ | ||
589 | struct clk dev_clks[2][32]; | ||
590 | |||
591 | /* | ||
592 | * Given a psc number return the dev_clk | ||
593 | * associated with it | ||
594 | */ | ||
595 | static struct clk *psc_dev_clk(int pscnum) | ||
596 | { | ||
597 | int reg, bit; | ||
598 | struct clk *clk; | ||
599 | |||
600 | reg = 0; | ||
601 | bit = 27 - pscnum; | ||
602 | |||
603 | clk = &dev_clks[reg][bit]; | ||
604 | clk->reg = 0; | ||
605 | clk->bit = bit; | ||
606 | return clk; | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * PSC clock rate calculation | ||
611 | */ | ||
612 | static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np) | ||
613 | { | ||
614 | unsigned long mclk_src = sys_clk.rate; | ||
615 | unsigned long mclk_div; | ||
616 | |||
617 | /* | ||
618 | * Can only change value of mclk divider | ||
619 | * when the divider is disabled. | ||
620 | * | ||
621 | * Zero is not a valid divider so minimum | ||
622 | * divider is 1 | ||
623 | * | ||
624 | * disable/set divider/enable | ||
625 | */ | ||
626 | out_be32(&clockctl->pccr[pscnum], 0); | ||
627 | out_be32(&clockctl->pccr[pscnum], 0x00020000); | ||
628 | out_be32(&clockctl->pccr[pscnum], 0x00030000); | ||
629 | |||
630 | if (clockctl->pccr[pscnum] & 0x80) { | ||
631 | clk->rate = spdif_rxclk.rate; | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | switch ((clockctl->pccr[pscnum] >> 14) & 0x3) { | ||
636 | case 0: | ||
637 | mclk_src = sys_clk.rate; | ||
638 | break; | ||
639 | case 1: | ||
640 | mclk_src = ref_clk.rate; | ||
641 | break; | ||
642 | case 2: | ||
643 | mclk_src = psc_mclk_in.rate; | ||
644 | break; | ||
645 | case 3: | ||
646 | mclk_src = spdif_txclk.rate; | ||
647 | break; | ||
648 | } | ||
649 | |||
650 | mclk_div = ((clockctl->pccr[pscnum] >> 17) & 0x7fff) + 1; | ||
651 | clk->rate = mclk_src / mclk_div; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * Find all psc nodes in device tree and assign a clock | ||
656 | * with name "psc%d_mclk" and dev pointing at the device | ||
657 | * returned from of_find_device_by_node | ||
658 | */ | ||
659 | static void psc_clks_init(void) | ||
660 | { | ||
661 | struct device_node *np; | ||
662 | const u32 *cell_index; | ||
663 | struct of_device *ofdev; | ||
664 | |||
665 | for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") { | ||
666 | cell_index = of_get_property(np, "cell-index", NULL); | ||
667 | if (cell_index) { | ||
668 | int pscnum = *cell_index; | ||
669 | struct clk *clk = psc_dev_clk(pscnum); | ||
670 | |||
671 | clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL; | ||
672 | ofdev = of_find_device_by_node(np); | ||
673 | clk->dev = &ofdev->dev; | ||
674 | /* | ||
675 | * AC97 is special rate clock does | ||
676 | * not go through normal path | ||
677 | */ | ||
678 | if (strcmp("ac97", np->name) == 0) | ||
679 | clk->rate = ac97_clk.rate; | ||
680 | else | ||
681 | psc_calc_rate(clk, pscnum, np); | ||
682 | sprintf(clk->name, "psc%d_mclk", pscnum); | ||
683 | clk_register(clk); | ||
684 | clk_enable(clk); | ||
685 | } | ||
686 | } | ||
687 | } | ||
688 | |||
689 | static struct clk_interface mpc5121_clk_functions = { | ||
690 | .clk_get = mpc5121_clk_get, | ||
691 | .clk_enable = mpc5121_clk_enable, | ||
692 | .clk_disable = mpc5121_clk_disable, | ||
693 | .clk_get_rate = mpc5121_clk_get_rate, | ||
694 | .clk_put = mpc5121_clk_put, | ||
695 | .clk_round_rate = mpc5121_clk_round_rate, | ||
696 | .clk_set_rate = mpc5121_clk_set_rate, | ||
697 | .clk_set_parent = NULL, | ||
698 | .clk_get_parent = NULL, | ||
699 | }; | ||
700 | |||
701 | static int | ||
702 | mpc5121_clk_init(void) | ||
703 | { | ||
704 | struct device_node *np; | ||
705 | |||
706 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); | ||
707 | if (np) { | ||
708 | clockctl = of_iomap(np, 0); | ||
709 | of_node_put(np); | ||
710 | } | ||
711 | |||
712 | if (!clockctl) { | ||
713 | printk(KERN_ERR "Could not map clock control registers\n"); | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | rate_clks_init(); | ||
718 | psc_clks_init(); | ||
719 | |||
720 | /* leave clockctl mapped forever */ | ||
721 | /*iounmap(clockctl); */ | ||
722 | DEBUG_CLK_DUMP(); | ||
723 | clocks_initialized++; | ||
724 | clk_functions = mpc5121_clk_functions; | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | |||
729 | arch_initcall(mpc5121_clk_init); | ||
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index 50bd3a31902..5ebf6939a69 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. | 2 | * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007 | 4 | * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007 |
5 | * | 5 | * |
@@ -15,7 +15,6 @@ | |||
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/irq.h> | ||
19 | #include <linux/of_platform.h> | 18 | #include <linux/of_platform.h> |
20 | 19 | ||
21 | #include <asm/machdep.h> | 20 | #include <asm/machdep.h> |
@@ -23,65 +22,22 @@ | |||
23 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
24 | #include <asm/time.h> | 23 | #include <asm/time.h> |
25 | 24 | ||
26 | /** | 25 | #include "mpc512x.h" |
27 | * mpc512x_find_ips_freq - Find the IPS bus frequency for a device | 26 | #include "mpc5121_ads.h" |
28 | * @node: device node | ||
29 | * | ||
30 | * Returns IPS bus frequency, or 0 if the bus frequency cannot be found. | ||
31 | */ | ||
32 | unsigned long | ||
33 | mpc512x_find_ips_freq(struct device_node *node) | ||
34 | { | ||
35 | struct device_node *np; | ||
36 | const unsigned int *p_ips_freq = NULL; | ||
37 | |||
38 | of_node_get(node); | ||
39 | while (node) { | ||
40 | p_ips_freq = of_get_property(node, "bus-frequency", NULL); | ||
41 | if (p_ips_freq) | ||
42 | break; | ||
43 | |||
44 | np = of_get_parent(node); | ||
45 | of_node_put(node); | ||
46 | node = np; | ||
47 | } | ||
48 | if (node) | ||
49 | of_node_put(node); | ||
50 | |||
51 | return p_ips_freq ? *p_ips_freq : 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL(mpc512x_find_ips_freq); | ||
54 | |||
55 | static struct of_device_id __initdata of_bus_ids[] = { | ||
56 | { .name = "soc", }, | ||
57 | { .name = "localbus", }, | ||
58 | {}, | ||
59 | }; | ||
60 | 27 | ||
61 | static void __init mpc5121_ads_declare_of_platform_devices(void) | 28 | static void __init mpc5121_ads_setup_arch(void) |
62 | { | 29 | { |
63 | /* Find every child of the SOC node and add it to of_platform */ | 30 | printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n"); |
64 | if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) | 31 | /* |
65 | printk(KERN_ERR __FILE__ ": " | 32 | * cpld regs are needed early |
66 | "Error while probing of_platform bus\n"); | 33 | */ |
34 | mpc5121_ads_cpld_map(); | ||
67 | } | 35 | } |
68 | 36 | ||
69 | static void __init mpc5121_ads_init_IRQ(void) | 37 | static void __init mpc5121_ads_init_IRQ(void) |
70 | { | 38 | { |
71 | struct device_node *np; | 39 | mpc512x_init_IRQ(); |
72 | 40 | mpc5121_ads_cpld_pic_init(); | |
73 | np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); | ||
74 | if (!np) | ||
75 | return; | ||
76 | |||
77 | ipic_init(np, 0); | ||
78 | of_node_put(np); | ||
79 | |||
80 | /* | ||
81 | * Initialize the default interrupt mapping priorities, | ||
82 | * in case the boot rom changed something on us. | ||
83 | */ | ||
84 | ipic_set_default_priority(); | ||
85 | } | 41 | } |
86 | 42 | ||
87 | /* | 43 | /* |
@@ -97,7 +53,8 @@ static int __init mpc5121_ads_probe(void) | |||
97 | define_machine(mpc5121_ads) { | 53 | define_machine(mpc5121_ads) { |
98 | .name = "MPC5121 ADS", | 54 | .name = "MPC5121 ADS", |
99 | .probe = mpc5121_ads_probe, | 55 | .probe = mpc5121_ads_probe, |
100 | .init = mpc5121_ads_declare_of_platform_devices, | 56 | .setup_arch = mpc5121_ads_setup_arch, |
57 | .init = mpc512x_declare_of_platform_devices, | ||
101 | .init_IRQ = mpc5121_ads_init_IRQ, | 58 | .init_IRQ = mpc5121_ads_init_IRQ, |
102 | .get_irq = ipic_get_irq, | 59 | .get_irq = ipic_get_irq, |
103 | .calibrate_decr = generic_calibrate_decr, | 60 | .calibrate_decr = generic_calibrate_decr, |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.h b/arch/powerpc/platforms/512x/mpc5121_ads.h new file mode 100644 index 00000000000..662076cfee2 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * Prototypes for ADS5121 specific code | ||
10 | */ | ||
11 | |||
12 | #ifndef __MPC512ADS_H__ | ||
13 | #define __MPC512ADS_H__ | ||
14 | extern void __init mpc5121_ads_cpld_map(void); | ||
15 | extern void __init mpc5121_ads_cpld_pic_init(void); | ||
16 | #endif /* __MPC512ADS_H__ */ | ||
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c new file mode 100644 index 00000000000..a6ce8056662 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: John Rigby, <jrigby@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * MPC5121ADS CPLD irq handling | ||
8 | * | ||
9 | * This is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <asm/prom.h> | ||
22 | |||
23 | static struct device_node *cpld_pic_node; | ||
24 | static struct irq_host *cpld_pic_host; | ||
25 | |||
26 | /* | ||
27 | * Bits to ignore in the misc_status register | ||
28 | * 0x10 touch screen pendown is hard routed to irq1 | ||
29 | * 0x02 pci status is read from pci status register | ||
30 | */ | ||
31 | #define MISC_IGNORE 0x12 | ||
32 | |||
33 | /* | ||
34 | * Nothing to ignore in pci status register | ||
35 | */ | ||
36 | #define PCI_IGNORE 0x00 | ||
37 | |||
38 | struct cpld_pic { | ||
39 | u8 pci_mask; | ||
40 | u8 pci_status; | ||
41 | u8 route; | ||
42 | u8 misc_mask; | ||
43 | u8 misc_status; | ||
44 | u8 misc_control; | ||
45 | }; | ||
46 | |||
47 | static struct cpld_pic __iomem *cpld_regs; | ||
48 | |||
49 | static void __iomem * | ||
50 | irq_to_pic_mask(unsigned int irq) | ||
51 | { | ||
52 | return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask; | ||
53 | } | ||
54 | |||
55 | static unsigned int | ||
56 | irq_to_pic_bit(unsigned int irq) | ||
57 | { | ||
58 | return 1 << (irq & 0x7); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | cpld_mask_irq(unsigned int irq) | ||
63 | { | ||
64 | unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; | ||
65 | void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); | ||
66 | |||
67 | out_8(pic_mask, | ||
68 | in_8(pic_mask) | irq_to_pic_bit(cpld_irq)); | ||
69 | } | ||
70 | |||
71 | static void | ||
72 | cpld_unmask_irq(unsigned int irq) | ||
73 | { | ||
74 | unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; | ||
75 | void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); | ||
76 | |||
77 | out_8(pic_mask, | ||
78 | in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq)); | ||
79 | } | ||
80 | |||
81 | static struct irq_chip cpld_pic = { | ||
82 | .typename = " CPLD PIC ", | ||
83 | .mask = cpld_mask_irq, | ||
84 | .ack = cpld_mask_irq, | ||
85 | .unmask = cpld_unmask_irq, | ||
86 | }; | ||
87 | |||
88 | static int | ||
89 | cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, | ||
90 | u8 __iomem *maskp) | ||
91 | { | ||
92 | int cpld_irq; | ||
93 | u8 status = in_8(statusp); | ||
94 | u8 mask = in_8(maskp); | ||
95 | |||
96 | /* ignore don't cares and masked irqs */ | ||
97 | status |= (ignore | mask); | ||
98 | |||
99 | if (status == 0xff) | ||
100 | return NO_IRQ_IGNORE; | ||
101 | |||
102 | cpld_irq = ffz(status) + offset; | ||
103 | |||
104 | return irq_linear_revmap(cpld_pic_host, cpld_irq); | ||
105 | } | ||
106 | |||
107 | static void | ||
108 | cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) | ||
109 | { | ||
110 | irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, | ||
111 | &cpld_regs->pci_mask); | ||
112 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | ||
113 | generic_handle_irq(irq); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, | ||
118 | &cpld_regs->misc_mask); | ||
119 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | ||
120 | generic_handle_irq(irq); | ||
121 | return; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static int | ||
126 | cpld_pic_host_match(struct irq_host *h, struct device_node *node) | ||
127 | { | ||
128 | return cpld_pic_node == node; | ||
129 | } | ||
130 | |||
131 | static int | ||
132 | cpld_pic_host_map(struct irq_host *h, unsigned int virq, | ||
133 | irq_hw_number_t hw) | ||
134 | { | ||
135 | get_irq_desc(virq)->status |= IRQ_LEVEL; | ||
136 | set_irq_chip_and_handler(virq, &cpld_pic, handle_level_irq); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static struct | ||
141 | irq_host_ops cpld_pic_host_ops = { | ||
142 | .match = cpld_pic_host_match, | ||
143 | .map = cpld_pic_host_map, | ||
144 | }; | ||
145 | |||
146 | void __init | ||
147 | mpc5121_ads_cpld_map(void) | ||
148 | { | ||
149 | struct device_node *np = NULL; | ||
150 | |||
151 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); | ||
152 | if (!np) { | ||
153 | printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | cpld_regs = of_iomap(np, 0); | ||
158 | of_node_put(np); | ||
159 | } | ||
160 | |||
161 | void __init | ||
162 | mpc5121_ads_cpld_pic_init(void) | ||
163 | { | ||
164 | unsigned int cascade_irq; | ||
165 | struct device_node *np = NULL; | ||
166 | |||
167 | pr_debug("cpld_ic_init\n"); | ||
168 | |||
169 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); | ||
170 | if (!np) { | ||
171 | printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | if (!cpld_regs) | ||
176 | goto end; | ||
177 | |||
178 | cascade_irq = irq_of_parse_and_map(np, 0); | ||
179 | if (cascade_irq == NO_IRQ) | ||
180 | goto end; | ||
181 | |||
182 | /* | ||
183 | * statically route touch screen pendown through 1 | ||
184 | * and ignore it here | ||
185 | * route all others through our cascade irq | ||
186 | */ | ||
187 | out_8(&cpld_regs->route, 0xfd); | ||
188 | out_8(&cpld_regs->pci_mask, 0xff); | ||
189 | /* unmask pci ints in misc mask */ | ||
190 | out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE)); | ||
191 | |||
192 | cpld_pic_node = of_node_get(np); | ||
193 | |||
194 | cpld_pic_host = | ||
195 | irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); | ||
196 | if (!cpld_pic_host) { | ||
197 | printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n"); | ||
198 | goto end; | ||
199 | } | ||
200 | |||
201 | set_irq_chained_handler(cascade_irq, cpld_pic_cascade); | ||
202 | end: | ||
203 | of_node_put(np); | ||
204 | } | ||
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c new file mode 100644 index 00000000000..2479de9e2d1 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: John Rigby, <jrigby@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * MPC5121 SoC setup | ||
8 | * | ||
9 | * This is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | |||
19 | #include <asm/machdep.h> | ||
20 | #include <asm/ipic.h> | ||
21 | #include <asm/prom.h> | ||
22 | #include <asm/time.h> | ||
23 | |||
24 | #include "mpc512x.h" | ||
25 | |||
26 | /* | ||
27 | * list of supported boards | ||
28 | */ | ||
29 | static char *board[] __initdata = { | ||
30 | "prt,prtlvt", | ||
31 | NULL | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * Called very early, MMU is off, device-tree isn't unflattened | ||
36 | */ | ||
37 | static int __init mpc5121_generic_probe(void) | ||
38 | { | ||
39 | unsigned long node = of_get_flat_dt_root(); | ||
40 | int i = 0; | ||
41 | |||
42 | while (board[i]) { | ||
43 | if (of_flat_dt_is_compatible(node, board[i])) | ||
44 | break; | ||
45 | i++; | ||
46 | } | ||
47 | |||
48 | return board[i] != NULL; | ||
49 | } | ||
50 | |||
51 | define_machine(mpc5121_generic) { | ||
52 | .name = "MPC5121 generic", | ||
53 | .probe = mpc5121_generic_probe, | ||
54 | .init = mpc512x_declare_of_platform_devices, | ||
55 | .init_IRQ = mpc512x_init_IRQ, | ||
56 | .get_irq = ipic_get_irq, | ||
57 | .calibrate_decr = generic_calibrate_decr, | ||
58 | }; | ||
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h new file mode 100644 index 00000000000..9c03693cb00 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc512x.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * Prototypes for MPC512x shared code | ||
10 | */ | ||
11 | |||
12 | #ifndef __MPC512X_H__ | ||
13 | #define __MPC512X_H__ | ||
14 | extern unsigned long mpc512x_find_ips_freq(struct device_node *node); | ||
15 | extern void __init mpc512x_init_IRQ(void); | ||
16 | void __init mpc512x_declare_of_platform_devices(void); | ||
17 | #endif /* __MPC512X_H__ */ | ||
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c new file mode 100644 index 00000000000..d8cd579f319 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: John Rigby <jrigby@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * MPC512x Shared code | ||
8 | * | ||
9 | * This is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | |||
20 | #include <asm/machdep.h> | ||
21 | #include <asm/ipic.h> | ||
22 | #include <asm/prom.h> | ||
23 | #include <asm/time.h> | ||
24 | |||
25 | #include "mpc512x.h" | ||
26 | |||
27 | unsigned long | ||
28 | mpc512x_find_ips_freq(struct device_node *node) | ||
29 | { | ||
30 | struct device_node *np; | ||
31 | const unsigned int *p_ips_freq = NULL; | ||
32 | |||
33 | of_node_get(node); | ||
34 | while (node) { | ||
35 | p_ips_freq = of_get_property(node, "bus-frequency", NULL); | ||
36 | if (p_ips_freq) | ||
37 | break; | ||
38 | |||
39 | np = of_get_parent(node); | ||
40 | of_node_put(node); | ||
41 | node = np; | ||
42 | } | ||
43 | if (node) | ||
44 | of_node_put(node); | ||
45 | |||
46 | return p_ips_freq ? *p_ips_freq : 0; | ||
47 | } | ||
48 | EXPORT_SYMBOL(mpc512x_find_ips_freq); | ||
49 | |||
50 | void __init mpc512x_init_IRQ(void) | ||
51 | { | ||
52 | struct device_node *np; | ||
53 | |||
54 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ipic"); | ||
55 | if (!np) | ||
56 | return; | ||
57 | |||
58 | ipic_init(np, 0); | ||
59 | of_node_put(np); | ||
60 | |||
61 | /* | ||
62 | * Initialize the default interrupt mapping priorities, | ||
63 | * in case the boot rom changed something on us. | ||
64 | */ | ||
65 | ipic_set_default_priority(); | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Nodes to do bus probe on, soc and localbus | ||
70 | */ | ||
71 | static struct of_device_id __initdata of_bus_ids[] = { | ||
72 | { .compatible = "fsl,mpc5121-immr", }, | ||
73 | { .compatible = "fsl,mpc5121-localbus", }, | ||
74 | {}, | ||
75 | }; | ||
76 | |||
77 | void __init mpc512x_declare_of_platform_devices(void) | ||
78 | { | ||
79 | if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) | ||
80 | printk(KERN_ERR __FILE__ ": " | ||
81 | "Error while probing of_platform bus\n"); | ||
82 | } | ||
83 | |||