diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2006-09-26 02:32:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:54 -0400 |
commit | 5f97f7f9400de47ae837170bb274e90ad3934386 (patch) | |
tree | 514451e6dc6b46253293a00035d375e77b1c65ed /arch/avr32/mach-at32ap/at32ap7000.c | |
parent | 53e62d3aaa60590d4a69b4e07c29f448b5151047 (diff) |
[PATCH] avr32 architecture
This adds support for the Atmel AVR32 architecture as well as the AT32AP7000
CPU and the AT32STK1000 development board.
AVR32 is a new high-performance 32-bit RISC microprocessor core, designed for
cost-sensitive embedded applications, with particular emphasis on low power
consumption and high code density. The AVR32 architecture is not binary
compatible with earlier 8-bit AVR architectures.
The AVR32 architecture, including the instruction set, is described by the
AVR32 Architecture Manual, available from
http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf
The Atmel AT32AP7000 is the first CPU implementing the AVR32 architecture. It
features a 7-stage pipeline, 16KB instruction and data caches and a full
Memory Management Unit. It also comes with a large set of integrated
peripherals, many of which are shared with the AT91 ARM-based controllers from
Atmel.
Full data sheet is available from
http://www.atmel.com/dyn/resources/prod_documents/doc32003.pdf
while the CPU core implementation including caches and MMU is documented by
the AVR32 AP Technical Reference, available from
http://www.atmel.com/dyn/resources/prod_documents/doc32001.pdf
Information about the AT32STK1000 development board can be found at
http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3918
including a BSP CD image with an earlier version of this patch, development
tools (binaries and source/patches) and a root filesystem image suitable for
booting from SD card.
Alternatively, there's a preliminary "getting started" guide available at
http://avr32linux.org/twiki/bin/view/Main/GettingStarted which provides links
to the sources and patches you will need in order to set up a cross-compiling
environment for avr32-linux.
This patch, as well as the other patches included with the BSP and the
toolchain patches, is actively supported by Atmel Corporation.
[dmccr@us.ibm.com: Fix more pxx_page macro locations]
[bunk@stusta.de: fix `make defconfig']
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Dave McCracken <dmccr@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/avr32/mach-at32ap/at32ap7000.c')
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap7000.c | 866 |
1 files changed, 866 insertions, 0 deletions
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c new file mode 100644 index 000000000000..e8c6893a1c23 --- /dev/null +++ b/arch/avr32/mach-at32ap/at32ap7000.c | |||
@@ -0,0 +1,866 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2006 Atmel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/clk.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | |||
12 | #include <asm/io.h> | ||
13 | |||
14 | #include <asm/arch/board.h> | ||
15 | #include <asm/arch/portmux.h> | ||
16 | #include <asm/arch/sm.h> | ||
17 | |||
18 | #include "clock.h" | ||
19 | #include "pio.h" | ||
20 | #include "sm.h" | ||
21 | |||
22 | #define PBMEM(base) \ | ||
23 | { \ | ||
24 | .start = base, \ | ||
25 | .end = base + 0x3ff, \ | ||
26 | .flags = IORESOURCE_MEM, \ | ||
27 | } | ||
28 | #define IRQ(num) \ | ||
29 | { \ | ||
30 | .start = num, \ | ||
31 | .end = num, \ | ||
32 | .flags = IORESOURCE_IRQ, \ | ||
33 | } | ||
34 | #define NAMED_IRQ(num, _name) \ | ||
35 | { \ | ||
36 | .start = num, \ | ||
37 | .end = num, \ | ||
38 | .name = _name, \ | ||
39 | .flags = IORESOURCE_IRQ, \ | ||
40 | } | ||
41 | |||
42 | #define DEFINE_DEV(_name, _id) \ | ||
43 | static struct platform_device _name##_id##_device = { \ | ||
44 | .name = #_name, \ | ||
45 | .id = _id, \ | ||
46 | .resource = _name##_id##_resource, \ | ||
47 | .num_resources = ARRAY_SIZE(_name##_id##_resource), \ | ||
48 | } | ||
49 | #define DEFINE_DEV_DATA(_name, _id) \ | ||
50 | static struct platform_device _name##_id##_device = { \ | ||
51 | .name = #_name, \ | ||
52 | .id = _id, \ | ||
53 | .dev = { \ | ||
54 | .platform_data = &_name##_id##_data, \ | ||
55 | }, \ | ||
56 | .resource = _name##_id##_resource, \ | ||
57 | .num_resources = ARRAY_SIZE(_name##_id##_resource), \ | ||
58 | } | ||
59 | |||
60 | #define DEV_CLK(_name, devname, bus, _index) \ | ||
61 | static struct clk devname##_##_name = { \ | ||
62 | .name = #_name, \ | ||
63 | .dev = &devname##_device.dev, \ | ||
64 | .parent = &bus##_clk, \ | ||
65 | .mode = bus##_clk_mode, \ | ||
66 | .get_rate = bus##_clk_get_rate, \ | ||
67 | .index = _index, \ | ||
68 | } | ||
69 | |||
70 | enum { | ||
71 | PIOA, | ||
72 | PIOB, | ||
73 | PIOC, | ||
74 | PIOD, | ||
75 | }; | ||
76 | |||
77 | enum { | ||
78 | FUNC_A, | ||
79 | FUNC_B, | ||
80 | }; | ||
81 | |||
82 | unsigned long at32ap7000_osc_rates[3] = { | ||
83 | [0] = 32768, | ||
84 | /* FIXME: these are ATSTK1002-specific */ | ||
85 | [1] = 20000000, | ||
86 | [2] = 12000000, | ||
87 | }; | ||
88 | |||
89 | static unsigned long osc_get_rate(struct clk *clk) | ||
90 | { | ||
91 | return at32ap7000_osc_rates[clk->index]; | ||
92 | } | ||
93 | |||
94 | static unsigned long pll_get_rate(struct clk *clk, unsigned long control) | ||
95 | { | ||
96 | unsigned long div, mul, rate; | ||
97 | |||
98 | if (!(control & SM_BIT(PLLEN))) | ||
99 | return 0; | ||
100 | |||
101 | div = SM_BFEXT(PLLDIV, control) + 1; | ||
102 | mul = SM_BFEXT(PLLMUL, control) + 1; | ||
103 | |||
104 | rate = clk->parent->get_rate(clk->parent); | ||
105 | rate = (rate + div / 2) / div; | ||
106 | rate *= mul; | ||
107 | |||
108 | return rate; | ||
109 | } | ||
110 | |||
111 | static unsigned long pll0_get_rate(struct clk *clk) | ||
112 | { | ||
113 | u32 control; | ||
114 | |||
115 | control = sm_readl(&system_manager, PM_PLL0); | ||
116 | |||
117 | return pll_get_rate(clk, control); | ||
118 | } | ||
119 | |||
120 | static unsigned long pll1_get_rate(struct clk *clk) | ||
121 | { | ||
122 | u32 control; | ||
123 | |||
124 | control = sm_readl(&system_manager, PM_PLL1); | ||
125 | |||
126 | return pll_get_rate(clk, control); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * The AT32AP7000 has five primary clock sources: One 32kHz | ||
131 | * oscillator, two crystal oscillators and two PLLs. | ||
132 | */ | ||
133 | static struct clk osc32k = { | ||
134 | .name = "osc32k", | ||
135 | .get_rate = osc_get_rate, | ||
136 | .users = 1, | ||
137 | .index = 0, | ||
138 | }; | ||
139 | static struct clk osc0 = { | ||
140 | .name = "osc0", | ||
141 | .get_rate = osc_get_rate, | ||
142 | .users = 1, | ||
143 | .index = 1, | ||
144 | }; | ||
145 | static struct clk osc1 = { | ||
146 | .name = "osc1", | ||
147 | .get_rate = osc_get_rate, | ||
148 | .index = 2, | ||
149 | }; | ||
150 | static struct clk pll0 = { | ||
151 | .name = "pll0", | ||
152 | .get_rate = pll0_get_rate, | ||
153 | .parent = &osc0, | ||
154 | }; | ||
155 | static struct clk pll1 = { | ||
156 | .name = "pll1", | ||
157 | .get_rate = pll1_get_rate, | ||
158 | .parent = &osc0, | ||
159 | }; | ||
160 | |||
161 | /* | ||
162 | * The main clock can be either osc0 or pll0. The boot loader may | ||
163 | * have chosen one for us, so we don't really know which one until we | ||
164 | * have a look at the SM. | ||
165 | */ | ||
166 | static struct clk *main_clock; | ||
167 | |||
168 | /* | ||
169 | * Synchronous clocks are generated from the main clock. The clocks | ||
170 | * must satisfy the constraint | ||
171 | * fCPU >= fHSB >= fPB | ||
172 | * i.e. each clock must not be faster than its parent. | ||
173 | */ | ||
174 | static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift) | ||
175 | { | ||
176 | return main_clock->get_rate(main_clock) >> shift; | ||
177 | }; | ||
178 | |||
179 | static void cpu_clk_mode(struct clk *clk, int enabled) | ||
180 | { | ||
181 | struct at32_sm *sm = &system_manager; | ||
182 | unsigned long flags; | ||
183 | u32 mask; | ||
184 | |||
185 | spin_lock_irqsave(&sm->lock, flags); | ||
186 | mask = sm_readl(sm, PM_CPU_MASK); | ||
187 | if (enabled) | ||
188 | mask |= 1 << clk->index; | ||
189 | else | ||
190 | mask &= ~(1 << clk->index); | ||
191 | sm_writel(sm, PM_CPU_MASK, mask); | ||
192 | spin_unlock_irqrestore(&sm->lock, flags); | ||
193 | } | ||
194 | |||
195 | static unsigned long cpu_clk_get_rate(struct clk *clk) | ||
196 | { | ||
197 | unsigned long cksel, shift = 0; | ||
198 | |||
199 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
200 | if (cksel & SM_BIT(CPUDIV)) | ||
201 | shift = SM_BFEXT(CPUSEL, cksel) + 1; | ||
202 | |||
203 | return bus_clk_get_rate(clk, shift); | ||
204 | } | ||
205 | |||
206 | static void hsb_clk_mode(struct clk *clk, int enabled) | ||
207 | { | ||
208 | struct at32_sm *sm = &system_manager; | ||
209 | unsigned long flags; | ||
210 | u32 mask; | ||
211 | |||
212 | spin_lock_irqsave(&sm->lock, flags); | ||
213 | mask = sm_readl(sm, PM_HSB_MASK); | ||
214 | if (enabled) | ||
215 | mask |= 1 << clk->index; | ||
216 | else | ||
217 | mask &= ~(1 << clk->index); | ||
218 | sm_writel(sm, PM_HSB_MASK, mask); | ||
219 | spin_unlock_irqrestore(&sm->lock, flags); | ||
220 | } | ||
221 | |||
222 | static unsigned long hsb_clk_get_rate(struct clk *clk) | ||
223 | { | ||
224 | unsigned long cksel, shift = 0; | ||
225 | |||
226 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
227 | if (cksel & SM_BIT(HSBDIV)) | ||
228 | shift = SM_BFEXT(HSBSEL, cksel) + 1; | ||
229 | |||
230 | return bus_clk_get_rate(clk, shift); | ||
231 | } | ||
232 | |||
233 | static void pba_clk_mode(struct clk *clk, int enabled) | ||
234 | { | ||
235 | struct at32_sm *sm = &system_manager; | ||
236 | unsigned long flags; | ||
237 | u32 mask; | ||
238 | |||
239 | spin_lock_irqsave(&sm->lock, flags); | ||
240 | mask = sm_readl(sm, PM_PBA_MASK); | ||
241 | if (enabled) | ||
242 | mask |= 1 << clk->index; | ||
243 | else | ||
244 | mask &= ~(1 << clk->index); | ||
245 | sm_writel(sm, PM_PBA_MASK, mask); | ||
246 | spin_unlock_irqrestore(&sm->lock, flags); | ||
247 | } | ||
248 | |||
249 | static unsigned long pba_clk_get_rate(struct clk *clk) | ||
250 | { | ||
251 | unsigned long cksel, shift = 0; | ||
252 | |||
253 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
254 | if (cksel & SM_BIT(PBADIV)) | ||
255 | shift = SM_BFEXT(PBASEL, cksel) + 1; | ||
256 | |||
257 | return bus_clk_get_rate(clk, shift); | ||
258 | } | ||
259 | |||
260 | static void pbb_clk_mode(struct clk *clk, int enabled) | ||
261 | { | ||
262 | struct at32_sm *sm = &system_manager; | ||
263 | unsigned long flags; | ||
264 | u32 mask; | ||
265 | |||
266 | spin_lock_irqsave(&sm->lock, flags); | ||
267 | mask = sm_readl(sm, PM_PBB_MASK); | ||
268 | if (enabled) | ||
269 | mask |= 1 << clk->index; | ||
270 | else | ||
271 | mask &= ~(1 << clk->index); | ||
272 | sm_writel(sm, PM_PBB_MASK, mask); | ||
273 | spin_unlock_irqrestore(&sm->lock, flags); | ||
274 | } | ||
275 | |||
276 | static unsigned long pbb_clk_get_rate(struct clk *clk) | ||
277 | { | ||
278 | unsigned long cksel, shift = 0; | ||
279 | |||
280 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
281 | if (cksel & SM_BIT(PBBDIV)) | ||
282 | shift = SM_BFEXT(PBBSEL, cksel) + 1; | ||
283 | |||
284 | return bus_clk_get_rate(clk, shift); | ||
285 | } | ||
286 | |||
287 | static struct clk cpu_clk = { | ||
288 | .name = "cpu", | ||
289 | .get_rate = cpu_clk_get_rate, | ||
290 | .users = 1, | ||
291 | }; | ||
292 | static struct clk hsb_clk = { | ||
293 | .name = "hsb", | ||
294 | .parent = &cpu_clk, | ||
295 | .get_rate = hsb_clk_get_rate, | ||
296 | }; | ||
297 | static struct clk pba_clk = { | ||
298 | .name = "pba", | ||
299 | .parent = &hsb_clk, | ||
300 | .mode = hsb_clk_mode, | ||
301 | .get_rate = pba_clk_get_rate, | ||
302 | .index = 1, | ||
303 | }; | ||
304 | static struct clk pbb_clk = { | ||
305 | .name = "pbb", | ||
306 | .parent = &hsb_clk, | ||
307 | .mode = hsb_clk_mode, | ||
308 | .get_rate = pbb_clk_get_rate, | ||
309 | .users = 1, | ||
310 | .index = 2, | ||
311 | }; | ||
312 | |||
313 | /* -------------------------------------------------------------------- | ||
314 | * Generic Clock operations | ||
315 | * -------------------------------------------------------------------- */ | ||
316 | |||
317 | static void genclk_mode(struct clk *clk, int enabled) | ||
318 | { | ||
319 | u32 control; | ||
320 | |||
321 | BUG_ON(clk->index > 7); | ||
322 | |||
323 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
324 | if (enabled) | ||
325 | control |= SM_BIT(CEN); | ||
326 | else | ||
327 | control &= ~SM_BIT(CEN); | ||
328 | sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control); | ||
329 | } | ||
330 | |||
331 | static unsigned long genclk_get_rate(struct clk *clk) | ||
332 | { | ||
333 | u32 control; | ||
334 | unsigned long div = 1; | ||
335 | |||
336 | BUG_ON(clk->index > 7); | ||
337 | |||
338 | if (!clk->parent) | ||
339 | return 0; | ||
340 | |||
341 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
342 | if (control & SM_BIT(DIVEN)) | ||
343 | div = 2 * (SM_BFEXT(DIV, control) + 1); | ||
344 | |||
345 | return clk->parent->get_rate(clk->parent) / div; | ||
346 | } | ||
347 | |||
348 | static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply) | ||
349 | { | ||
350 | u32 control; | ||
351 | unsigned long parent_rate, actual_rate, div; | ||
352 | |||
353 | BUG_ON(clk->index > 7); | ||
354 | |||
355 | if (!clk->parent) | ||
356 | return 0; | ||
357 | |||
358 | parent_rate = clk->parent->get_rate(clk->parent); | ||
359 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
360 | |||
361 | if (rate > 3 * parent_rate / 4) { | ||
362 | actual_rate = parent_rate; | ||
363 | control &= ~SM_BIT(DIVEN); | ||
364 | } else { | ||
365 | div = (parent_rate + rate) / (2 * rate) - 1; | ||
366 | control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN); | ||
367 | actual_rate = parent_rate / (2 * (div + 1)); | ||
368 | } | ||
369 | |||
370 | printk("clk %s: new rate %lu (actual rate %lu)\n", | ||
371 | clk->name, rate, actual_rate); | ||
372 | |||
373 | if (apply) | ||
374 | sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, | ||
375 | control); | ||
376 | |||
377 | return actual_rate; | ||
378 | } | ||
379 | |||
380 | int genclk_set_parent(struct clk *clk, struct clk *parent) | ||
381 | { | ||
382 | u32 control; | ||
383 | |||
384 | BUG_ON(clk->index > 7); | ||
385 | |||
386 | printk("clk %s: new parent %s (was %s)\n", | ||
387 | clk->name, parent->name, | ||
388 | clk->parent ? clk->parent->name : "(null)"); | ||
389 | |||
390 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
391 | |||
392 | if (parent == &osc1 || parent == &pll1) | ||
393 | control |= SM_BIT(OSCSEL); | ||
394 | else if (parent == &osc0 || parent == &pll0) | ||
395 | control &= ~SM_BIT(OSCSEL); | ||
396 | else | ||
397 | return -EINVAL; | ||
398 | |||
399 | if (parent == &pll0 || parent == &pll1) | ||
400 | control |= SM_BIT(PLLSEL); | ||
401 | else | ||
402 | control &= ~SM_BIT(PLLSEL); | ||
403 | |||
404 | sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control); | ||
405 | clk->parent = parent; | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | /* -------------------------------------------------------------------- | ||
411 | * System peripherals | ||
412 | * -------------------------------------------------------------------- */ | ||
413 | static struct resource sm_resource[] = { | ||
414 | PBMEM(0xfff00000), | ||
415 | NAMED_IRQ(19, "eim"), | ||
416 | NAMED_IRQ(20, "pm"), | ||
417 | NAMED_IRQ(21, "rtc"), | ||
418 | }; | ||
419 | struct platform_device at32_sm_device = { | ||
420 | .name = "sm", | ||
421 | .id = 0, | ||
422 | .resource = sm_resource, | ||
423 | .num_resources = ARRAY_SIZE(sm_resource), | ||
424 | }; | ||
425 | DEV_CLK(pclk, at32_sm, pbb, 0); | ||
426 | |||
427 | static struct resource intc0_resource[] = { | ||
428 | PBMEM(0xfff00400), | ||
429 | }; | ||
430 | struct platform_device at32_intc0_device = { | ||
431 | .name = "intc", | ||
432 | .id = 0, | ||
433 | .resource = intc0_resource, | ||
434 | .num_resources = ARRAY_SIZE(intc0_resource), | ||
435 | }; | ||
436 | DEV_CLK(pclk, at32_intc0, pbb, 1); | ||
437 | |||
438 | static struct clk ebi_clk = { | ||
439 | .name = "ebi", | ||
440 | .parent = &hsb_clk, | ||
441 | .mode = hsb_clk_mode, | ||
442 | .get_rate = hsb_clk_get_rate, | ||
443 | .users = 1, | ||
444 | }; | ||
445 | static struct clk hramc_clk = { | ||
446 | .name = "hramc", | ||
447 | .parent = &hsb_clk, | ||
448 | .mode = hsb_clk_mode, | ||
449 | .get_rate = hsb_clk_get_rate, | ||
450 | .users = 1, | ||
451 | }; | ||
452 | |||
453 | static struct platform_device pdc_device = { | ||
454 | .name = "pdc", | ||
455 | .id = 0, | ||
456 | }; | ||
457 | DEV_CLK(hclk, pdc, hsb, 4); | ||
458 | DEV_CLK(pclk, pdc, pba, 16); | ||
459 | |||
460 | static struct clk pico_clk = { | ||
461 | .name = "pico", | ||
462 | .parent = &cpu_clk, | ||
463 | .mode = cpu_clk_mode, | ||
464 | .get_rate = cpu_clk_get_rate, | ||
465 | .users = 1, | ||
466 | }; | ||
467 | |||
468 | /* -------------------------------------------------------------------- | ||
469 | * PIO | ||
470 | * -------------------------------------------------------------------- */ | ||
471 | |||
472 | static struct resource pio0_resource[] = { | ||
473 | PBMEM(0xffe02800), | ||
474 | IRQ(13), | ||
475 | }; | ||
476 | DEFINE_DEV(pio, 0); | ||
477 | DEV_CLK(mck, pio0, pba, 10); | ||
478 | |||
479 | static struct resource pio1_resource[] = { | ||
480 | PBMEM(0xffe02c00), | ||
481 | IRQ(14), | ||
482 | }; | ||
483 | DEFINE_DEV(pio, 1); | ||
484 | DEV_CLK(mck, pio1, pba, 11); | ||
485 | |||
486 | static struct resource pio2_resource[] = { | ||
487 | PBMEM(0xffe03000), | ||
488 | IRQ(15), | ||
489 | }; | ||
490 | DEFINE_DEV(pio, 2); | ||
491 | DEV_CLK(mck, pio2, pba, 12); | ||
492 | |||
493 | static struct resource pio3_resource[] = { | ||
494 | PBMEM(0xffe03400), | ||
495 | IRQ(16), | ||
496 | }; | ||
497 | DEFINE_DEV(pio, 3); | ||
498 | DEV_CLK(mck, pio3, pba, 13); | ||
499 | |||
500 | void __init at32_add_system_devices(void) | ||
501 | { | ||
502 | system_manager.eim_first_irq = NR_INTERNAL_IRQS; | ||
503 | |||
504 | platform_device_register(&at32_sm_device); | ||
505 | platform_device_register(&at32_intc0_device); | ||
506 | platform_device_register(&pdc_device); | ||
507 | |||
508 | platform_device_register(&pio0_device); | ||
509 | platform_device_register(&pio1_device); | ||
510 | platform_device_register(&pio2_device); | ||
511 | platform_device_register(&pio3_device); | ||
512 | } | ||
513 | |||
514 | /* -------------------------------------------------------------------- | ||
515 | * USART | ||
516 | * -------------------------------------------------------------------- */ | ||
517 | |||
518 | static struct resource usart0_resource[] = { | ||
519 | PBMEM(0xffe00c00), | ||
520 | IRQ(7), | ||
521 | }; | ||
522 | DEFINE_DEV(usart, 0); | ||
523 | DEV_CLK(usart, usart0, pba, 4); | ||
524 | |||
525 | static struct resource usart1_resource[] = { | ||
526 | PBMEM(0xffe01000), | ||
527 | IRQ(7), | ||
528 | }; | ||
529 | DEFINE_DEV(usart, 1); | ||
530 | DEV_CLK(usart, usart1, pba, 4); | ||
531 | |||
532 | static struct resource usart2_resource[] = { | ||
533 | PBMEM(0xffe01400), | ||
534 | IRQ(8), | ||
535 | }; | ||
536 | DEFINE_DEV(usart, 2); | ||
537 | DEV_CLK(usart, usart2, pba, 5); | ||
538 | |||
539 | static struct resource usart3_resource[] = { | ||
540 | PBMEM(0xffe01800), | ||
541 | IRQ(9), | ||
542 | }; | ||
543 | DEFINE_DEV(usart, 3); | ||
544 | DEV_CLK(usart, usart3, pba, 6); | ||
545 | |||
546 | static inline void configure_usart0_pins(void) | ||
547 | { | ||
548 | portmux_set_func(PIOA, 8, FUNC_B); /* RXD */ | ||
549 | portmux_set_func(PIOA, 9, FUNC_B); /* TXD */ | ||
550 | } | ||
551 | |||
552 | static inline void configure_usart1_pins(void) | ||
553 | { | ||
554 | portmux_set_func(PIOA, 17, FUNC_A); /* RXD */ | ||
555 | portmux_set_func(PIOA, 18, FUNC_A); /* TXD */ | ||
556 | } | ||
557 | |||
558 | static inline void configure_usart2_pins(void) | ||
559 | { | ||
560 | portmux_set_func(PIOB, 26, FUNC_B); /* RXD */ | ||
561 | portmux_set_func(PIOB, 27, FUNC_B); /* TXD */ | ||
562 | } | ||
563 | |||
564 | static inline void configure_usart3_pins(void) | ||
565 | { | ||
566 | portmux_set_func(PIOB, 18, FUNC_B); /* RXD */ | ||
567 | portmux_set_func(PIOB, 17, FUNC_B); /* TXD */ | ||
568 | } | ||
569 | |||
570 | static struct platform_device *setup_usart(unsigned int id) | ||
571 | { | ||
572 | struct platform_device *pdev; | ||
573 | |||
574 | switch (id) { | ||
575 | case 0: | ||
576 | pdev = &usart0_device; | ||
577 | configure_usart0_pins(); | ||
578 | break; | ||
579 | case 1: | ||
580 | pdev = &usart1_device; | ||
581 | configure_usart1_pins(); | ||
582 | break; | ||
583 | case 2: | ||
584 | pdev = &usart2_device; | ||
585 | configure_usart2_pins(); | ||
586 | break; | ||
587 | case 3: | ||
588 | pdev = &usart3_device; | ||
589 | configure_usart3_pins(); | ||
590 | break; | ||
591 | default: | ||
592 | pdev = NULL; | ||
593 | break; | ||
594 | } | ||
595 | |||
596 | return pdev; | ||
597 | } | ||
598 | |||
599 | struct platform_device *__init at32_add_device_usart(unsigned int id) | ||
600 | { | ||
601 | struct platform_device *pdev; | ||
602 | |||
603 | pdev = setup_usart(id); | ||
604 | if (pdev) | ||
605 | platform_device_register(pdev); | ||
606 | |||
607 | return pdev; | ||
608 | } | ||
609 | |||
610 | struct platform_device *at91_default_console_device; | ||
611 | |||
612 | void __init at32_setup_serial_console(unsigned int usart_id) | ||
613 | { | ||
614 | at91_default_console_device = setup_usart(usart_id); | ||
615 | } | ||
616 | |||
617 | /* -------------------------------------------------------------------- | ||
618 | * Ethernet | ||
619 | * -------------------------------------------------------------------- */ | ||
620 | |||
621 | static struct eth_platform_data macb0_data; | ||
622 | static struct resource macb0_resource[] = { | ||
623 | PBMEM(0xfff01800), | ||
624 | IRQ(25), | ||
625 | }; | ||
626 | DEFINE_DEV_DATA(macb, 0); | ||
627 | DEV_CLK(hclk, macb0, hsb, 8); | ||
628 | DEV_CLK(pclk, macb0, pbb, 6); | ||
629 | |||
630 | struct platform_device *__init | ||
631 | at32_add_device_eth(unsigned int id, struct eth_platform_data *data) | ||
632 | { | ||
633 | struct platform_device *pdev; | ||
634 | |||
635 | switch (id) { | ||
636 | case 0: | ||
637 | pdev = &macb0_device; | ||
638 | |||
639 | portmux_set_func(PIOC, 3, FUNC_A); /* TXD0 */ | ||
640 | portmux_set_func(PIOC, 4, FUNC_A); /* TXD1 */ | ||
641 | portmux_set_func(PIOC, 7, FUNC_A); /* TXEN */ | ||
642 | portmux_set_func(PIOC, 8, FUNC_A); /* TXCK */ | ||
643 | portmux_set_func(PIOC, 9, FUNC_A); /* RXD0 */ | ||
644 | portmux_set_func(PIOC, 10, FUNC_A); /* RXD1 */ | ||
645 | portmux_set_func(PIOC, 13, FUNC_A); /* RXER */ | ||
646 | portmux_set_func(PIOC, 15, FUNC_A); /* RXDV */ | ||
647 | portmux_set_func(PIOC, 16, FUNC_A); /* MDC */ | ||
648 | portmux_set_func(PIOC, 17, FUNC_A); /* MDIO */ | ||
649 | |||
650 | if (!data->is_rmii) { | ||
651 | portmux_set_func(PIOC, 0, FUNC_A); /* COL */ | ||
652 | portmux_set_func(PIOC, 1, FUNC_A); /* CRS */ | ||
653 | portmux_set_func(PIOC, 2, FUNC_A); /* TXER */ | ||
654 | portmux_set_func(PIOC, 5, FUNC_A); /* TXD2 */ | ||
655 | portmux_set_func(PIOC, 6, FUNC_A); /* TXD3 */ | ||
656 | portmux_set_func(PIOC, 11, FUNC_A); /* RXD2 */ | ||
657 | portmux_set_func(PIOC, 12, FUNC_A); /* RXD3 */ | ||
658 | portmux_set_func(PIOC, 14, FUNC_A); /* RXCK */ | ||
659 | portmux_set_func(PIOC, 18, FUNC_A); /* SPD */ | ||
660 | } | ||
661 | break; | ||
662 | |||
663 | default: | ||
664 | return NULL; | ||
665 | } | ||
666 | |||
667 | memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data)); | ||
668 | platform_device_register(pdev); | ||
669 | |||
670 | return pdev; | ||
671 | } | ||
672 | |||
673 | /* -------------------------------------------------------------------- | ||
674 | * SPI | ||
675 | * -------------------------------------------------------------------- */ | ||
676 | static struct resource spi0_resource[] = { | ||
677 | PBMEM(0xffe00000), | ||
678 | IRQ(3), | ||
679 | }; | ||
680 | DEFINE_DEV(spi, 0); | ||
681 | DEV_CLK(mck, spi0, pba, 0); | ||
682 | |||
683 | struct platform_device *__init at32_add_device_spi(unsigned int id) | ||
684 | { | ||
685 | struct platform_device *pdev; | ||
686 | |||
687 | switch (id) { | ||
688 | case 0: | ||
689 | pdev = &spi0_device; | ||
690 | portmux_set_func(PIOA, 0, FUNC_A); /* MISO */ | ||
691 | portmux_set_func(PIOA, 1, FUNC_A); /* MOSI */ | ||
692 | portmux_set_func(PIOA, 2, FUNC_A); /* SCK */ | ||
693 | portmux_set_func(PIOA, 3, FUNC_A); /* NPCS0 */ | ||
694 | portmux_set_func(PIOA, 4, FUNC_A); /* NPCS1 */ | ||
695 | portmux_set_func(PIOA, 5, FUNC_A); /* NPCS2 */ | ||
696 | break; | ||
697 | |||
698 | default: | ||
699 | return NULL; | ||
700 | } | ||
701 | |||
702 | platform_device_register(pdev); | ||
703 | return pdev; | ||
704 | } | ||
705 | |||
706 | /* -------------------------------------------------------------------- | ||
707 | * LCDC | ||
708 | * -------------------------------------------------------------------- */ | ||
709 | static struct lcdc_platform_data lcdc0_data; | ||
710 | static struct resource lcdc0_resource[] = { | ||
711 | { | ||
712 | .start = 0xff000000, | ||
713 | .end = 0xff000fff, | ||
714 | .flags = IORESOURCE_MEM, | ||
715 | }, | ||
716 | IRQ(1), | ||
717 | }; | ||
718 | DEFINE_DEV_DATA(lcdc, 0); | ||
719 | DEV_CLK(hclk, lcdc0, hsb, 7); | ||
720 | static struct clk lcdc0_pixclk = { | ||
721 | .name = "pixclk", | ||
722 | .dev = &lcdc0_device.dev, | ||
723 | .mode = genclk_mode, | ||
724 | .get_rate = genclk_get_rate, | ||
725 | .set_rate = genclk_set_rate, | ||
726 | .set_parent = genclk_set_parent, | ||
727 | .index = 7, | ||
728 | }; | ||
729 | |||
730 | struct platform_device *__init | ||
731 | at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data) | ||
732 | { | ||
733 | struct platform_device *pdev; | ||
734 | |||
735 | switch (id) { | ||
736 | case 0: | ||
737 | pdev = &lcdc0_device; | ||
738 | portmux_set_func(PIOC, 19, FUNC_A); /* CC */ | ||
739 | portmux_set_func(PIOC, 20, FUNC_A); /* HSYNC */ | ||
740 | portmux_set_func(PIOC, 21, FUNC_A); /* PCLK */ | ||
741 | portmux_set_func(PIOC, 22, FUNC_A); /* VSYNC */ | ||
742 | portmux_set_func(PIOC, 23, FUNC_A); /* DVAL */ | ||
743 | portmux_set_func(PIOC, 24, FUNC_A); /* MODE */ | ||
744 | portmux_set_func(PIOC, 25, FUNC_A); /* PWR */ | ||
745 | portmux_set_func(PIOC, 26, FUNC_A); /* DATA0 */ | ||
746 | portmux_set_func(PIOC, 27, FUNC_A); /* DATA1 */ | ||
747 | portmux_set_func(PIOC, 28, FUNC_A); /* DATA2 */ | ||
748 | portmux_set_func(PIOC, 29, FUNC_A); /* DATA3 */ | ||
749 | portmux_set_func(PIOC, 30, FUNC_A); /* DATA4 */ | ||
750 | portmux_set_func(PIOC, 31, FUNC_A); /* DATA5 */ | ||
751 | portmux_set_func(PIOD, 0, FUNC_A); /* DATA6 */ | ||
752 | portmux_set_func(PIOD, 1, FUNC_A); /* DATA7 */ | ||
753 | portmux_set_func(PIOD, 2, FUNC_A); /* DATA8 */ | ||
754 | portmux_set_func(PIOD, 3, FUNC_A); /* DATA9 */ | ||
755 | portmux_set_func(PIOD, 4, FUNC_A); /* DATA10 */ | ||
756 | portmux_set_func(PIOD, 5, FUNC_A); /* DATA11 */ | ||
757 | portmux_set_func(PIOD, 6, FUNC_A); /* DATA12 */ | ||
758 | portmux_set_func(PIOD, 7, FUNC_A); /* DATA13 */ | ||
759 | portmux_set_func(PIOD, 8, FUNC_A); /* DATA14 */ | ||
760 | portmux_set_func(PIOD, 9, FUNC_A); /* DATA15 */ | ||
761 | portmux_set_func(PIOD, 10, FUNC_A); /* DATA16 */ | ||
762 | portmux_set_func(PIOD, 11, FUNC_A); /* DATA17 */ | ||
763 | portmux_set_func(PIOD, 12, FUNC_A); /* DATA18 */ | ||
764 | portmux_set_func(PIOD, 13, FUNC_A); /* DATA19 */ | ||
765 | portmux_set_func(PIOD, 14, FUNC_A); /* DATA20 */ | ||
766 | portmux_set_func(PIOD, 15, FUNC_A); /* DATA21 */ | ||
767 | portmux_set_func(PIOD, 16, FUNC_A); /* DATA22 */ | ||
768 | portmux_set_func(PIOD, 17, FUNC_A); /* DATA23 */ | ||
769 | |||
770 | clk_set_parent(&lcdc0_pixclk, &pll0); | ||
771 | clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0)); | ||
772 | break; | ||
773 | |||
774 | default: | ||
775 | return NULL; | ||
776 | } | ||
777 | |||
778 | memcpy(pdev->dev.platform_data, data, | ||
779 | sizeof(struct lcdc_platform_data)); | ||
780 | |||
781 | platform_device_register(pdev); | ||
782 | return pdev; | ||
783 | } | ||
784 | |||
785 | struct clk *at32_clock_list[] = { | ||
786 | &osc32k, | ||
787 | &osc0, | ||
788 | &osc1, | ||
789 | &pll0, | ||
790 | &pll1, | ||
791 | &cpu_clk, | ||
792 | &hsb_clk, | ||
793 | &pba_clk, | ||
794 | &pbb_clk, | ||
795 | &at32_sm_pclk, | ||
796 | &at32_intc0_pclk, | ||
797 | &ebi_clk, | ||
798 | &hramc_clk, | ||
799 | &pdc_hclk, | ||
800 | &pdc_pclk, | ||
801 | &pico_clk, | ||
802 | &pio0_mck, | ||
803 | &pio1_mck, | ||
804 | &pio2_mck, | ||
805 | &pio3_mck, | ||
806 | &usart0_usart, | ||
807 | &usart1_usart, | ||
808 | &usart2_usart, | ||
809 | &usart3_usart, | ||
810 | &macb0_hclk, | ||
811 | &macb0_pclk, | ||
812 | &spi0_mck, | ||
813 | &lcdc0_hclk, | ||
814 | &lcdc0_pixclk, | ||
815 | }; | ||
816 | unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); | ||
817 | |||
818 | void __init at32_portmux_init(void) | ||
819 | { | ||
820 | at32_init_pio(&pio0_device); | ||
821 | at32_init_pio(&pio1_device); | ||
822 | at32_init_pio(&pio2_device); | ||
823 | at32_init_pio(&pio3_device); | ||
824 | } | ||
825 | |||
826 | void __init at32_clock_init(void) | ||
827 | { | ||
828 | struct at32_sm *sm = &system_manager; | ||
829 | u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; | ||
830 | int i; | ||
831 | |||
832 | if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL)) | ||
833 | main_clock = &pll0; | ||
834 | else | ||
835 | main_clock = &osc0; | ||
836 | |||
837 | if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC)) | ||
838 | pll0.parent = &osc1; | ||
839 | if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC)) | ||
840 | pll1.parent = &osc1; | ||
841 | |||
842 | /* | ||
843 | * Turn on all clocks that have at least one user already, and | ||
844 | * turn off everything else. We only do this for module | ||
845 | * clocks, and even though it isn't particularly pretty to | ||
846 | * check the address of the mode function, it should do the | ||
847 | * trick... | ||
848 | */ | ||
849 | for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { | ||
850 | struct clk *clk = at32_clock_list[i]; | ||
851 | |||
852 | if (clk->mode == &cpu_clk_mode) | ||
853 | cpu_mask |= 1 << clk->index; | ||
854 | else if (clk->mode == &hsb_clk_mode) | ||
855 | hsb_mask |= 1 << clk->index; | ||
856 | else if (clk->mode == &pba_clk_mode) | ||
857 | pba_mask |= 1 << clk->index; | ||
858 | else if (clk->mode == &pbb_clk_mode) | ||
859 | pbb_mask |= 1 << clk->index; | ||
860 | } | ||
861 | |||
862 | sm_writel(sm, PM_CPU_MASK, cpu_mask); | ||
863 | sm_writel(sm, PM_HSB_MASK, hsb_mask); | ||
864 | sm_writel(sm, PM_PBA_MASK, pba_mask); | ||
865 | sm_writel(sm, PM_PBB_MASK, pbb_mask); | ||
866 | } | ||