diff options
author | Maxime Bizon <mbizon@freebox.fr> | 2009-08-18 08:23:37 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-09-17 14:07:52 -0400 |
commit | e7300d04bd0809eb7ea10a2ed8c729459f816e36 (patch) | |
tree | 8af589d3954c09323d3f74e69aa6fabbb32e049e /arch/mips/bcm63xx | |
parent | 0de663ef8627f35fda9106a8faaca512f29e493e (diff) |
MIPS: BCM63xx: Add support for the Broadcom BCM63xx family of SOCs.
Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/bcm63xx')
-rw-r--r-- | arch/mips/bcm63xx/Kconfig | 25 | ||||
-rw-r--r-- | arch/mips/bcm63xx/Makefile | 7 | ||||
-rw-r--r-- | arch/mips/bcm63xx/boards/Kconfig | 11 | ||||
-rw-r--r-- | arch/mips/bcm63xx/boards/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/bcm63xx/boards/board_bcm963xx.c | 837 | ||||
-rw-r--r-- | arch/mips/bcm63xx/clk.c | 226 | ||||
-rw-r--r-- | arch/mips/bcm63xx/cpu.c | 345 | ||||
-rw-r--r-- | arch/mips/bcm63xx/cs.c | 144 | ||||
-rw-r--r-- | arch/mips/bcm63xx/dev-dsp.c | 56 | ||||
-rw-r--r-- | arch/mips/bcm63xx/early_printk.c | 30 | ||||
-rw-r--r-- | arch/mips/bcm63xx/gpio.c | 134 | ||||
-rw-r--r-- | arch/mips/bcm63xx/irq.c | 253 | ||||
-rw-r--r-- | arch/mips/bcm63xx/prom.c | 55 | ||||
-rw-r--r-- | arch/mips/bcm63xx/setup.c | 125 | ||||
-rw-r--r-- | arch/mips/bcm63xx/timer.c | 205 |
15 files changed, 2456 insertions, 0 deletions
diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig new file mode 100644 index 000000000000..fb177d6df066 --- /dev/null +++ b/arch/mips/bcm63xx/Kconfig | |||
@@ -0,0 +1,25 @@ | |||
1 | menu "CPU support" | ||
2 | depends on BCM63XX | ||
3 | |||
4 | config BCM63XX_CPU_6338 | ||
5 | bool "support 6338 CPU" | ||
6 | select HW_HAS_PCI | ||
7 | select USB_ARCH_HAS_OHCI | ||
8 | select USB_OHCI_BIG_ENDIAN_DESC | ||
9 | select USB_OHCI_BIG_ENDIAN_MMIO | ||
10 | |||
11 | config BCM63XX_CPU_6345 | ||
12 | bool "support 6345 CPU" | ||
13 | select USB_OHCI_BIG_ENDIAN_DESC | ||
14 | select USB_OHCI_BIG_ENDIAN_MMIO | ||
15 | |||
16 | config BCM63XX_CPU_6348 | ||
17 | bool "support 6348 CPU" | ||
18 | select HW_HAS_PCI | ||
19 | |||
20 | config BCM63XX_CPU_6358 | ||
21 | bool "support 6358 CPU" | ||
22 | select HW_HAS_PCI | ||
23 | endmenu | ||
24 | |||
25 | source "arch/mips/bcm63xx/boards/Kconfig" | ||
diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile new file mode 100644 index 000000000000..99bbc8753a21 --- /dev/null +++ b/arch/mips/bcm63xx/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \ | ||
2 | dev-dsp.o | ||
3 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
4 | |||
5 | obj-y += boards/ | ||
6 | |||
7 | EXTRA_CFLAGS += -Werror | ||
diff --git a/arch/mips/bcm63xx/boards/Kconfig b/arch/mips/bcm63xx/boards/Kconfig new file mode 100644 index 000000000000..c6aed33d893e --- /dev/null +++ b/arch/mips/bcm63xx/boards/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | choice | ||
2 | prompt "Board support" | ||
3 | depends on BCM63XX | ||
4 | default BOARD_BCM963XX | ||
5 | |||
6 | config BOARD_BCM963XX | ||
7 | bool "Generic Broadcom 963xx boards" | ||
8 | select SSB | ||
9 | help | ||
10 | |||
11 | endchoice | ||
diff --git a/arch/mips/bcm63xx/boards/Makefile b/arch/mips/bcm63xx/boards/Makefile new file mode 100644 index 000000000000..e5cc86dc1da8 --- /dev/null +++ b/arch/mips/bcm63xx/boards/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_BOARD_BCM963XX) += board_bcm963xx.o | ||
2 | |||
3 | EXTRA_CFLAGS += -Werror | ||
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c new file mode 100644 index 000000000000..fd77f548207a --- /dev/null +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c | |||
@@ -0,0 +1,837 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/mtd/mtd.h> | ||
15 | #include <linux/mtd/partitions.h> | ||
16 | #include <linux/mtd/physmap.h> | ||
17 | #include <linux/ssb/ssb.h> | ||
18 | #include <asm/addrspace.h> | ||
19 | #include <bcm63xx_board.h> | ||
20 | #include <bcm63xx_cpu.h> | ||
21 | #include <bcm63xx_regs.h> | ||
22 | #include <bcm63xx_io.h> | ||
23 | #include <bcm63xx_board.h> | ||
24 | #include <bcm63xx_dev_pci.h> | ||
25 | #include <bcm63xx_dev_enet.h> | ||
26 | #include <bcm63xx_dev_dsp.h> | ||
27 | #include <board_bcm963xx.h> | ||
28 | |||
29 | #define PFX "board_bcm963xx: " | ||
30 | |||
31 | static struct bcm963xx_nvram nvram; | ||
32 | static unsigned int mac_addr_used; | ||
33 | static struct board_info board; | ||
34 | |||
35 | /* | ||
36 | * known 6338 boards | ||
37 | */ | ||
38 | #ifdef CONFIG_BCM63XX_CPU_6338 | ||
39 | static struct board_info __initdata board_96338gw = { | ||
40 | .name = "96338GW", | ||
41 | .expected_cpu_id = 0x6338, | ||
42 | |||
43 | .has_enet0 = 1, | ||
44 | .enet0 = { | ||
45 | .force_speed_100 = 1, | ||
46 | .force_duplex_full = 1, | ||
47 | }, | ||
48 | |||
49 | .has_ohci0 = 1, | ||
50 | |||
51 | .leds = { | ||
52 | { | ||
53 | .name = "adsl", | ||
54 | .gpio = 3, | ||
55 | .active_low = 1, | ||
56 | }, | ||
57 | { | ||
58 | .name = "ses", | ||
59 | .gpio = 5, | ||
60 | .active_low = 1, | ||
61 | }, | ||
62 | { | ||
63 | .name = "ppp-fail", | ||
64 | .gpio = 4, | ||
65 | .active_low = 1, | ||
66 | }, | ||
67 | { | ||
68 | .name = "power", | ||
69 | .gpio = 0, | ||
70 | .active_low = 1, | ||
71 | .default_trigger = "default-on", | ||
72 | }, | ||
73 | { | ||
74 | .name = "stop", | ||
75 | .gpio = 1, | ||
76 | .active_low = 1, | ||
77 | } | ||
78 | }, | ||
79 | }; | ||
80 | |||
81 | static struct board_info __initdata board_96338w = { | ||
82 | .name = "96338W", | ||
83 | .expected_cpu_id = 0x6338, | ||
84 | |||
85 | .has_enet0 = 1, | ||
86 | .enet0 = { | ||
87 | .force_speed_100 = 1, | ||
88 | .force_duplex_full = 1, | ||
89 | }, | ||
90 | |||
91 | .leds = { | ||
92 | { | ||
93 | .name = "adsl", | ||
94 | .gpio = 3, | ||
95 | .active_low = 1, | ||
96 | }, | ||
97 | { | ||
98 | .name = "ses", | ||
99 | .gpio = 5, | ||
100 | .active_low = 1, | ||
101 | }, | ||
102 | { | ||
103 | .name = "ppp-fail", | ||
104 | .gpio = 4, | ||
105 | .active_low = 1, | ||
106 | }, | ||
107 | { | ||
108 | .name = "power", | ||
109 | .gpio = 0, | ||
110 | .active_low = 1, | ||
111 | .default_trigger = "default-on", | ||
112 | }, | ||
113 | { | ||
114 | .name = "stop", | ||
115 | .gpio = 1, | ||
116 | .active_low = 1, | ||
117 | }, | ||
118 | }, | ||
119 | }; | ||
120 | #endif | ||
121 | |||
122 | /* | ||
123 | * known 6345 boards | ||
124 | */ | ||
125 | #ifdef CONFIG_BCM63XX_CPU_6345 | ||
126 | static struct board_info __initdata board_96345gw2 = { | ||
127 | .name = "96345GW2", | ||
128 | .expected_cpu_id = 0x6345, | ||
129 | }; | ||
130 | #endif | ||
131 | |||
132 | /* | ||
133 | * known 6348 boards | ||
134 | */ | ||
135 | #ifdef CONFIG_BCM63XX_CPU_6348 | ||
136 | static struct board_info __initdata board_96348r = { | ||
137 | .name = "96348R", | ||
138 | .expected_cpu_id = 0x6348, | ||
139 | |||
140 | .has_enet0 = 1, | ||
141 | .has_pci = 1, | ||
142 | |||
143 | .enet0 = { | ||
144 | .has_phy = 1, | ||
145 | .use_internal_phy = 1, | ||
146 | }, | ||
147 | |||
148 | .leds = { | ||
149 | { | ||
150 | .name = "adsl-fail", | ||
151 | .gpio = 2, | ||
152 | .active_low = 1, | ||
153 | }, | ||
154 | { | ||
155 | .name = "ppp", | ||
156 | .gpio = 3, | ||
157 | .active_low = 1, | ||
158 | }, | ||
159 | { | ||
160 | .name = "ppp-fail", | ||
161 | .gpio = 4, | ||
162 | .active_low = 1, | ||
163 | }, | ||
164 | { | ||
165 | .name = "power", | ||
166 | .gpio = 0, | ||
167 | .active_low = 1, | ||
168 | .default_trigger = "default-on", | ||
169 | |||
170 | }, | ||
171 | { | ||
172 | .name = "stop", | ||
173 | .gpio = 1, | ||
174 | .active_low = 1, | ||
175 | }, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static struct board_info __initdata board_96348gw_10 = { | ||
180 | .name = "96348GW-10", | ||
181 | .expected_cpu_id = 0x6348, | ||
182 | |||
183 | .has_enet0 = 1, | ||
184 | .has_enet1 = 1, | ||
185 | .has_pci = 1, | ||
186 | |||
187 | .enet0 = { | ||
188 | .has_phy = 1, | ||
189 | .use_internal_phy = 1, | ||
190 | }, | ||
191 | .enet1 = { | ||
192 | .force_speed_100 = 1, | ||
193 | .force_duplex_full = 1, | ||
194 | }, | ||
195 | |||
196 | .has_ohci0 = 1, | ||
197 | .has_pccard = 1, | ||
198 | .has_ehci0 = 1, | ||
199 | |||
200 | .has_dsp = 1, | ||
201 | .dsp = { | ||
202 | .gpio_rst = 6, | ||
203 | .gpio_int = 34, | ||
204 | .cs = 2, | ||
205 | .ext_irq = 2, | ||
206 | }, | ||
207 | |||
208 | .leds = { | ||
209 | { | ||
210 | .name = "adsl-fail", | ||
211 | .gpio = 2, | ||
212 | .active_low = 1, | ||
213 | }, | ||
214 | { | ||
215 | .name = "ppp", | ||
216 | .gpio = 3, | ||
217 | .active_low = 1, | ||
218 | }, | ||
219 | { | ||
220 | .name = "ppp-fail", | ||
221 | .gpio = 4, | ||
222 | .active_low = 1, | ||
223 | }, | ||
224 | { | ||
225 | .name = "power", | ||
226 | .gpio = 0, | ||
227 | .active_low = 1, | ||
228 | .default_trigger = "default-on", | ||
229 | }, | ||
230 | { | ||
231 | .name = "stop", | ||
232 | .gpio = 1, | ||
233 | .active_low = 1, | ||
234 | }, | ||
235 | }, | ||
236 | }; | ||
237 | |||
238 | static struct board_info __initdata board_96348gw_11 = { | ||
239 | .name = "96348GW-11", | ||
240 | .expected_cpu_id = 0x6348, | ||
241 | |||
242 | .has_enet0 = 1, | ||
243 | .has_enet1 = 1, | ||
244 | .has_pci = 1, | ||
245 | |||
246 | .enet0 = { | ||
247 | .has_phy = 1, | ||
248 | .use_internal_phy = 1, | ||
249 | }, | ||
250 | |||
251 | .enet1 = { | ||
252 | .force_speed_100 = 1, | ||
253 | .force_duplex_full = 1, | ||
254 | }, | ||
255 | |||
256 | |||
257 | .has_ohci0 = 1, | ||
258 | .has_pccard = 1, | ||
259 | .has_ehci0 = 1, | ||
260 | |||
261 | .leds = { | ||
262 | { | ||
263 | .name = "adsl-fail", | ||
264 | .gpio = 2, | ||
265 | .active_low = 1, | ||
266 | }, | ||
267 | { | ||
268 | .name = "ppp", | ||
269 | .gpio = 3, | ||
270 | .active_low = 1, | ||
271 | }, | ||
272 | { | ||
273 | .name = "ppp-fail", | ||
274 | .gpio = 4, | ||
275 | .active_low = 1, | ||
276 | }, | ||
277 | { | ||
278 | .name = "power", | ||
279 | .gpio = 0, | ||
280 | .active_low = 1, | ||
281 | .default_trigger = "default-on", | ||
282 | }, | ||
283 | { | ||
284 | .name = "stop", | ||
285 | .gpio = 1, | ||
286 | .active_low = 1, | ||
287 | }, | ||
288 | }, | ||
289 | }; | ||
290 | |||
291 | static struct board_info __initdata board_96348gw = { | ||
292 | .name = "96348GW", | ||
293 | .expected_cpu_id = 0x6348, | ||
294 | |||
295 | .has_enet0 = 1, | ||
296 | .has_enet1 = 1, | ||
297 | .has_pci = 1, | ||
298 | |||
299 | .enet0 = { | ||
300 | .has_phy = 1, | ||
301 | .use_internal_phy = 1, | ||
302 | }, | ||
303 | .enet1 = { | ||
304 | .force_speed_100 = 1, | ||
305 | .force_duplex_full = 1, | ||
306 | }, | ||
307 | |||
308 | .has_ohci0 = 1, | ||
309 | |||
310 | .has_dsp = 1, | ||
311 | .dsp = { | ||
312 | .gpio_rst = 6, | ||
313 | .gpio_int = 34, | ||
314 | .ext_irq = 2, | ||
315 | .cs = 2, | ||
316 | }, | ||
317 | |||
318 | .leds = { | ||
319 | { | ||
320 | .name = "adsl-fail", | ||
321 | .gpio = 2, | ||
322 | .active_low = 1, | ||
323 | }, | ||
324 | { | ||
325 | .name = "ppp", | ||
326 | .gpio = 3, | ||
327 | .active_low = 1, | ||
328 | }, | ||
329 | { | ||
330 | .name = "ppp-fail", | ||
331 | .gpio = 4, | ||
332 | .active_low = 1, | ||
333 | }, | ||
334 | { | ||
335 | .name = "power", | ||
336 | .gpio = 0, | ||
337 | .active_low = 1, | ||
338 | .default_trigger = "default-on", | ||
339 | }, | ||
340 | { | ||
341 | .name = "stop", | ||
342 | .gpio = 1, | ||
343 | .active_low = 1, | ||
344 | }, | ||
345 | }, | ||
346 | }; | ||
347 | |||
348 | static struct board_info __initdata board_FAST2404 = { | ||
349 | .name = "F@ST2404", | ||
350 | .expected_cpu_id = 0x6348, | ||
351 | |||
352 | .has_enet0 = 1, | ||
353 | .has_enet1 = 1, | ||
354 | .has_pci = 1, | ||
355 | |||
356 | .enet0 = { | ||
357 | .has_phy = 1, | ||
358 | .use_internal_phy = 1, | ||
359 | }, | ||
360 | |||
361 | .enet1 = { | ||
362 | .force_speed_100 = 1, | ||
363 | .force_duplex_full = 1, | ||
364 | }, | ||
365 | |||
366 | |||
367 | .has_ohci0 = 1, | ||
368 | .has_pccard = 1, | ||
369 | .has_ehci0 = 1, | ||
370 | }; | ||
371 | |||
372 | static struct board_info __initdata board_DV201AMR = { | ||
373 | .name = "DV201AMR", | ||
374 | .expected_cpu_id = 0x6348, | ||
375 | |||
376 | .has_pci = 1, | ||
377 | .has_ohci0 = 1, | ||
378 | |||
379 | .has_enet0 = 1, | ||
380 | .has_enet1 = 1, | ||
381 | .enet0 = { | ||
382 | .has_phy = 1, | ||
383 | .use_internal_phy = 1, | ||
384 | }, | ||
385 | .enet1 = { | ||
386 | .force_speed_100 = 1, | ||
387 | .force_duplex_full = 1, | ||
388 | }, | ||
389 | }; | ||
390 | |||
391 | static struct board_info __initdata board_96348gw_a = { | ||
392 | .name = "96348GW-A", | ||
393 | .expected_cpu_id = 0x6348, | ||
394 | |||
395 | .has_enet0 = 1, | ||
396 | .has_enet1 = 1, | ||
397 | .has_pci = 1, | ||
398 | |||
399 | .enet0 = { | ||
400 | .has_phy = 1, | ||
401 | .use_internal_phy = 1, | ||
402 | }, | ||
403 | .enet1 = { | ||
404 | .force_speed_100 = 1, | ||
405 | .force_duplex_full = 1, | ||
406 | }, | ||
407 | |||
408 | .has_ohci0 = 1, | ||
409 | }; | ||
410 | #endif | ||
411 | |||
412 | /* | ||
413 | * known 6358 boards | ||
414 | */ | ||
415 | #ifdef CONFIG_BCM63XX_CPU_6358 | ||
416 | static struct board_info __initdata board_96358vw = { | ||
417 | .name = "96358VW", | ||
418 | .expected_cpu_id = 0x6358, | ||
419 | |||
420 | .has_enet0 = 1, | ||
421 | .has_enet1 = 1, | ||
422 | .has_pci = 1, | ||
423 | |||
424 | .enet0 = { | ||
425 | .has_phy = 1, | ||
426 | .use_internal_phy = 1, | ||
427 | }, | ||
428 | |||
429 | .enet1 = { | ||
430 | .force_speed_100 = 1, | ||
431 | .force_duplex_full = 1, | ||
432 | }, | ||
433 | |||
434 | |||
435 | .has_ohci0 = 1, | ||
436 | .has_pccard = 1, | ||
437 | .has_ehci0 = 1, | ||
438 | |||
439 | .leds = { | ||
440 | { | ||
441 | .name = "adsl-fail", | ||
442 | .gpio = 15, | ||
443 | .active_low = 1, | ||
444 | }, | ||
445 | { | ||
446 | .name = "ppp", | ||
447 | .gpio = 22, | ||
448 | .active_low = 1, | ||
449 | }, | ||
450 | { | ||
451 | .name = "ppp-fail", | ||
452 | .gpio = 23, | ||
453 | .active_low = 1, | ||
454 | }, | ||
455 | { | ||
456 | .name = "power", | ||
457 | .gpio = 4, | ||
458 | .default_trigger = "default-on", | ||
459 | }, | ||
460 | { | ||
461 | .name = "stop", | ||
462 | .gpio = 5, | ||
463 | }, | ||
464 | }, | ||
465 | }; | ||
466 | |||
467 | static struct board_info __initdata board_96358vw2 = { | ||
468 | .name = "96358VW2", | ||
469 | .expected_cpu_id = 0x6358, | ||
470 | |||
471 | .has_enet0 = 1, | ||
472 | .has_enet1 = 1, | ||
473 | .has_pci = 1, | ||
474 | |||
475 | .enet0 = { | ||
476 | .has_phy = 1, | ||
477 | .use_internal_phy = 1, | ||
478 | }, | ||
479 | |||
480 | .enet1 = { | ||
481 | .force_speed_100 = 1, | ||
482 | .force_duplex_full = 1, | ||
483 | }, | ||
484 | |||
485 | |||
486 | .has_ohci0 = 1, | ||
487 | .has_pccard = 1, | ||
488 | .has_ehci0 = 1, | ||
489 | |||
490 | .leds = { | ||
491 | { | ||
492 | .name = "adsl", | ||
493 | .gpio = 22, | ||
494 | .active_low = 1, | ||
495 | }, | ||
496 | { | ||
497 | .name = "ppp-fail", | ||
498 | .gpio = 23, | ||
499 | }, | ||
500 | { | ||
501 | .name = "power", | ||
502 | .gpio = 5, | ||
503 | .active_low = 1, | ||
504 | .default_trigger = "default-on", | ||
505 | }, | ||
506 | { | ||
507 | .name = "stop", | ||
508 | .gpio = 4, | ||
509 | .active_low = 1, | ||
510 | }, | ||
511 | }, | ||
512 | }; | ||
513 | |||
514 | static struct board_info __initdata board_AGPFS0 = { | ||
515 | .name = "AGPF-S0", | ||
516 | .expected_cpu_id = 0x6358, | ||
517 | |||
518 | .has_enet0 = 1, | ||
519 | .has_enet1 = 1, | ||
520 | .has_pci = 1, | ||
521 | |||
522 | .enet0 = { | ||
523 | .has_phy = 1, | ||
524 | .use_internal_phy = 1, | ||
525 | }, | ||
526 | |||
527 | .enet1 = { | ||
528 | .force_speed_100 = 1, | ||
529 | .force_duplex_full = 1, | ||
530 | }, | ||
531 | |||
532 | .has_ohci0 = 1, | ||
533 | .has_ehci0 = 1, | ||
534 | }; | ||
535 | #endif | ||
536 | |||
537 | /* | ||
538 | * all boards | ||
539 | */ | ||
540 | static const struct board_info __initdata *bcm963xx_boards[] = { | ||
541 | #ifdef CONFIG_BCM63XX_CPU_6338 | ||
542 | &board_96338gw, | ||
543 | &board_96338w, | ||
544 | #endif | ||
545 | #ifdef CONFIG_BCM63XX_CPU_6345 | ||
546 | &board_96345gw2, | ||
547 | #endif | ||
548 | #ifdef CONFIG_BCM63XX_CPU_6348 | ||
549 | &board_96348r, | ||
550 | &board_96348gw, | ||
551 | &board_96348gw_10, | ||
552 | &board_96348gw_11, | ||
553 | &board_FAST2404, | ||
554 | &board_DV201AMR, | ||
555 | &board_96348gw_a, | ||
556 | #endif | ||
557 | |||
558 | #ifdef CONFIG_BCM63XX_CPU_6358 | ||
559 | &board_96358vw, | ||
560 | &board_96358vw2, | ||
561 | &board_AGPFS0, | ||
562 | #endif | ||
563 | }; | ||
564 | |||
565 | /* | ||
566 | * early init callback, read nvram data from flash and checksum it | ||
567 | */ | ||
568 | void __init board_prom_init(void) | ||
569 | { | ||
570 | unsigned int check_len, i; | ||
571 | u8 *boot_addr, *cfe, *p; | ||
572 | char cfe_version[32]; | ||
573 | u32 val; | ||
574 | |||
575 | /* read base address of boot chip select (0) | ||
576 | * 6345 does not have MPI but boots from standard | ||
577 | * MIPS Flash address */ | ||
578 | if (BCMCPU_IS_6345()) | ||
579 | val = 0x1fc00000; | ||
580 | else { | ||
581 | val = bcm_mpi_readl(MPI_CSBASE_REG(0)); | ||
582 | val &= MPI_CSBASE_BASE_MASK; | ||
583 | } | ||
584 | boot_addr = (u8 *)KSEG1ADDR(val); | ||
585 | |||
586 | /* dump cfe version */ | ||
587 | cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET; | ||
588 | if (!memcmp(cfe, "cfe-v", 5)) | ||
589 | snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u", | ||
590 | cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]); | ||
591 | else | ||
592 | strcpy(cfe_version, "unknown"); | ||
593 | printk(KERN_INFO PFX "CFE version: %s\n", cfe_version); | ||
594 | |||
595 | /* extract nvram data */ | ||
596 | memcpy(&nvram, boot_addr + BCM963XX_NVRAM_OFFSET, sizeof(nvram)); | ||
597 | |||
598 | /* check checksum before using data */ | ||
599 | if (nvram.version <= 4) | ||
600 | check_len = offsetof(struct bcm963xx_nvram, checksum_old); | ||
601 | else | ||
602 | check_len = sizeof(nvram); | ||
603 | val = 0; | ||
604 | p = (u8 *)&nvram; | ||
605 | while (check_len--) | ||
606 | val += *p; | ||
607 | if (val) { | ||
608 | printk(KERN_ERR PFX "invalid nvram checksum\n"); | ||
609 | return; | ||
610 | } | ||
611 | |||
612 | /* find board by name */ | ||
613 | for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) { | ||
614 | if (strncmp(nvram.name, bcm963xx_boards[i]->name, | ||
615 | sizeof(nvram.name))) | ||
616 | continue; | ||
617 | /* copy, board desc array is marked initdata */ | ||
618 | memcpy(&board, bcm963xx_boards[i], sizeof(board)); | ||
619 | break; | ||
620 | } | ||
621 | |||
622 | /* bail out if board is not found, will complain later */ | ||
623 | if (!board.name[0]) { | ||
624 | char name[17]; | ||
625 | memcpy(name, nvram.name, 16); | ||
626 | name[16] = 0; | ||
627 | printk(KERN_ERR PFX "unknown bcm963xx board: %s\n", | ||
628 | name); | ||
629 | return; | ||
630 | } | ||
631 | |||
632 | /* setup pin multiplexing depending on board enabled device, | ||
633 | * this has to be done this early since PCI init is done | ||
634 | * inside arch_initcall */ | ||
635 | val = 0; | ||
636 | |||
637 | #ifdef CONFIG_PCI | ||
638 | if (board.has_pci) { | ||
639 | bcm63xx_pci_enabled = 1; | ||
640 | if (BCMCPU_IS_6348()) | ||
641 | val |= GPIO_MODE_6348_G2_PCI; | ||
642 | } | ||
643 | #endif | ||
644 | |||
645 | if (board.has_pccard) { | ||
646 | if (BCMCPU_IS_6348()) | ||
647 | val |= GPIO_MODE_6348_G1_MII_PCCARD; | ||
648 | } | ||
649 | |||
650 | if (board.has_enet0 && !board.enet0.use_internal_phy) { | ||
651 | if (BCMCPU_IS_6348()) | ||
652 | val |= GPIO_MODE_6348_G3_EXT_MII | | ||
653 | GPIO_MODE_6348_G0_EXT_MII; | ||
654 | } | ||
655 | |||
656 | if (board.has_enet1 && !board.enet1.use_internal_phy) { | ||
657 | if (BCMCPU_IS_6348()) | ||
658 | val |= GPIO_MODE_6348_G3_EXT_MII | | ||
659 | GPIO_MODE_6348_G0_EXT_MII; | ||
660 | } | ||
661 | |||
662 | bcm_gpio_writel(val, GPIO_MODE_REG); | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * second stage init callback, good time to panic if we couldn't | ||
667 | * identify on which board we're running since early printk is working | ||
668 | */ | ||
669 | void __init board_setup(void) | ||
670 | { | ||
671 | if (!board.name[0]) | ||
672 | panic("unable to detect bcm963xx board"); | ||
673 | printk(KERN_INFO PFX "board name: %s\n", board.name); | ||
674 | |||
675 | /* make sure we're running on expected cpu */ | ||
676 | if (bcm63xx_get_cpu_id() != board.expected_cpu_id) | ||
677 | panic("unexpected CPU for bcm963xx board"); | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * return board name for /proc/cpuinfo | ||
682 | */ | ||
683 | const char *board_get_name(void) | ||
684 | { | ||
685 | return board.name; | ||
686 | } | ||
687 | |||
688 | /* | ||
689 | * register & return a new board mac address | ||
690 | */ | ||
691 | static int board_get_mac_address(u8 *mac) | ||
692 | { | ||
693 | u8 *p; | ||
694 | int count; | ||
695 | |||
696 | if (mac_addr_used >= nvram.mac_addr_count) { | ||
697 | printk(KERN_ERR PFX "not enough mac address\n"); | ||
698 | return -ENODEV; | ||
699 | } | ||
700 | |||
701 | memcpy(mac, nvram.mac_addr_base, ETH_ALEN); | ||
702 | p = mac + ETH_ALEN - 1; | ||
703 | count = mac_addr_used; | ||
704 | |||
705 | while (count--) { | ||
706 | do { | ||
707 | (*p)++; | ||
708 | if (*p != 0) | ||
709 | break; | ||
710 | p--; | ||
711 | } while (p != mac); | ||
712 | } | ||
713 | |||
714 | if (p == mac) { | ||
715 | printk(KERN_ERR PFX "unable to fetch mac address\n"); | ||
716 | return -ENODEV; | ||
717 | } | ||
718 | |||
719 | mac_addr_used++; | ||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static struct mtd_partition mtd_partitions[] = { | ||
724 | { | ||
725 | .name = "cfe", | ||
726 | .offset = 0x0, | ||
727 | .size = 0x40000, | ||
728 | } | ||
729 | }; | ||
730 | |||
731 | static struct physmap_flash_data flash_data = { | ||
732 | .width = 2, | ||
733 | .nr_parts = ARRAY_SIZE(mtd_partitions), | ||
734 | .parts = mtd_partitions, | ||
735 | }; | ||
736 | |||
737 | static struct resource mtd_resources[] = { | ||
738 | { | ||
739 | .start = 0, /* filled at runtime */ | ||
740 | .end = 0, /* filled at runtime */ | ||
741 | .flags = IORESOURCE_MEM, | ||
742 | } | ||
743 | }; | ||
744 | |||
745 | static struct platform_device mtd_dev = { | ||
746 | .name = "physmap-flash", | ||
747 | .resource = mtd_resources, | ||
748 | .num_resources = ARRAY_SIZE(mtd_resources), | ||
749 | .dev = { | ||
750 | .platform_data = &flash_data, | ||
751 | }, | ||
752 | }; | ||
753 | |||
754 | /* | ||
755 | * Register a sane SPROMv2 to make the on-board | ||
756 | * bcm4318 WLAN work | ||
757 | */ | ||
758 | #ifdef CONFIG_SSB_PCIHOST | ||
759 | static struct ssb_sprom bcm63xx_sprom = { | ||
760 | .revision = 0x02, | ||
761 | .board_rev = 0x17, | ||
762 | .country_code = 0x0, | ||
763 | .ant_available_bg = 0x3, | ||
764 | .pa0b0 = 0x15ae, | ||
765 | .pa0b1 = 0xfa85, | ||
766 | .pa0b2 = 0xfe8d, | ||
767 | .pa1b0 = 0xffff, | ||
768 | .pa1b1 = 0xffff, | ||
769 | .pa1b2 = 0xffff, | ||
770 | .gpio0 = 0xff, | ||
771 | .gpio1 = 0xff, | ||
772 | .gpio2 = 0xff, | ||
773 | .gpio3 = 0xff, | ||
774 | .maxpwr_bg = 0x004c, | ||
775 | .itssi_bg = 0x00, | ||
776 | .boardflags_lo = 0x2848, | ||
777 | .boardflags_hi = 0x0000, | ||
778 | }; | ||
779 | #endif | ||
780 | |||
781 | static struct gpio_led_platform_data bcm63xx_led_data; | ||
782 | |||
783 | static struct platform_device bcm63xx_gpio_leds = { | ||
784 | .name = "leds-gpio", | ||
785 | .id = 0, | ||
786 | .dev.platform_data = &bcm63xx_led_data, | ||
787 | }; | ||
788 | |||
789 | /* | ||
790 | * third stage init callback, register all board devices. | ||
791 | */ | ||
792 | int __init board_register_devices(void) | ||
793 | { | ||
794 | u32 val; | ||
795 | |||
796 | if (board.has_enet0 && | ||
797 | !board_get_mac_address(board.enet0.mac_addr)) | ||
798 | bcm63xx_enet_register(0, &board.enet0); | ||
799 | |||
800 | if (board.has_enet1 && | ||
801 | !board_get_mac_address(board.enet1.mac_addr)) | ||
802 | bcm63xx_enet_register(1, &board.enet1); | ||
803 | |||
804 | if (board.has_dsp) | ||
805 | bcm63xx_dsp_register(&board.dsp); | ||
806 | |||
807 | /* Generate MAC address for WLAN and | ||
808 | * register our SPROM */ | ||
809 | #ifdef CONFIG_SSB_PCIHOST | ||
810 | if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { | ||
811 | memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); | ||
812 | memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); | ||
813 | if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0) | ||
814 | printk(KERN_ERR "failed to register fallback SPROM\n"); | ||
815 | } | ||
816 | #endif | ||
817 | |||
818 | /* read base address of boot chip select (0) */ | ||
819 | if (BCMCPU_IS_6345()) | ||
820 | val = 0x1fc00000; | ||
821 | else { | ||
822 | val = bcm_mpi_readl(MPI_CSBASE_REG(0)); | ||
823 | val &= MPI_CSBASE_BASE_MASK; | ||
824 | } | ||
825 | mtd_resources[0].start = val; | ||
826 | mtd_resources[0].end = 0x1FFFFFFF; | ||
827 | |||
828 | platform_device_register(&mtd_dev); | ||
829 | |||
830 | bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds); | ||
831 | bcm63xx_led_data.leds = board.leds; | ||
832 | |||
833 | platform_device_register(&bcm63xx_gpio_leds); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c new file mode 100644 index 000000000000..2c68ee9ccee2 --- /dev/null +++ b/arch/mips/bcm63xx/clk.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/mutex.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <bcm63xx_cpu.h> | ||
14 | #include <bcm63xx_io.h> | ||
15 | #include <bcm63xx_regs.h> | ||
16 | #include <bcm63xx_clk.h> | ||
17 | |||
18 | static DEFINE_MUTEX(clocks_mutex); | ||
19 | |||
20 | |||
21 | static void clk_enable_unlocked(struct clk *clk) | ||
22 | { | ||
23 | if (clk->set && (clk->usage++) == 0) | ||
24 | clk->set(clk, 1); | ||
25 | } | ||
26 | |||
27 | static void clk_disable_unlocked(struct clk *clk) | ||
28 | { | ||
29 | if (clk->set && (--clk->usage) == 0) | ||
30 | clk->set(clk, 0); | ||
31 | } | ||
32 | |||
33 | static void bcm_hwclock_set(u32 mask, int enable) | ||
34 | { | ||
35 | u32 reg; | ||
36 | |||
37 | reg = bcm_perf_readl(PERF_CKCTL_REG); | ||
38 | if (enable) | ||
39 | reg |= mask; | ||
40 | else | ||
41 | reg &= ~mask; | ||
42 | bcm_perf_writel(reg, PERF_CKCTL_REG); | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Ethernet MAC "misc" clock: dma clocks and main clock on 6348 | ||
47 | */ | ||
48 | static void enet_misc_set(struct clk *clk, int enable) | ||
49 | { | ||
50 | u32 mask; | ||
51 | |||
52 | if (BCMCPU_IS_6338()) | ||
53 | mask = CKCTL_6338_ENET_EN; | ||
54 | else if (BCMCPU_IS_6345()) | ||
55 | mask = CKCTL_6345_ENET_EN; | ||
56 | else if (BCMCPU_IS_6348()) | ||
57 | mask = CKCTL_6348_ENET_EN; | ||
58 | else | ||
59 | /* BCMCPU_IS_6358 */ | ||
60 | mask = CKCTL_6358_EMUSB_EN; | ||
61 | bcm_hwclock_set(mask, enable); | ||
62 | } | ||
63 | |||
64 | static struct clk clk_enet_misc = { | ||
65 | .set = enet_misc_set, | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * Ethernet MAC clocks: only revelant on 6358, silently enable misc | ||
70 | * clocks | ||
71 | */ | ||
72 | static void enetx_set(struct clk *clk, int enable) | ||
73 | { | ||
74 | if (enable) | ||
75 | clk_enable_unlocked(&clk_enet_misc); | ||
76 | else | ||
77 | clk_disable_unlocked(&clk_enet_misc); | ||
78 | |||
79 | if (BCMCPU_IS_6358()) { | ||
80 | u32 mask; | ||
81 | |||
82 | if (clk->id == 0) | ||
83 | mask = CKCTL_6358_ENET0_EN; | ||
84 | else | ||
85 | mask = CKCTL_6358_ENET1_EN; | ||
86 | bcm_hwclock_set(mask, enable); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static struct clk clk_enet0 = { | ||
91 | .id = 0, | ||
92 | .set = enetx_set, | ||
93 | }; | ||
94 | |||
95 | static struct clk clk_enet1 = { | ||
96 | .id = 1, | ||
97 | .set = enetx_set, | ||
98 | }; | ||
99 | |||
100 | /* | ||
101 | * Ethernet PHY clock | ||
102 | */ | ||
103 | static void ephy_set(struct clk *clk, int enable) | ||
104 | { | ||
105 | if (!BCMCPU_IS_6358()) | ||
106 | return; | ||
107 | bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); | ||
108 | } | ||
109 | |||
110 | |||
111 | static struct clk clk_ephy = { | ||
112 | .set = ephy_set, | ||
113 | }; | ||
114 | |||
115 | /* | ||
116 | * PCM clock | ||
117 | */ | ||
118 | static void pcm_set(struct clk *clk, int enable) | ||
119 | { | ||
120 | if (!BCMCPU_IS_6358()) | ||
121 | return; | ||
122 | bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); | ||
123 | } | ||
124 | |||
125 | static struct clk clk_pcm = { | ||
126 | .set = pcm_set, | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * USB host clock | ||
131 | */ | ||
132 | static void usbh_set(struct clk *clk, int enable) | ||
133 | { | ||
134 | if (!BCMCPU_IS_6348()) | ||
135 | return; | ||
136 | bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); | ||
137 | } | ||
138 | |||
139 | static struct clk clk_usbh = { | ||
140 | .set = usbh_set, | ||
141 | }; | ||
142 | |||
143 | /* | ||
144 | * SPI clock | ||
145 | */ | ||
146 | static void spi_set(struct clk *clk, int enable) | ||
147 | { | ||
148 | u32 mask; | ||
149 | |||
150 | if (BCMCPU_IS_6338()) | ||
151 | mask = CKCTL_6338_SPI_EN; | ||
152 | else if (BCMCPU_IS_6348()) | ||
153 | mask = CKCTL_6348_SPI_EN; | ||
154 | else | ||
155 | /* BCMCPU_IS_6358 */ | ||
156 | mask = CKCTL_6358_SPI_EN; | ||
157 | bcm_hwclock_set(mask, enable); | ||
158 | } | ||
159 | |||
160 | static struct clk clk_spi = { | ||
161 | .set = spi_set, | ||
162 | }; | ||
163 | |||
164 | /* | ||
165 | * Internal peripheral clock | ||
166 | */ | ||
167 | static struct clk clk_periph = { | ||
168 | .rate = (50 * 1000 * 1000), | ||
169 | }; | ||
170 | |||
171 | |||
172 | /* | ||
173 | * Linux clock API implementation | ||
174 | */ | ||
175 | int clk_enable(struct clk *clk) | ||
176 | { | ||
177 | mutex_lock(&clocks_mutex); | ||
178 | clk_enable_unlocked(clk); | ||
179 | mutex_unlock(&clocks_mutex); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | EXPORT_SYMBOL(clk_enable); | ||
184 | |||
185 | void clk_disable(struct clk *clk) | ||
186 | { | ||
187 | mutex_lock(&clocks_mutex); | ||
188 | clk_disable_unlocked(clk); | ||
189 | mutex_unlock(&clocks_mutex); | ||
190 | } | ||
191 | |||
192 | EXPORT_SYMBOL(clk_disable); | ||
193 | |||
194 | unsigned long clk_get_rate(struct clk *clk) | ||
195 | { | ||
196 | return clk->rate; | ||
197 | } | ||
198 | |||
199 | EXPORT_SYMBOL(clk_get_rate); | ||
200 | |||
201 | struct clk *clk_get(struct device *dev, const char *id) | ||
202 | { | ||
203 | if (!strcmp(id, "enet0")) | ||
204 | return &clk_enet0; | ||
205 | if (!strcmp(id, "enet1")) | ||
206 | return &clk_enet1; | ||
207 | if (!strcmp(id, "ephy")) | ||
208 | return &clk_ephy; | ||
209 | if (!strcmp(id, "usbh")) | ||
210 | return &clk_usbh; | ||
211 | if (!strcmp(id, "spi")) | ||
212 | return &clk_spi; | ||
213 | if (!strcmp(id, "periph")) | ||
214 | return &clk_periph; | ||
215 | if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) | ||
216 | return &clk_pcm; | ||
217 | return ERR_PTR(-ENOENT); | ||
218 | } | ||
219 | |||
220 | EXPORT_SYMBOL(clk_get); | ||
221 | |||
222 | void clk_put(struct clk *clk) | ||
223 | { | ||
224 | } | ||
225 | |||
226 | EXPORT_SYMBOL(clk_put); | ||
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c new file mode 100644 index 000000000000..6dc43f0483e8 --- /dev/null +++ b/arch/mips/bcm63xx/cpu.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org> | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/cpu.h> | ||
13 | #include <bcm63xx_cpu.h> | ||
14 | #include <bcm63xx_regs.h> | ||
15 | #include <bcm63xx_io.h> | ||
16 | #include <bcm63xx_irq.h> | ||
17 | |||
18 | const unsigned long *bcm63xx_regs_base; | ||
19 | EXPORT_SYMBOL(bcm63xx_regs_base); | ||
20 | |||
21 | const int *bcm63xx_irqs; | ||
22 | EXPORT_SYMBOL(bcm63xx_irqs); | ||
23 | |||
24 | static u16 bcm63xx_cpu_id; | ||
25 | static u16 bcm63xx_cpu_rev; | ||
26 | static unsigned int bcm63xx_cpu_freq; | ||
27 | static unsigned int bcm63xx_memory_size; | ||
28 | |||
29 | /* | ||
30 | * 6338 register sets and irqs | ||
31 | */ | ||
32 | static const unsigned long bcm96338_regs_base[] = { | ||
33 | [RSET_DSL_LMEM] = BCM_6338_DSL_LMEM_BASE, | ||
34 | [RSET_PERF] = BCM_6338_PERF_BASE, | ||
35 | [RSET_TIMER] = BCM_6338_TIMER_BASE, | ||
36 | [RSET_WDT] = BCM_6338_WDT_BASE, | ||
37 | [RSET_UART0] = BCM_6338_UART0_BASE, | ||
38 | [RSET_GPIO] = BCM_6338_GPIO_BASE, | ||
39 | [RSET_SPI] = BCM_6338_SPI_BASE, | ||
40 | [RSET_OHCI0] = BCM_6338_OHCI0_BASE, | ||
41 | [RSET_OHCI_PRIV] = BCM_6338_OHCI_PRIV_BASE, | ||
42 | [RSET_USBH_PRIV] = BCM_6338_USBH_PRIV_BASE, | ||
43 | [RSET_UDC0] = BCM_6338_UDC0_BASE, | ||
44 | [RSET_MPI] = BCM_6338_MPI_BASE, | ||
45 | [RSET_PCMCIA] = BCM_6338_PCMCIA_BASE, | ||
46 | [RSET_SDRAM] = BCM_6338_SDRAM_BASE, | ||
47 | [RSET_DSL] = BCM_6338_DSL_BASE, | ||
48 | [RSET_ENET0] = BCM_6338_ENET0_BASE, | ||
49 | [RSET_ENET1] = BCM_6338_ENET1_BASE, | ||
50 | [RSET_ENETDMA] = BCM_6338_ENETDMA_BASE, | ||
51 | [RSET_MEMC] = BCM_6338_MEMC_BASE, | ||
52 | [RSET_DDR] = BCM_6338_DDR_BASE, | ||
53 | }; | ||
54 | |||
55 | static const int bcm96338_irqs[] = { | ||
56 | [IRQ_TIMER] = BCM_6338_TIMER_IRQ, | ||
57 | [IRQ_UART0] = BCM_6338_UART0_IRQ, | ||
58 | [IRQ_DSL] = BCM_6338_DSL_IRQ, | ||
59 | [IRQ_ENET0] = BCM_6338_ENET0_IRQ, | ||
60 | [IRQ_ENET_PHY] = BCM_6338_ENET_PHY_IRQ, | ||
61 | [IRQ_ENET0_RXDMA] = BCM_6338_ENET0_RXDMA_IRQ, | ||
62 | [IRQ_ENET0_TXDMA] = BCM_6338_ENET0_TXDMA_IRQ, | ||
63 | }; | ||
64 | |||
65 | /* | ||
66 | * 6345 register sets and irqs | ||
67 | */ | ||
68 | static const unsigned long bcm96345_regs_base[] = { | ||
69 | [RSET_DSL_LMEM] = BCM_6345_DSL_LMEM_BASE, | ||
70 | [RSET_PERF] = BCM_6345_PERF_BASE, | ||
71 | [RSET_TIMER] = BCM_6345_TIMER_BASE, | ||
72 | [RSET_WDT] = BCM_6345_WDT_BASE, | ||
73 | [RSET_UART0] = BCM_6345_UART0_BASE, | ||
74 | [RSET_GPIO] = BCM_6345_GPIO_BASE, | ||
75 | [RSET_SPI] = BCM_6345_SPI_BASE, | ||
76 | [RSET_UDC0] = BCM_6345_UDC0_BASE, | ||
77 | [RSET_OHCI0] = BCM_6345_OHCI0_BASE, | ||
78 | [RSET_OHCI_PRIV] = BCM_6345_OHCI_PRIV_BASE, | ||
79 | [RSET_USBH_PRIV] = BCM_6345_USBH_PRIV_BASE, | ||
80 | [RSET_MPI] = BCM_6345_MPI_BASE, | ||
81 | [RSET_PCMCIA] = BCM_6345_PCMCIA_BASE, | ||
82 | [RSET_DSL] = BCM_6345_DSL_BASE, | ||
83 | [RSET_ENET0] = BCM_6345_ENET0_BASE, | ||
84 | [RSET_ENET1] = BCM_6345_ENET1_BASE, | ||
85 | [RSET_ENETDMA] = BCM_6345_ENETDMA_BASE, | ||
86 | [RSET_EHCI0] = BCM_6345_EHCI0_BASE, | ||
87 | [RSET_SDRAM] = BCM_6345_SDRAM_BASE, | ||
88 | [RSET_MEMC] = BCM_6345_MEMC_BASE, | ||
89 | [RSET_DDR] = BCM_6345_DDR_BASE, | ||
90 | }; | ||
91 | |||
92 | static const int bcm96345_irqs[] = { | ||
93 | [IRQ_TIMER] = BCM_6345_TIMER_IRQ, | ||
94 | [IRQ_UART0] = BCM_6345_UART0_IRQ, | ||
95 | [IRQ_DSL] = BCM_6345_DSL_IRQ, | ||
96 | [IRQ_ENET0] = BCM_6345_ENET0_IRQ, | ||
97 | [IRQ_ENET_PHY] = BCM_6345_ENET_PHY_IRQ, | ||
98 | [IRQ_ENET0_RXDMA] = BCM_6345_ENET0_RXDMA_IRQ, | ||
99 | [IRQ_ENET0_TXDMA] = BCM_6345_ENET0_TXDMA_IRQ, | ||
100 | }; | ||
101 | |||
102 | /* | ||
103 | * 6348 register sets and irqs | ||
104 | */ | ||
105 | static const unsigned long bcm96348_regs_base[] = { | ||
106 | [RSET_DSL_LMEM] = BCM_6348_DSL_LMEM_BASE, | ||
107 | [RSET_PERF] = BCM_6348_PERF_BASE, | ||
108 | [RSET_TIMER] = BCM_6348_TIMER_BASE, | ||
109 | [RSET_WDT] = BCM_6348_WDT_BASE, | ||
110 | [RSET_UART0] = BCM_6348_UART0_BASE, | ||
111 | [RSET_GPIO] = BCM_6348_GPIO_BASE, | ||
112 | [RSET_SPI] = BCM_6348_SPI_BASE, | ||
113 | [RSET_OHCI0] = BCM_6348_OHCI0_BASE, | ||
114 | [RSET_OHCI_PRIV] = BCM_6348_OHCI_PRIV_BASE, | ||
115 | [RSET_USBH_PRIV] = BCM_6348_USBH_PRIV_BASE, | ||
116 | [RSET_MPI] = BCM_6348_MPI_BASE, | ||
117 | [RSET_PCMCIA] = BCM_6348_PCMCIA_BASE, | ||
118 | [RSET_SDRAM] = BCM_6348_SDRAM_BASE, | ||
119 | [RSET_DSL] = BCM_6348_DSL_BASE, | ||
120 | [RSET_ENET0] = BCM_6348_ENET0_BASE, | ||
121 | [RSET_ENET1] = BCM_6348_ENET1_BASE, | ||
122 | [RSET_ENETDMA] = BCM_6348_ENETDMA_BASE, | ||
123 | [RSET_MEMC] = BCM_6348_MEMC_BASE, | ||
124 | [RSET_DDR] = BCM_6348_DDR_BASE, | ||
125 | }; | ||
126 | |||
127 | static const int bcm96348_irqs[] = { | ||
128 | [IRQ_TIMER] = BCM_6348_TIMER_IRQ, | ||
129 | [IRQ_UART0] = BCM_6348_UART0_IRQ, | ||
130 | [IRQ_DSL] = BCM_6348_DSL_IRQ, | ||
131 | [IRQ_ENET0] = BCM_6348_ENET0_IRQ, | ||
132 | [IRQ_ENET1] = BCM_6348_ENET1_IRQ, | ||
133 | [IRQ_ENET_PHY] = BCM_6348_ENET_PHY_IRQ, | ||
134 | [IRQ_OHCI0] = BCM_6348_OHCI0_IRQ, | ||
135 | [IRQ_PCMCIA] = BCM_6348_PCMCIA_IRQ, | ||
136 | [IRQ_ENET0_RXDMA] = BCM_6348_ENET0_RXDMA_IRQ, | ||
137 | [IRQ_ENET0_TXDMA] = BCM_6348_ENET0_TXDMA_IRQ, | ||
138 | [IRQ_ENET1_RXDMA] = BCM_6348_ENET1_RXDMA_IRQ, | ||
139 | [IRQ_ENET1_TXDMA] = BCM_6348_ENET1_TXDMA_IRQ, | ||
140 | [IRQ_PCI] = BCM_6348_PCI_IRQ, | ||
141 | }; | ||
142 | |||
143 | /* | ||
144 | * 6358 register sets and irqs | ||
145 | */ | ||
146 | static const unsigned long bcm96358_regs_base[] = { | ||
147 | [RSET_DSL_LMEM] = BCM_6358_DSL_LMEM_BASE, | ||
148 | [RSET_PERF] = BCM_6358_PERF_BASE, | ||
149 | [RSET_TIMER] = BCM_6358_TIMER_BASE, | ||
150 | [RSET_WDT] = BCM_6358_WDT_BASE, | ||
151 | [RSET_UART0] = BCM_6358_UART0_BASE, | ||
152 | [RSET_GPIO] = BCM_6358_GPIO_BASE, | ||
153 | [RSET_SPI] = BCM_6358_SPI_BASE, | ||
154 | [RSET_OHCI0] = BCM_6358_OHCI0_BASE, | ||
155 | [RSET_EHCI0] = BCM_6358_EHCI0_BASE, | ||
156 | [RSET_OHCI_PRIV] = BCM_6358_OHCI_PRIV_BASE, | ||
157 | [RSET_USBH_PRIV] = BCM_6358_USBH_PRIV_BASE, | ||
158 | [RSET_MPI] = BCM_6358_MPI_BASE, | ||
159 | [RSET_PCMCIA] = BCM_6358_PCMCIA_BASE, | ||
160 | [RSET_SDRAM] = BCM_6358_SDRAM_BASE, | ||
161 | [RSET_DSL] = BCM_6358_DSL_BASE, | ||
162 | [RSET_ENET0] = BCM_6358_ENET0_BASE, | ||
163 | [RSET_ENET1] = BCM_6358_ENET1_BASE, | ||
164 | [RSET_ENETDMA] = BCM_6358_ENETDMA_BASE, | ||
165 | [RSET_MEMC] = BCM_6358_MEMC_BASE, | ||
166 | [RSET_DDR] = BCM_6358_DDR_BASE, | ||
167 | }; | ||
168 | |||
169 | static const int bcm96358_irqs[] = { | ||
170 | [IRQ_TIMER] = BCM_6358_TIMER_IRQ, | ||
171 | [IRQ_UART0] = BCM_6358_UART0_IRQ, | ||
172 | [IRQ_DSL] = BCM_6358_DSL_IRQ, | ||
173 | [IRQ_ENET0] = BCM_6358_ENET0_IRQ, | ||
174 | [IRQ_ENET1] = BCM_6358_ENET1_IRQ, | ||
175 | [IRQ_ENET_PHY] = BCM_6358_ENET_PHY_IRQ, | ||
176 | [IRQ_OHCI0] = BCM_6358_OHCI0_IRQ, | ||
177 | [IRQ_EHCI0] = BCM_6358_EHCI0_IRQ, | ||
178 | [IRQ_PCMCIA] = BCM_6358_PCMCIA_IRQ, | ||
179 | [IRQ_ENET0_RXDMA] = BCM_6358_ENET0_RXDMA_IRQ, | ||
180 | [IRQ_ENET0_TXDMA] = BCM_6358_ENET0_TXDMA_IRQ, | ||
181 | [IRQ_ENET1_RXDMA] = BCM_6358_ENET1_RXDMA_IRQ, | ||
182 | [IRQ_ENET1_TXDMA] = BCM_6358_ENET1_TXDMA_IRQ, | ||
183 | [IRQ_PCI] = BCM_6358_PCI_IRQ, | ||
184 | }; | ||
185 | |||
186 | u16 __bcm63xx_get_cpu_id(void) | ||
187 | { | ||
188 | return bcm63xx_cpu_id; | ||
189 | } | ||
190 | |||
191 | EXPORT_SYMBOL(__bcm63xx_get_cpu_id); | ||
192 | |||
193 | u16 bcm63xx_get_cpu_rev(void) | ||
194 | { | ||
195 | return bcm63xx_cpu_rev; | ||
196 | } | ||
197 | |||
198 | EXPORT_SYMBOL(bcm63xx_get_cpu_rev); | ||
199 | |||
200 | unsigned int bcm63xx_get_cpu_freq(void) | ||
201 | { | ||
202 | return bcm63xx_cpu_freq; | ||
203 | } | ||
204 | |||
205 | unsigned int bcm63xx_get_memory_size(void) | ||
206 | { | ||
207 | return bcm63xx_memory_size; | ||
208 | } | ||
209 | |||
210 | static unsigned int detect_cpu_clock(void) | ||
211 | { | ||
212 | unsigned int tmp, n1 = 0, n2 = 0, m1 = 0; | ||
213 | |||
214 | /* BCM6338 has a fixed 240 Mhz frequency */ | ||
215 | if (BCMCPU_IS_6338()) | ||
216 | return 240000000; | ||
217 | |||
218 | /* BCM6345 has a fixed 140Mhz frequency */ | ||
219 | if (BCMCPU_IS_6345()) | ||
220 | return 140000000; | ||
221 | |||
222 | /* | ||
223 | * frequency depends on PLL configuration: | ||
224 | */ | ||
225 | if (BCMCPU_IS_6348()) { | ||
226 | /* 16MHz * (N1 + 1) * (N2 + 2) / (M1_CPU + 1) */ | ||
227 | tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG); | ||
228 | n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT; | ||
229 | n2 = (tmp & MIPSPLLCTL_N2_MASK) >> MIPSPLLCTL_N2_SHIFT; | ||
230 | m1 = (tmp & MIPSPLLCTL_M1CPU_MASK) >> MIPSPLLCTL_M1CPU_SHIFT; | ||
231 | n1 += 1; | ||
232 | n2 += 2; | ||
233 | m1 += 1; | ||
234 | } | ||
235 | |||
236 | if (BCMCPU_IS_6358()) { | ||
237 | /* 16MHz * N1 * N2 / M1_CPU */ | ||
238 | tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_REG); | ||
239 | n1 = (tmp & DMIPSPLLCFG_N1_MASK) >> DMIPSPLLCFG_N1_SHIFT; | ||
240 | n2 = (tmp & DMIPSPLLCFG_N2_MASK) >> DMIPSPLLCFG_N2_SHIFT; | ||
241 | m1 = (tmp & DMIPSPLLCFG_M1_MASK) >> DMIPSPLLCFG_M1_SHIFT; | ||
242 | } | ||
243 | |||
244 | return (16 * 1000000 * n1 * n2) / m1; | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * attempt to detect the amount of memory installed | ||
249 | */ | ||
250 | static unsigned int detect_memory_size(void) | ||
251 | { | ||
252 | unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0; | ||
253 | u32 val; | ||
254 | |||
255 | if (BCMCPU_IS_6345()) | ||
256 | return (8 * 1024 * 1024); | ||
257 | |||
258 | if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) { | ||
259 | val = bcm_sdram_readl(SDRAM_CFG_REG); | ||
260 | rows = (val & SDRAM_CFG_ROW_MASK) >> SDRAM_CFG_ROW_SHIFT; | ||
261 | cols = (val & SDRAM_CFG_COL_MASK) >> SDRAM_CFG_COL_SHIFT; | ||
262 | is_32bits = (val & SDRAM_CFG_32B_MASK) ? 1 : 0; | ||
263 | banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1; | ||
264 | } | ||
265 | |||
266 | if (BCMCPU_IS_6358()) { | ||
267 | val = bcm_memc_readl(MEMC_CFG_REG); | ||
268 | rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT; | ||
269 | cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT; | ||
270 | is_32bits = (val & MEMC_CFG_32B_MASK) ? 0 : 1; | ||
271 | banks = 2; | ||
272 | } | ||
273 | |||
274 | /* 0 => 11 address bits ... 2 => 13 address bits */ | ||
275 | rows += 11; | ||
276 | |||
277 | /* 0 => 8 address bits ... 2 => 10 address bits */ | ||
278 | cols += 8; | ||
279 | |||
280 | return 1 << (cols + rows + (is_32bits + 1) + banks); | ||
281 | } | ||
282 | |||
283 | void __init bcm63xx_cpu_init(void) | ||
284 | { | ||
285 | unsigned int tmp, expected_cpu_id; | ||
286 | struct cpuinfo_mips *c = ¤t_cpu_data; | ||
287 | |||
288 | /* soc registers location depends on cpu type */ | ||
289 | expected_cpu_id = 0; | ||
290 | |||
291 | switch (c->cputype) { | ||
292 | /* | ||
293 | * BCM6338 as the same PrId as BCM3302 see arch/mips/kernel/cpu-probe.c | ||
294 | */ | ||
295 | case CPU_BCM3302: | ||
296 | expected_cpu_id = BCM6338_CPU_ID; | ||
297 | bcm63xx_regs_base = bcm96338_regs_base; | ||
298 | bcm63xx_irqs = bcm96338_irqs; | ||
299 | break; | ||
300 | case CPU_BCM6345: | ||
301 | expected_cpu_id = BCM6345_CPU_ID; | ||
302 | bcm63xx_regs_base = bcm96345_regs_base; | ||
303 | bcm63xx_irqs = bcm96345_irqs; | ||
304 | break; | ||
305 | case CPU_BCM6348: | ||
306 | expected_cpu_id = BCM6348_CPU_ID; | ||
307 | bcm63xx_regs_base = bcm96348_regs_base; | ||
308 | bcm63xx_irqs = bcm96348_irqs; | ||
309 | break; | ||
310 | case CPU_BCM6358: | ||
311 | expected_cpu_id = BCM6358_CPU_ID; | ||
312 | bcm63xx_regs_base = bcm96358_regs_base; | ||
313 | bcm63xx_irqs = bcm96358_irqs; | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * really early to panic, but delaying panic would not help since we | ||
319 | * will never get any working console | ||
320 | */ | ||
321 | if (!expected_cpu_id) | ||
322 | panic("unsupported Broadcom CPU"); | ||
323 | |||
324 | /* | ||
325 | * bcm63xx_regs_base is set, we can access soc registers | ||
326 | */ | ||
327 | |||
328 | /* double check CPU type */ | ||
329 | tmp = bcm_perf_readl(PERF_REV_REG); | ||
330 | bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT; | ||
331 | bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT; | ||
332 | |||
333 | if (bcm63xx_cpu_id != expected_cpu_id) | ||
334 | panic("bcm63xx CPU id mismatch"); | ||
335 | |||
336 | bcm63xx_cpu_freq = detect_cpu_clock(); | ||
337 | bcm63xx_memory_size = detect_memory_size(); | ||
338 | |||
339 | printk(KERN_INFO "Detected Broadcom 0x%04x CPU revision %02x\n", | ||
340 | bcm63xx_cpu_id, bcm63xx_cpu_rev); | ||
341 | printk(KERN_INFO "CPU frequency is %u MHz\n", | ||
342 | bcm63xx_cpu_freq / 1000000); | ||
343 | printk(KERN_INFO "%uMB of RAM installed\n", | ||
344 | bcm63xx_memory_size >> 20); | ||
345 | } | ||
diff --git a/arch/mips/bcm63xx/cs.c b/arch/mips/bcm63xx/cs.c new file mode 100644 index 000000000000..50d8190bbf7b --- /dev/null +++ b/arch/mips/bcm63xx/cs.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/log2.h> | ||
13 | #include <bcm63xx_cpu.h> | ||
14 | #include <bcm63xx_io.h> | ||
15 | #include <bcm63xx_regs.h> | ||
16 | #include <bcm63xx_cs.h> | ||
17 | |||
18 | static DEFINE_SPINLOCK(bcm63xx_cs_lock); | ||
19 | |||
20 | /* | ||
21 | * check if given chip select exists | ||
22 | */ | ||
23 | static int is_valid_cs(unsigned int cs) | ||
24 | { | ||
25 | if (cs > 6) | ||
26 | return 0; | ||
27 | return 1; | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * Configure chipselect base address and size (bytes). | ||
32 | * Size must be a power of two between 8k and 256M. | ||
33 | */ | ||
34 | int bcm63xx_set_cs_base(unsigned int cs, u32 base, unsigned int size) | ||
35 | { | ||
36 | unsigned long flags; | ||
37 | u32 val; | ||
38 | |||
39 | if (!is_valid_cs(cs)) | ||
40 | return -EINVAL; | ||
41 | |||
42 | /* sanity check on size */ | ||
43 | if (size != roundup_pow_of_two(size)) | ||
44 | return -EINVAL; | ||
45 | |||
46 | if (size < 8 * 1024 || size > 256 * 1024 * 1024) | ||
47 | return -EINVAL; | ||
48 | |||
49 | val = (base & MPI_CSBASE_BASE_MASK); | ||
50 | /* 8k => 0 - 256M => 15 */ | ||
51 | val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT; | ||
52 | |||
53 | spin_lock_irqsave(&bcm63xx_cs_lock, flags); | ||
54 | bcm_mpi_writel(val, MPI_CSBASE_REG(cs)); | ||
55 | spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | EXPORT_SYMBOL(bcm63xx_set_cs_base); | ||
61 | |||
62 | /* | ||
63 | * configure chipselect timing (ns) | ||
64 | */ | ||
65 | int bcm63xx_set_cs_timing(unsigned int cs, unsigned int wait, | ||
66 | unsigned int setup, unsigned int hold) | ||
67 | { | ||
68 | unsigned long flags; | ||
69 | u32 val; | ||
70 | |||
71 | if (!is_valid_cs(cs)) | ||
72 | return -EINVAL; | ||
73 | |||
74 | spin_lock_irqsave(&bcm63xx_cs_lock, flags); | ||
75 | val = bcm_mpi_readl(MPI_CSCTL_REG(cs)); | ||
76 | val &= ~(MPI_CSCTL_WAIT_MASK); | ||
77 | val &= ~(MPI_CSCTL_SETUP_MASK); | ||
78 | val &= ~(MPI_CSCTL_HOLD_MASK); | ||
79 | val |= wait << MPI_CSCTL_WAIT_SHIFT; | ||
80 | val |= setup << MPI_CSCTL_SETUP_SHIFT; | ||
81 | val |= hold << MPI_CSCTL_HOLD_SHIFT; | ||
82 | bcm_mpi_writel(val, MPI_CSCTL_REG(cs)); | ||
83 | spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | EXPORT_SYMBOL(bcm63xx_set_cs_timing); | ||
89 | |||
90 | /* | ||
91 | * configure other chipselect parameter (data bus size, ...) | ||
92 | */ | ||
93 | int bcm63xx_set_cs_param(unsigned int cs, u32 params) | ||
94 | { | ||
95 | unsigned long flags; | ||
96 | u32 val; | ||
97 | |||
98 | if (!is_valid_cs(cs)) | ||
99 | return -EINVAL; | ||
100 | |||
101 | /* none of this fields apply to pcmcia */ | ||
102 | if (cs == MPI_CS_PCMCIA_COMMON || | ||
103 | cs == MPI_CS_PCMCIA_ATTR || | ||
104 | cs == MPI_CS_PCMCIA_IO) | ||
105 | return -EINVAL; | ||
106 | |||
107 | spin_lock_irqsave(&bcm63xx_cs_lock, flags); | ||
108 | val = bcm_mpi_readl(MPI_CSCTL_REG(cs)); | ||
109 | val &= ~(MPI_CSCTL_DATA16_MASK); | ||
110 | val &= ~(MPI_CSCTL_SYNCMODE_MASK); | ||
111 | val &= ~(MPI_CSCTL_TSIZE_MASK); | ||
112 | val &= ~(MPI_CSCTL_ENDIANSWAP_MASK); | ||
113 | val |= params; | ||
114 | bcm_mpi_writel(val, MPI_CSCTL_REG(cs)); | ||
115 | spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | EXPORT_SYMBOL(bcm63xx_set_cs_param); | ||
121 | |||
122 | /* | ||
123 | * set cs status (enable/disable) | ||
124 | */ | ||
125 | int bcm63xx_set_cs_status(unsigned int cs, int enable) | ||
126 | { | ||
127 | unsigned long flags; | ||
128 | u32 val; | ||
129 | |||
130 | if (!is_valid_cs(cs)) | ||
131 | return -EINVAL; | ||
132 | |||
133 | spin_lock_irqsave(&bcm63xx_cs_lock, flags); | ||
134 | val = bcm_mpi_readl(MPI_CSCTL_REG(cs)); | ||
135 | if (enable) | ||
136 | val |= MPI_CSCTL_ENABLE_MASK; | ||
137 | else | ||
138 | val &= ~MPI_CSCTL_ENABLE_MASK; | ||
139 | bcm_mpi_writel(val, MPI_CSCTL_REG(cs)); | ||
140 | spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | EXPORT_SYMBOL(bcm63xx_set_cs_status); | ||
diff --git a/arch/mips/bcm63xx/dev-dsp.c b/arch/mips/bcm63xx/dev-dsp.c new file mode 100644 index 000000000000..da46d1d3c77c --- /dev/null +++ b/arch/mips/bcm63xx/dev-dsp.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Broadcom BCM63xx VoIP DSP registration | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org> | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | |||
15 | #include <bcm63xx_cpu.h> | ||
16 | #include <bcm63xx_dev_dsp.h> | ||
17 | #include <bcm63xx_regs.h> | ||
18 | #include <bcm63xx_io.h> | ||
19 | |||
20 | static struct resource voip_dsp_resources[] = { | ||
21 | { | ||
22 | .start = -1, /* filled at runtime */ | ||
23 | .end = -1, /* filled at runtime */ | ||
24 | .flags = IORESOURCE_MEM, | ||
25 | }, | ||
26 | { | ||
27 | .start = -1, /* filled at runtime */ | ||
28 | .flags = IORESOURCE_IRQ, | ||
29 | }, | ||
30 | }; | ||
31 | |||
32 | static struct platform_device bcm63xx_voip_dsp_device = { | ||
33 | .name = "bcm63xx-voip-dsp", | ||
34 | .id = 0, | ||
35 | .num_resources = ARRAY_SIZE(voip_dsp_resources), | ||
36 | .resource = voip_dsp_resources, | ||
37 | }; | ||
38 | |||
39 | int __init bcm63xx_dsp_register(const struct bcm63xx_dsp_platform_data *pd) | ||
40 | { | ||
41 | struct bcm63xx_dsp_platform_data *dpd; | ||
42 | u32 val; | ||
43 | |||
44 | /* Get the memory window */ | ||
45 | val = bcm_mpi_readl(MPI_CSBASE_REG(pd->cs - 1)); | ||
46 | val &= MPI_CSBASE_BASE_MASK; | ||
47 | voip_dsp_resources[0].start = val; | ||
48 | voip_dsp_resources[0].end = val + 0xFFFFFFF; | ||
49 | voip_dsp_resources[1].start = pd->ext_irq; | ||
50 | |||
51 | /* copy given platform data */ | ||
52 | dpd = bcm63xx_voip_dsp_device.dev.platform_data; | ||
53 | memcpy(dpd, pd, sizeof (*pd)); | ||
54 | |||
55 | return platform_device_register(&bcm63xx_voip_dsp_device); | ||
56 | } | ||
diff --git a/arch/mips/bcm63xx/early_printk.c b/arch/mips/bcm63xx/early_printk.c new file mode 100644 index 000000000000..bf353c937df2 --- /dev/null +++ b/arch/mips/bcm63xx/early_printk.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <bcm63xx_io.h> | ||
11 | #include <bcm63xx_regs.h> | ||
12 | |||
13 | static void __init wait_xfered(void) | ||
14 | { | ||
15 | unsigned int val; | ||
16 | |||
17 | /* wait for any previous char to be transmitted */ | ||
18 | do { | ||
19 | val = bcm_uart0_readl(UART_IR_REG); | ||
20 | if (val & UART_IR_STAT(UART_IR_TXEMPTY)) | ||
21 | break; | ||
22 | } while (1); | ||
23 | } | ||
24 | |||
25 | void __init prom_putchar(char c) | ||
26 | { | ||
27 | wait_xfered(); | ||
28 | bcm_uart0_writel(c, UART_FIFO_REG); | ||
29 | wait_xfered(); | ||
30 | } | ||
diff --git a/arch/mips/bcm63xx/gpio.c b/arch/mips/bcm63xx/gpio.c new file mode 100644 index 000000000000..87ca39046334 --- /dev/null +++ b/arch/mips/bcm63xx/gpio.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/gpio.h> | ||
15 | |||
16 | #include <bcm63xx_cpu.h> | ||
17 | #include <bcm63xx_gpio.h> | ||
18 | #include <bcm63xx_io.h> | ||
19 | #include <bcm63xx_regs.h> | ||
20 | |||
21 | static DEFINE_SPINLOCK(bcm63xx_gpio_lock); | ||
22 | static u32 gpio_out_low, gpio_out_high; | ||
23 | |||
24 | static void bcm63xx_gpio_set(struct gpio_chip *chip, | ||
25 | unsigned gpio, int val) | ||
26 | { | ||
27 | u32 reg; | ||
28 | u32 mask; | ||
29 | u32 *v; | ||
30 | unsigned long flags; | ||
31 | |||
32 | if (gpio >= chip->ngpio) | ||
33 | BUG(); | ||
34 | |||
35 | if (gpio < 32) { | ||
36 | reg = GPIO_DATA_LO_REG; | ||
37 | mask = 1 << gpio; | ||
38 | v = &gpio_out_low; | ||
39 | } else { | ||
40 | reg = GPIO_DATA_HI_REG; | ||
41 | mask = 1 << (gpio - 32); | ||
42 | v = &gpio_out_high; | ||
43 | } | ||
44 | |||
45 | spin_lock_irqsave(&bcm63xx_gpio_lock, flags); | ||
46 | if (val) | ||
47 | *v |= mask; | ||
48 | else | ||
49 | *v &= ~mask; | ||
50 | bcm_gpio_writel(*v, reg); | ||
51 | spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags); | ||
52 | } | ||
53 | |||
54 | static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio) | ||
55 | { | ||
56 | u32 reg; | ||
57 | u32 mask; | ||
58 | |||
59 | if (gpio >= chip->ngpio) | ||
60 | BUG(); | ||
61 | |||
62 | if (gpio < 32) { | ||
63 | reg = GPIO_DATA_LO_REG; | ||
64 | mask = 1 << gpio; | ||
65 | } else { | ||
66 | reg = GPIO_DATA_HI_REG; | ||
67 | mask = 1 << (gpio - 32); | ||
68 | } | ||
69 | |||
70 | return !!(bcm_gpio_readl(reg) & mask); | ||
71 | } | ||
72 | |||
73 | static int bcm63xx_gpio_set_direction(struct gpio_chip *chip, | ||
74 | unsigned gpio, int dir) | ||
75 | { | ||
76 | u32 reg; | ||
77 | u32 mask; | ||
78 | u32 tmp; | ||
79 | unsigned long flags; | ||
80 | |||
81 | if (gpio >= chip->ngpio) | ||
82 | BUG(); | ||
83 | |||
84 | if (gpio < 32) { | ||
85 | reg = GPIO_CTL_LO_REG; | ||
86 | mask = 1 << gpio; | ||
87 | } else { | ||
88 | reg = GPIO_CTL_HI_REG; | ||
89 | mask = 1 << (gpio - 32); | ||
90 | } | ||
91 | |||
92 | spin_lock_irqsave(&bcm63xx_gpio_lock, flags); | ||
93 | tmp = bcm_gpio_readl(reg); | ||
94 | if (dir == GPIO_DIR_IN) | ||
95 | tmp &= ~mask; | ||
96 | else | ||
97 | tmp |= mask; | ||
98 | bcm_gpio_writel(tmp, reg); | ||
99 | spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int bcm63xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) | ||
105 | { | ||
106 | return bcm63xx_gpio_set_direction(chip, gpio, GPIO_DIR_IN); | ||
107 | } | ||
108 | |||
109 | static int bcm63xx_gpio_direction_output(struct gpio_chip *chip, | ||
110 | unsigned gpio, int value) | ||
111 | { | ||
112 | bcm63xx_gpio_set(chip, gpio, value); | ||
113 | return bcm63xx_gpio_set_direction(chip, gpio, GPIO_DIR_OUT); | ||
114 | } | ||
115 | |||
116 | |||
117 | static struct gpio_chip bcm63xx_gpio_chip = { | ||
118 | .label = "bcm63xx-gpio", | ||
119 | .direction_input = bcm63xx_gpio_direction_input, | ||
120 | .direction_output = bcm63xx_gpio_direction_output, | ||
121 | .get = bcm63xx_gpio_get, | ||
122 | .set = bcm63xx_gpio_set, | ||
123 | .base = 0, | ||
124 | }; | ||
125 | |||
126 | int __init bcm63xx_gpio_init(void) | ||
127 | { | ||
128 | bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count(); | ||
129 | pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio); | ||
130 | |||
131 | return gpiochip_add(&bcm63xx_gpio_chip); | ||
132 | } | ||
133 | |||
134 | arch_initcall(bcm63xx_gpio_init); | ||
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c new file mode 100644 index 000000000000..a0c5cd18c192 --- /dev/null +++ b/arch/mips/bcm63xx/irq.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr> | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <asm/irq_cpu.h> | ||
15 | #include <asm/mipsregs.h> | ||
16 | #include <bcm63xx_cpu.h> | ||
17 | #include <bcm63xx_regs.h> | ||
18 | #include <bcm63xx_io.h> | ||
19 | #include <bcm63xx_irq.h> | ||
20 | |||
21 | /* | ||
22 | * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not | ||
23 | * prioritize any interrupt relatively to another. the static counter | ||
24 | * will resume the loop where it ended the last time we left this | ||
25 | * function. | ||
26 | */ | ||
27 | static void bcm63xx_irq_dispatch_internal(void) | ||
28 | { | ||
29 | u32 pending; | ||
30 | static int i; | ||
31 | |||
32 | pending = bcm_perf_readl(PERF_IRQMASK_REG) & | ||
33 | bcm_perf_readl(PERF_IRQSTAT_REG); | ||
34 | |||
35 | if (!pending) | ||
36 | return ; | ||
37 | |||
38 | while (1) { | ||
39 | int to_call = i; | ||
40 | |||
41 | i = (i + 1) & 0x1f; | ||
42 | if (pending & (1 << to_call)) { | ||
43 | do_IRQ(to_call + IRQ_INTERNAL_BASE); | ||
44 | break; | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | asmlinkage void plat_irq_dispatch(void) | ||
50 | { | ||
51 | u32 cause; | ||
52 | |||
53 | do { | ||
54 | cause = read_c0_cause() & read_c0_status() & ST0_IM; | ||
55 | |||
56 | if (!cause) | ||
57 | break; | ||
58 | |||
59 | if (cause & CAUSEF_IP7) | ||
60 | do_IRQ(7); | ||
61 | if (cause & CAUSEF_IP2) | ||
62 | bcm63xx_irq_dispatch_internal(); | ||
63 | if (cause & CAUSEF_IP3) | ||
64 | do_IRQ(IRQ_EXT_0); | ||
65 | if (cause & CAUSEF_IP4) | ||
66 | do_IRQ(IRQ_EXT_1); | ||
67 | if (cause & CAUSEF_IP5) | ||
68 | do_IRQ(IRQ_EXT_2); | ||
69 | if (cause & CAUSEF_IP6) | ||
70 | do_IRQ(IRQ_EXT_3); | ||
71 | } while (1); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * internal IRQs operations: only mask/unmask on PERF irq mask | ||
76 | * register. | ||
77 | */ | ||
78 | static inline void bcm63xx_internal_irq_mask(unsigned int irq) | ||
79 | { | ||
80 | u32 mask; | ||
81 | |||
82 | irq -= IRQ_INTERNAL_BASE; | ||
83 | mask = bcm_perf_readl(PERF_IRQMASK_REG); | ||
84 | mask &= ~(1 << irq); | ||
85 | bcm_perf_writel(mask, PERF_IRQMASK_REG); | ||
86 | } | ||
87 | |||
88 | static void bcm63xx_internal_irq_unmask(unsigned int irq) | ||
89 | { | ||
90 | u32 mask; | ||
91 | |||
92 | irq -= IRQ_INTERNAL_BASE; | ||
93 | mask = bcm_perf_readl(PERF_IRQMASK_REG); | ||
94 | mask |= (1 << irq); | ||
95 | bcm_perf_writel(mask, PERF_IRQMASK_REG); | ||
96 | } | ||
97 | |||
98 | static unsigned int bcm63xx_internal_irq_startup(unsigned int irq) | ||
99 | { | ||
100 | bcm63xx_internal_irq_unmask(irq); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * external IRQs operations: mask/unmask and clear on PERF external | ||
106 | * irq control register. | ||
107 | */ | ||
108 | static void bcm63xx_external_irq_mask(unsigned int irq) | ||
109 | { | ||
110 | u32 reg; | ||
111 | |||
112 | irq -= IRQ_EXT_BASE; | ||
113 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | ||
114 | reg &= ~EXTIRQ_CFG_MASK(irq); | ||
115 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | ||
116 | } | ||
117 | |||
118 | static void bcm63xx_external_irq_unmask(unsigned int irq) | ||
119 | { | ||
120 | u32 reg; | ||
121 | |||
122 | irq -= IRQ_EXT_BASE; | ||
123 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | ||
124 | reg |= EXTIRQ_CFG_MASK(irq); | ||
125 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | ||
126 | } | ||
127 | |||
128 | static void bcm63xx_external_irq_clear(unsigned int irq) | ||
129 | { | ||
130 | u32 reg; | ||
131 | |||
132 | irq -= IRQ_EXT_BASE; | ||
133 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | ||
134 | reg |= EXTIRQ_CFG_CLEAR(irq); | ||
135 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | ||
136 | } | ||
137 | |||
138 | static unsigned int bcm63xx_external_irq_startup(unsigned int irq) | ||
139 | { | ||
140 | set_c0_status(0x100 << (irq - IRQ_MIPS_BASE)); | ||
141 | irq_enable_hazard(); | ||
142 | bcm63xx_external_irq_unmask(irq); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static void bcm63xx_external_irq_shutdown(unsigned int irq) | ||
147 | { | ||
148 | bcm63xx_external_irq_mask(irq); | ||
149 | clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE)); | ||
150 | irq_disable_hazard(); | ||
151 | } | ||
152 | |||
153 | static int bcm63xx_external_irq_set_type(unsigned int irq, | ||
154 | unsigned int flow_type) | ||
155 | { | ||
156 | u32 reg; | ||
157 | struct irq_desc *desc = irq_desc + irq; | ||
158 | |||
159 | irq -= IRQ_EXT_BASE; | ||
160 | |||
161 | flow_type &= IRQ_TYPE_SENSE_MASK; | ||
162 | |||
163 | if (flow_type == IRQ_TYPE_NONE) | ||
164 | flow_type = IRQ_TYPE_LEVEL_LOW; | ||
165 | |||
166 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | ||
167 | switch (flow_type) { | ||
168 | case IRQ_TYPE_EDGE_BOTH: | ||
169 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | ||
170 | reg |= EXTIRQ_CFG_BOTHEDGE(irq); | ||
171 | break; | ||
172 | |||
173 | case IRQ_TYPE_EDGE_RISING: | ||
174 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | ||
175 | reg |= EXTIRQ_CFG_SENSE(irq); | ||
176 | reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); | ||
177 | break; | ||
178 | |||
179 | case IRQ_TYPE_EDGE_FALLING: | ||
180 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | ||
181 | reg &= ~EXTIRQ_CFG_SENSE(irq); | ||
182 | reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); | ||
183 | break; | ||
184 | |||
185 | case IRQ_TYPE_LEVEL_HIGH: | ||
186 | reg |= EXTIRQ_CFG_LEVELSENSE(irq); | ||
187 | reg |= EXTIRQ_CFG_SENSE(irq); | ||
188 | break; | ||
189 | |||
190 | case IRQ_TYPE_LEVEL_LOW: | ||
191 | reg |= EXTIRQ_CFG_LEVELSENSE(irq); | ||
192 | reg &= ~EXTIRQ_CFG_SENSE(irq); | ||
193 | break; | ||
194 | |||
195 | default: | ||
196 | printk(KERN_ERR "bogus flow type combination given !\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | ||
200 | |||
201 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { | ||
202 | desc->status |= IRQ_LEVEL; | ||
203 | desc->handle_irq = handle_level_irq; | ||
204 | } else { | ||
205 | desc->handle_irq = handle_edge_irq; | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static struct irq_chip bcm63xx_internal_irq_chip = { | ||
212 | .name = "bcm63xx_ipic", | ||
213 | .startup = bcm63xx_internal_irq_startup, | ||
214 | .shutdown = bcm63xx_internal_irq_mask, | ||
215 | |||
216 | .mask = bcm63xx_internal_irq_mask, | ||
217 | .mask_ack = bcm63xx_internal_irq_mask, | ||
218 | .unmask = bcm63xx_internal_irq_unmask, | ||
219 | }; | ||
220 | |||
221 | static struct irq_chip bcm63xx_external_irq_chip = { | ||
222 | .name = "bcm63xx_epic", | ||
223 | .startup = bcm63xx_external_irq_startup, | ||
224 | .shutdown = bcm63xx_external_irq_shutdown, | ||
225 | |||
226 | .ack = bcm63xx_external_irq_clear, | ||
227 | |||
228 | .mask = bcm63xx_external_irq_mask, | ||
229 | .unmask = bcm63xx_external_irq_unmask, | ||
230 | |||
231 | .set_type = bcm63xx_external_irq_set_type, | ||
232 | }; | ||
233 | |||
234 | static struct irqaction cpu_ip2_cascade_action = { | ||
235 | .handler = no_action, | ||
236 | .name = "cascade_ip2", | ||
237 | }; | ||
238 | |||
239 | void __init arch_init_irq(void) | ||
240 | { | ||
241 | int i; | ||
242 | |||
243 | mips_cpu_irq_init(); | ||
244 | for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i) | ||
245 | set_irq_chip_and_handler(i, &bcm63xx_internal_irq_chip, | ||
246 | handle_level_irq); | ||
247 | |||
248 | for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i) | ||
249 | set_irq_chip_and_handler(i, &bcm63xx_external_irq_chip, | ||
250 | handle_edge_irq); | ||
251 | |||
252 | setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action); | ||
253 | } | ||
diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c new file mode 100644 index 000000000000..fb284fbc5853 --- /dev/null +++ b/arch/mips/bcm63xx/prom.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/bootmem.h> | ||
11 | #include <asm/bootinfo.h> | ||
12 | #include <bcm63xx_board.h> | ||
13 | #include <bcm63xx_cpu.h> | ||
14 | #include <bcm63xx_io.h> | ||
15 | #include <bcm63xx_regs.h> | ||
16 | #include <bcm63xx_gpio.h> | ||
17 | |||
18 | void __init prom_init(void) | ||
19 | { | ||
20 | u32 reg, mask; | ||
21 | |||
22 | bcm63xx_cpu_init(); | ||
23 | |||
24 | /* stop any running watchdog */ | ||
25 | bcm_wdt_writel(WDT_STOP_1, WDT_CTL_REG); | ||
26 | bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG); | ||
27 | |||
28 | /* disable all hardware blocks clock for now */ | ||
29 | if (BCMCPU_IS_6338()) | ||
30 | mask = CKCTL_6338_ALL_SAFE_EN; | ||
31 | else if (BCMCPU_IS_6345()) | ||
32 | mask = CKCTL_6345_ALL_SAFE_EN; | ||
33 | else if (BCMCPU_IS_6348()) | ||
34 | mask = CKCTL_6348_ALL_SAFE_EN; | ||
35 | else | ||
36 | /* BCMCPU_IS_6358() */ | ||
37 | mask = CKCTL_6358_ALL_SAFE_EN; | ||
38 | |||
39 | reg = bcm_perf_readl(PERF_CKCTL_REG); | ||
40 | reg &= ~mask; | ||
41 | bcm_perf_writel(reg, PERF_CKCTL_REG); | ||
42 | |||
43 | /* assign command line from kernel config */ | ||
44 | strcpy(arcs_cmdline, CONFIG_CMDLINE); | ||
45 | |||
46 | /* register gpiochip */ | ||
47 | bcm63xx_gpio_init(); | ||
48 | |||
49 | /* do low level board init */ | ||
50 | board_prom_init(); | ||
51 | } | ||
52 | |||
53 | void __init prom_free_prom_memory(void) | ||
54 | { | ||
55 | } | ||
diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c new file mode 100644 index 000000000000..b18a0ca926fa --- /dev/null +++ b/arch/mips/bcm63xx/setup.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/bootmem.h> | ||
13 | #include <linux/ioport.h> | ||
14 | #include <linux/pm.h> | ||
15 | #include <asm/bootinfo.h> | ||
16 | #include <asm/time.h> | ||
17 | #include <asm/reboot.h> | ||
18 | #include <asm/cacheflush.h> | ||
19 | #include <bcm63xx_board.h> | ||
20 | #include <bcm63xx_cpu.h> | ||
21 | #include <bcm63xx_regs.h> | ||
22 | #include <bcm63xx_io.h> | ||
23 | |||
24 | void bcm63xx_machine_halt(void) | ||
25 | { | ||
26 | printk(KERN_INFO "System halted\n"); | ||
27 | while (1) | ||
28 | ; | ||
29 | } | ||
30 | |||
31 | static void bcm6348_a1_reboot(void) | ||
32 | { | ||
33 | u32 reg; | ||
34 | |||
35 | /* soft reset all blocks */ | ||
36 | printk(KERN_INFO "soft-reseting all blocks ...\n"); | ||
37 | reg = bcm_perf_readl(PERF_SOFTRESET_REG); | ||
38 | reg &= ~SOFTRESET_6348_ALL; | ||
39 | bcm_perf_writel(reg, PERF_SOFTRESET_REG); | ||
40 | mdelay(10); | ||
41 | |||
42 | reg = bcm_perf_readl(PERF_SOFTRESET_REG); | ||
43 | reg |= SOFTRESET_6348_ALL; | ||
44 | bcm_perf_writel(reg, PERF_SOFTRESET_REG); | ||
45 | mdelay(10); | ||
46 | |||
47 | /* Jump to the power on address. */ | ||
48 | printk(KERN_INFO "jumping to reset vector.\n"); | ||
49 | /* set high vectors (base at 0xbfc00000 */ | ||
50 | set_c0_status(ST0_BEV | ST0_ERL); | ||
51 | /* run uncached in kseg0 */ | ||
52 | change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); | ||
53 | __flush_cache_all(); | ||
54 | /* remove all wired TLB entries */ | ||
55 | write_c0_wired(0); | ||
56 | __asm__ __volatile__( | ||
57 | "jr\t%0" | ||
58 | : | ||
59 | : "r" (0xbfc00000)); | ||
60 | while (1) | ||
61 | ; | ||
62 | } | ||
63 | |||
64 | void bcm63xx_machine_reboot(void) | ||
65 | { | ||
66 | u32 reg; | ||
67 | |||
68 | /* mask and clear all external irq */ | ||
69 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | ||
70 | reg &= ~EXTIRQ_CFG_MASK_ALL; | ||
71 | reg |= EXTIRQ_CFG_CLEAR_ALL; | ||
72 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | ||
73 | |||
74 | if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) | ||
75 | bcm6348_a1_reboot(); | ||
76 | |||
77 | printk(KERN_INFO "triggering watchdog soft-reset...\n"); | ||
78 | bcm_perf_writel(SYS_PLL_SOFT_RESET, PERF_SYS_PLL_CTL_REG); | ||
79 | while (1) | ||
80 | ; | ||
81 | } | ||
82 | |||
83 | static void __bcm63xx_machine_reboot(char *p) | ||
84 | { | ||
85 | bcm63xx_machine_reboot(); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * return system type in /proc/cpuinfo | ||
90 | */ | ||
91 | const char *get_system_type(void) | ||
92 | { | ||
93 | static char buf[128]; | ||
94 | snprintf(buf, sizeof(buf), "bcm63xx/%s (0x%04x/0x%04X)", | ||
95 | board_get_name(), | ||
96 | bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev()); | ||
97 | return buf; | ||
98 | } | ||
99 | |||
100 | void __init plat_time_init(void) | ||
101 | { | ||
102 | mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2; | ||
103 | } | ||
104 | |||
105 | void __init plat_mem_setup(void) | ||
106 | { | ||
107 | add_memory_region(0, bcm63xx_get_memory_size(), BOOT_MEM_RAM); | ||
108 | |||
109 | _machine_halt = bcm63xx_machine_halt; | ||
110 | _machine_restart = __bcm63xx_machine_reboot; | ||
111 | pm_power_off = bcm63xx_machine_halt; | ||
112 | |||
113 | set_io_port_base(0); | ||
114 | ioport_resource.start = 0; | ||
115 | ioport_resource.end = ~0; | ||
116 | |||
117 | board_setup(); | ||
118 | } | ||
119 | |||
120 | int __init bcm63xx_register_devices(void) | ||
121 | { | ||
122 | return board_register_devices(); | ||
123 | } | ||
124 | |||
125 | arch_initcall(bcm63xx_register_devices); | ||
diff --git a/arch/mips/bcm63xx/timer.c b/arch/mips/bcm63xx/timer.c new file mode 100644 index 000000000000..ba522bdcde4b --- /dev/null +++ b/arch/mips/bcm63xx/timer.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/err.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <bcm63xx_cpu.h> | ||
16 | #include <bcm63xx_io.h> | ||
17 | #include <bcm63xx_timer.h> | ||
18 | #include <bcm63xx_regs.h> | ||
19 | |||
20 | static DEFINE_SPINLOCK(timer_reg_lock); | ||
21 | static DEFINE_SPINLOCK(timer_data_lock); | ||
22 | static struct clk *periph_clk; | ||
23 | |||
24 | static struct timer_data { | ||
25 | void (*cb)(void *); | ||
26 | void *data; | ||
27 | } timer_data[BCM63XX_TIMER_COUNT]; | ||
28 | |||
29 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
30 | { | ||
31 | u32 stat; | ||
32 | int i; | ||
33 | |||
34 | spin_lock(&timer_reg_lock); | ||
35 | stat = bcm_timer_readl(TIMER_IRQSTAT_REG); | ||
36 | bcm_timer_writel(stat, TIMER_IRQSTAT_REG); | ||
37 | spin_unlock(&timer_reg_lock); | ||
38 | |||
39 | for (i = 0; i < BCM63XX_TIMER_COUNT; i++) { | ||
40 | if (!(stat & TIMER_IRQSTAT_TIMER_CAUSE(i))) | ||
41 | continue; | ||
42 | |||
43 | spin_lock(&timer_data_lock); | ||
44 | if (!timer_data[i].cb) { | ||
45 | spin_unlock(&timer_data_lock); | ||
46 | continue; | ||
47 | } | ||
48 | |||
49 | timer_data[i].cb(timer_data[i].data); | ||
50 | spin_unlock(&timer_data_lock); | ||
51 | } | ||
52 | |||
53 | return IRQ_HANDLED; | ||
54 | } | ||
55 | |||
56 | int bcm63xx_timer_enable(int id) | ||
57 | { | ||
58 | u32 reg; | ||
59 | unsigned long flags; | ||
60 | |||
61 | if (id >= BCM63XX_TIMER_COUNT) | ||
62 | return -EINVAL; | ||
63 | |||
64 | spin_lock_irqsave(&timer_reg_lock, flags); | ||
65 | |||
66 | reg = bcm_timer_readl(TIMER_CTLx_REG(id)); | ||
67 | reg |= TIMER_CTL_ENABLE_MASK; | ||
68 | bcm_timer_writel(reg, TIMER_CTLx_REG(id)); | ||
69 | |||
70 | reg = bcm_timer_readl(TIMER_IRQSTAT_REG); | ||
71 | reg |= TIMER_IRQSTAT_TIMER_IR_EN(id); | ||
72 | bcm_timer_writel(reg, TIMER_IRQSTAT_REG); | ||
73 | |||
74 | spin_unlock_irqrestore(&timer_reg_lock, flags); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | EXPORT_SYMBOL(bcm63xx_timer_enable); | ||
79 | |||
80 | int bcm63xx_timer_disable(int id) | ||
81 | { | ||
82 | u32 reg; | ||
83 | unsigned long flags; | ||
84 | |||
85 | if (id >= BCM63XX_TIMER_COUNT) | ||
86 | return -EINVAL; | ||
87 | |||
88 | spin_lock_irqsave(&timer_reg_lock, flags); | ||
89 | |||
90 | reg = bcm_timer_readl(TIMER_CTLx_REG(id)); | ||
91 | reg &= ~TIMER_CTL_ENABLE_MASK; | ||
92 | bcm_timer_writel(reg, TIMER_CTLx_REG(id)); | ||
93 | |||
94 | reg = bcm_timer_readl(TIMER_IRQSTAT_REG); | ||
95 | reg &= ~TIMER_IRQSTAT_TIMER_IR_EN(id); | ||
96 | bcm_timer_writel(reg, TIMER_IRQSTAT_REG); | ||
97 | |||
98 | spin_unlock_irqrestore(&timer_reg_lock, flags); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | EXPORT_SYMBOL(bcm63xx_timer_disable); | ||
103 | |||
104 | int bcm63xx_timer_register(int id, void (*callback)(void *data), void *data) | ||
105 | { | ||
106 | unsigned long flags; | ||
107 | int ret; | ||
108 | |||
109 | if (id >= BCM63XX_TIMER_COUNT || !callback) | ||
110 | return -EINVAL; | ||
111 | |||
112 | ret = 0; | ||
113 | spin_lock_irqsave(&timer_data_lock, flags); | ||
114 | if (timer_data[id].cb) { | ||
115 | ret = -EBUSY; | ||
116 | goto out; | ||
117 | } | ||
118 | |||
119 | timer_data[id].cb = callback; | ||
120 | timer_data[id].data = data; | ||
121 | |||
122 | out: | ||
123 | spin_unlock_irqrestore(&timer_data_lock, flags); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | EXPORT_SYMBOL(bcm63xx_timer_register); | ||
128 | |||
129 | void bcm63xx_timer_unregister(int id) | ||
130 | { | ||
131 | unsigned long flags; | ||
132 | |||
133 | if (id >= BCM63XX_TIMER_COUNT) | ||
134 | return; | ||
135 | |||
136 | spin_lock_irqsave(&timer_data_lock, flags); | ||
137 | timer_data[id].cb = NULL; | ||
138 | spin_unlock_irqrestore(&timer_data_lock, flags); | ||
139 | } | ||
140 | |||
141 | EXPORT_SYMBOL(bcm63xx_timer_unregister); | ||
142 | |||
143 | unsigned int bcm63xx_timer_countdown(unsigned int countdown_us) | ||
144 | { | ||
145 | return (clk_get_rate(periph_clk) / (1000 * 1000)) * countdown_us; | ||
146 | } | ||
147 | |||
148 | EXPORT_SYMBOL(bcm63xx_timer_countdown); | ||
149 | |||
150 | int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us) | ||
151 | { | ||
152 | u32 reg, countdown; | ||
153 | unsigned long flags; | ||
154 | |||
155 | if (id >= BCM63XX_TIMER_COUNT) | ||
156 | return -EINVAL; | ||
157 | |||
158 | countdown = bcm63xx_timer_countdown(countdown_us); | ||
159 | if (countdown & ~TIMER_CTL_COUNTDOWN_MASK) | ||
160 | return -EINVAL; | ||
161 | |||
162 | spin_lock_irqsave(&timer_reg_lock, flags); | ||
163 | reg = bcm_timer_readl(TIMER_CTLx_REG(id)); | ||
164 | |||
165 | if (monotonic) | ||
166 | reg &= ~TIMER_CTL_MONOTONIC_MASK; | ||
167 | else | ||
168 | reg |= TIMER_CTL_MONOTONIC_MASK; | ||
169 | |||
170 | reg &= ~TIMER_CTL_COUNTDOWN_MASK; | ||
171 | reg |= countdown; | ||
172 | bcm_timer_writel(reg, TIMER_CTLx_REG(id)); | ||
173 | |||
174 | spin_unlock_irqrestore(&timer_reg_lock, flags); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | EXPORT_SYMBOL(bcm63xx_timer_set); | ||
179 | |||
180 | int bcm63xx_timer_init(void) | ||
181 | { | ||
182 | int ret, irq; | ||
183 | u32 reg; | ||
184 | |||
185 | reg = bcm_timer_readl(TIMER_IRQSTAT_REG); | ||
186 | reg &= ~TIMER_IRQSTAT_TIMER0_IR_EN; | ||
187 | reg &= ~TIMER_IRQSTAT_TIMER1_IR_EN; | ||
188 | reg &= ~TIMER_IRQSTAT_TIMER2_IR_EN; | ||
189 | bcm_timer_writel(reg, TIMER_IRQSTAT_REG); | ||
190 | |||
191 | periph_clk = clk_get(NULL, "periph"); | ||
192 | if (IS_ERR(periph_clk)) | ||
193 | return -ENODEV; | ||
194 | |||
195 | irq = bcm63xx_get_irq_number(IRQ_TIMER); | ||
196 | ret = request_irq(irq, timer_interrupt, 0, "bcm63xx_timer", NULL); | ||
197 | if (ret) { | ||
198 | printk(KERN_ERR "bcm63xx_timer: failed to register irq\n"); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | arch_initcall(bcm63xx_timer_init); | ||