aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/bcm63xx
diff options
context:
space:
mode:
authorMaxime Bizon <mbizon@freebox.fr>2009-08-18 08:23:37 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-09-17 14:07:52 -0400
commite7300d04bd0809eb7ea10a2ed8c729459f816e36 (patch)
tree8af589d3954c09323d3f74e69aa6fabbb32e049e /arch/mips/bcm63xx
parent0de663ef8627f35fda9106a8faaca512f29e493e (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/Kconfig25
-rw-r--r--arch/mips/bcm63xx/Makefile7
-rw-r--r--arch/mips/bcm63xx/boards/Kconfig11
-rw-r--r--arch/mips/bcm63xx/boards/Makefile3
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c837
-rw-r--r--arch/mips/bcm63xx/clk.c226
-rw-r--r--arch/mips/bcm63xx/cpu.c345
-rw-r--r--arch/mips/bcm63xx/cs.c144
-rw-r--r--arch/mips/bcm63xx/dev-dsp.c56
-rw-r--r--arch/mips/bcm63xx/early_printk.c30
-rw-r--r--arch/mips/bcm63xx/gpio.c134
-rw-r--r--arch/mips/bcm63xx/irq.c253
-rw-r--r--arch/mips/bcm63xx/prom.c55
-rw-r--r--arch/mips/bcm63xx/setup.c125
-rw-r--r--arch/mips/bcm63xx/timer.c205
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 @@
1menu "CPU support"
2 depends on BCM63XX
3
4config 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
11config BCM63XX_CPU_6345
12 bool "support 6345 CPU"
13 select USB_OHCI_BIG_ENDIAN_DESC
14 select USB_OHCI_BIG_ENDIAN_MMIO
15
16config BCM63XX_CPU_6348
17 bool "support 6348 CPU"
18 select HW_HAS_PCI
19
20config BCM63XX_CPU_6358
21 bool "support 6358 CPU"
22 select HW_HAS_PCI
23endmenu
24
25source "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 @@
1obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
2 dev-dsp.o
3obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
4
5obj-y += boards/
6
7EXTRA_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 @@
1choice
2 prompt "Board support"
3 depends on BCM63XX
4 default BOARD_BCM963XX
5
6config BOARD_BCM963XX
7 bool "Generic Broadcom 963xx boards"
8 select SSB
9 help
10
11endchoice
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 @@
1obj-$(CONFIG_BOARD_BCM963XX) += board_bcm963xx.o
2
3EXTRA_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
31static struct bcm963xx_nvram nvram;
32static unsigned int mac_addr_used;
33static struct board_info board;
34
35/*
36 * known 6338 boards
37 */
38#ifdef CONFIG_BCM63XX_CPU_6338
39static 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
81static 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
126static 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
136static 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
179static 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
238static 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
291static 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
348static 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
372static 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
391static 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
416static 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
467static 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
514static 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 */
540static 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 */
568void __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 */
669void __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 */
683const char *board_get_name(void)
684{
685 return board.name;
686}
687
688/*
689 * register & return a new board mac address
690 */
691static 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
723static struct mtd_partition mtd_partitions[] = {
724 {
725 .name = "cfe",
726 .offset = 0x0,
727 .size = 0x40000,
728 }
729};
730
731static struct physmap_flash_data flash_data = {
732 .width = 2,
733 .nr_parts = ARRAY_SIZE(mtd_partitions),
734 .parts = mtd_partitions,
735};
736
737static struct resource mtd_resources[] = {
738 {
739 .start = 0, /* filled at runtime */
740 .end = 0, /* filled at runtime */
741 .flags = IORESOURCE_MEM,
742 }
743};
744
745static 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
759static 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
781static struct gpio_led_platform_data bcm63xx_led_data;
782
783static 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 */
792int __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
18static DEFINE_MUTEX(clocks_mutex);
19
20
21static void clk_enable_unlocked(struct clk *clk)
22{
23 if (clk->set && (clk->usage++) == 0)
24 clk->set(clk, 1);
25}
26
27static void clk_disable_unlocked(struct clk *clk)
28{
29 if (clk->set && (--clk->usage) == 0)
30 clk->set(clk, 0);
31}
32
33static 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 */
48static 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
64static 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 */
72static 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
90static struct clk clk_enet0 = {
91 .id = 0,
92 .set = enetx_set,
93};
94
95static struct clk clk_enet1 = {
96 .id = 1,
97 .set = enetx_set,
98};
99
100/*
101 * Ethernet PHY clock
102 */
103static 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
111static struct clk clk_ephy = {
112 .set = ephy_set,
113};
114
115/*
116 * PCM clock
117 */
118static 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
125static struct clk clk_pcm = {
126 .set = pcm_set,
127};
128
129/*
130 * USB host clock
131 */
132static 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
139static struct clk clk_usbh = {
140 .set = usbh_set,
141};
142
143/*
144 * SPI clock
145 */
146static 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
160static struct clk clk_spi = {
161 .set = spi_set,
162};
163
164/*
165 * Internal peripheral clock
166 */
167static struct clk clk_periph = {
168 .rate = (50 * 1000 * 1000),
169};
170
171
172/*
173 * Linux clock API implementation
174 */
175int 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
183EXPORT_SYMBOL(clk_enable);
184
185void clk_disable(struct clk *clk)
186{
187 mutex_lock(&clocks_mutex);
188 clk_disable_unlocked(clk);
189 mutex_unlock(&clocks_mutex);
190}
191
192EXPORT_SYMBOL(clk_disable);
193
194unsigned long clk_get_rate(struct clk *clk)
195{
196 return clk->rate;
197}
198
199EXPORT_SYMBOL(clk_get_rate);
200
201struct 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
220EXPORT_SYMBOL(clk_get);
221
222void clk_put(struct clk *clk)
223{
224}
225
226EXPORT_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
18const unsigned long *bcm63xx_regs_base;
19EXPORT_SYMBOL(bcm63xx_regs_base);
20
21const int *bcm63xx_irqs;
22EXPORT_SYMBOL(bcm63xx_irqs);
23
24static u16 bcm63xx_cpu_id;
25static u16 bcm63xx_cpu_rev;
26static unsigned int bcm63xx_cpu_freq;
27static unsigned int bcm63xx_memory_size;
28
29/*
30 * 6338 register sets and irqs
31 */
32static 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
55static 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 */
68static 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
92static 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 */
105static 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
127static 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 */
146static 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
169static 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
186u16 __bcm63xx_get_cpu_id(void)
187{
188 return bcm63xx_cpu_id;
189}
190
191EXPORT_SYMBOL(__bcm63xx_get_cpu_id);
192
193u16 bcm63xx_get_cpu_rev(void)
194{
195 return bcm63xx_cpu_rev;
196}
197
198EXPORT_SYMBOL(bcm63xx_get_cpu_rev);
199
200unsigned int bcm63xx_get_cpu_freq(void)
201{
202 return bcm63xx_cpu_freq;
203}
204
205unsigned int bcm63xx_get_memory_size(void)
206{
207 return bcm63xx_memory_size;
208}
209
210static 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 */
250static 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
283void __init bcm63xx_cpu_init(void)
284{
285 unsigned int tmp, expected_cpu_id;
286 struct cpuinfo_mips *c = &current_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
18static DEFINE_SPINLOCK(bcm63xx_cs_lock);
19
20/*
21 * check if given chip select exists
22 */
23static 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 */
34int 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
60EXPORT_SYMBOL(bcm63xx_set_cs_base);
61
62/*
63 * configure chipselect timing (ns)
64 */
65int 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
88EXPORT_SYMBOL(bcm63xx_set_cs_timing);
89
90/*
91 * configure other chipselect parameter (data bus size, ...)
92 */
93int 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
120EXPORT_SYMBOL(bcm63xx_set_cs_param);
121
122/*
123 * set cs status (enable/disable)
124 */
125int 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
144EXPORT_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
20static 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
32static 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
39int __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
13static 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
25void __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
21static DEFINE_SPINLOCK(bcm63xx_gpio_lock);
22static u32 gpio_out_low, gpio_out_high;
23
24static 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
54static 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
73static 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
104static 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
109static 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
117static 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
126int __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
134arch_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 */
27static 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
49asmlinkage 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 */
78static 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
88static 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
98static 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 */
108static 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
118static 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
128static 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
138static 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
146static 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
153static 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
211static 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
221static 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
234static struct irqaction cpu_ip2_cascade_action = {
235 .handler = no_action,
236 .name = "cascade_ip2",
237};
238
239void __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
18void __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
53void __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
24void bcm63xx_machine_halt(void)
25{
26 printk(KERN_INFO "System halted\n");
27 while (1)
28 ;
29}
30
31static 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
64void 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
83static void __bcm63xx_machine_reboot(char *p)
84{
85 bcm63xx_machine_reboot();
86}
87
88/*
89 * return system type in /proc/cpuinfo
90 */
91const 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
100void __init plat_time_init(void)
101{
102 mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2;
103}
104
105void __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
120int __init bcm63xx_register_devices(void)
121{
122 return board_register_devices();
123}
124
125arch_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
20static DEFINE_SPINLOCK(timer_reg_lock);
21static DEFINE_SPINLOCK(timer_data_lock);
22static struct clk *periph_clk;
23
24static struct timer_data {
25 void (*cb)(void *);
26 void *data;
27} timer_data[BCM63XX_TIMER_COUNT];
28
29static 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
56int 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
78EXPORT_SYMBOL(bcm63xx_timer_enable);
79
80int 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
102EXPORT_SYMBOL(bcm63xx_timer_disable);
103
104int 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
122out:
123 spin_unlock_irqrestore(&timer_data_lock, flags);
124 return ret;
125}
126
127EXPORT_SYMBOL(bcm63xx_timer_register);
128
129void 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
141EXPORT_SYMBOL(bcm63xx_timer_unregister);
142
143unsigned int bcm63xx_timer_countdown(unsigned int countdown_us)
144{
145 return (clk_get_rate(periph_clk) / (1000 * 1000)) * countdown_us;
146}
147
148EXPORT_SYMBOL(bcm63xx_timer_countdown);
149
150int 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
178EXPORT_SYMBOL(bcm63xx_timer_set);
179
180int 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
205arch_initcall(bcm63xx_timer_init);