aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/bcm63xx
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/bcm63xx
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/bcm63xx')
-rw-r--r--arch/mips/bcm63xx/Kconfig45
-rw-r--r--arch/mips/bcm63xx/Makefile8
-rw-r--r--arch/mips/bcm63xx/Platform6
-rw-r--r--arch/mips/bcm63xx/boards/Kconfig11
-rw-r--r--arch/mips/bcm63xx/boards/Makefile2
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c911
-rw-r--r--arch/mips/bcm63xx/clk.c579
-rw-r--r--arch/mips/bcm63xx/cpu.c385
-rw-r--r--arch/mips/bcm63xx/cs.c145
-rw-r--r--arch/mips/bcm63xx/dev-enet.c327
-rw-r--r--arch/mips/bcm63xx/dev-flash.c131
-rw-r--r--arch/mips/bcm63xx/dev-hsspi.c47
-rw-r--r--arch/mips/bcm63xx/dev-pcmcia.c144
-rw-r--r--arch/mips/bcm63xx/dev-rng.c40
-rw-r--r--arch/mips/bcm63xx/dev-spi.c60
-rw-r--r--arch/mips/bcm63xx/dev-uart.c76
-rw-r--r--arch/mips/bcm63xx/dev-usb-usbd.c65
-rw-r--r--arch/mips/bcm63xx/dev-wdt.c37
-rw-r--r--arch/mips/bcm63xx/early_printk.c30
-rw-r--r--arch/mips/bcm63xx/gpio.c151
-rw-r--r--arch/mips/bcm63xx/irq.c553
-rw-r--r--arch/mips/bcm63xx/nvram.c98
-rw-r--r--arch/mips/bcm63xx/prom.c100
-rw-r--r--arch/mips/bcm63xx/reset.c219
-rw-r--r--arch/mips/bcm63xx/setup.c170
-rw-r--r--arch/mips/bcm63xx/timer.c206
26 files changed, 4546 insertions, 0 deletions
diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig
new file mode 100644
index 000000000..837f6e5a2
--- /dev/null
+++ b/arch/mips/bcm63xx/Kconfig
@@ -0,0 +1,45 @@
1# SPDX-License-Identifier: GPL-2.0
2menu "CPU support"
3 depends on BCM63XX
4
5config BCM63XX_CPU_3368
6 bool "support 3368 CPU"
7 select SYS_HAS_CPU_BMIPS4350
8 select HAVE_PCI
9
10config BCM63XX_CPU_6328
11 bool "support 6328 CPU"
12 select SYS_HAS_CPU_BMIPS4350
13 select HAVE_PCI
14
15config BCM63XX_CPU_6338
16 bool "support 6338 CPU"
17 select SYS_HAS_CPU_BMIPS32_3300
18 select HAVE_PCI
19
20config BCM63XX_CPU_6345
21 bool "support 6345 CPU"
22 select SYS_HAS_CPU_BMIPS32_3300
23
24config BCM63XX_CPU_6348
25 bool "support 6348 CPU"
26 select SYS_HAS_CPU_BMIPS32_3300
27 select HAVE_PCI
28
29config BCM63XX_CPU_6358
30 bool "support 6358 CPU"
31 select SYS_HAS_CPU_BMIPS4350
32 select HAVE_PCI
33
34config BCM63XX_CPU_6362
35 bool "support 6362 CPU"
36 select SYS_HAS_CPU_BMIPS4350
37 select HAVE_PCI
38
39config BCM63XX_CPU_6368
40 bool "support 6368 CPU"
41 select SYS_HAS_CPU_BMIPS4350
42 select HAVE_PCI
43endmenu
44
45source "arch/mips/bcm63xx/boards/Kconfig"
diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile
new file mode 100644
index 000000000..d89651e53
--- /dev/null
+++ b/arch/mips/bcm63xx/Makefile
@@ -0,0 +1,8 @@
1# SPDX-License-Identifier: GPL-2.0
2obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \
3 setup.o timer.o dev-enet.o dev-flash.o dev-pcmcia.o \
4 dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o dev-wdt.o \
5 dev-usb-usbd.o
6obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
7
8obj-y += boards/
diff --git a/arch/mips/bcm63xx/Platform b/arch/mips/bcm63xx/Platform
new file mode 100644
index 000000000..882dc40f4
--- /dev/null
+++ b/arch/mips/bcm63xx/Platform
@@ -0,0 +1,6 @@
1#
2# Broadcom BCM63XX boards
3#
4cflags-$(CONFIG_BCM63XX) += \
5 -I$(srctree)/arch/mips/include/asm/mach-bcm63xx/
6load-$(CONFIG_BCM63XX) := 0xffffffff80010000
diff --git a/arch/mips/bcm63xx/boards/Kconfig b/arch/mips/bcm63xx/boards/Kconfig
new file mode 100644
index 000000000..492c3bd00
--- /dev/null
+++ b/arch/mips/bcm63xx/boards/Kconfig
@@ -0,0 +1,11 @@
1# SPDX-License-Identifier: GPL-2.0
2choice
3 prompt "Board support"
4 depends on BCM63XX
5 default BOARD_BCM963XX
6
7config BOARD_BCM963XX
8 bool "Generic Broadcom 963xx boards"
9 select SSB
10
11endchoice
diff --git a/arch/mips/bcm63xx/boards/Makefile b/arch/mips/bcm63xx/boards/Makefile
new file mode 100644
index 000000000..a74b9c8d0
--- /dev/null
+++ b/arch/mips/bcm63xx/boards/Makefile
@@ -0,0 +1,2 @@
1# SPDX-License-Identifier: GPL-2.0-only
2obj-$(CONFIG_BOARD_BCM963XX) += board_bcm963xx.o
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
new file mode 100644
index 000000000..01aff80a5
--- /dev/null
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -0,0 +1,911 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
4 * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
5 */
6
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/string.h>
12#include <linux/platform_device.h>
13#include <linux/ssb/ssb.h>
14#include <asm/addrspace.h>
15#include <bcm63xx_board.h>
16#include <bcm63xx_cpu.h>
17#include <bcm63xx_dev_uart.h>
18#include <bcm63xx_regs.h>
19#include <bcm63xx_io.h>
20#include <bcm63xx_nvram.h>
21#include <bcm63xx_dev_pci.h>
22#include <bcm63xx_dev_enet.h>
23#include <bcm63xx_dev_flash.h>
24#include <bcm63xx_dev_hsspi.h>
25#include <bcm63xx_dev_pcmcia.h>
26#include <bcm63xx_dev_spi.h>
27#include <bcm63xx_dev_usb_usbd.h>
28#include <board_bcm963xx.h>
29
30#include <uapi/linux/bcm933xx_hcs.h>
31
32#define HCS_OFFSET_128K 0x20000
33
34static struct board_info board;
35
36/*
37 * known 3368 boards
38 */
39#ifdef CONFIG_BCM63XX_CPU_3368
40static struct board_info __initdata board_cvg834g = {
41 .name = "CVG834G_E15R3921",
42 .expected_cpu_id = 0x3368,
43
44 .ephy_reset_gpio = 36,
45 .ephy_reset_gpio_flags = GPIOF_INIT_HIGH,
46 .has_pci = 1,
47 .has_uart0 = 1,
48 .has_uart1 = 1,
49
50 .has_enet0 = 1,
51 .enet0 = {
52 .has_phy = 1,
53 .use_internal_phy = 1,
54 },
55
56 .leds = {
57 {
58 .name = "CVG834G:green:power",
59 .gpio = 37,
60 .default_trigger= "default-on",
61 },
62 },
63};
64#endif /* CONFIG_BCM63XX_CPU_3368 */
65
66/*
67 * known 6328 boards
68 */
69#ifdef CONFIG_BCM63XX_CPU_6328
70static struct board_info __initdata board_96328avng = {
71 .name = "96328avng",
72 .expected_cpu_id = 0x6328,
73
74 .has_pci = 1,
75 .has_uart0 = 1,
76
77 .has_usbd = 0,
78 .usbd = {
79 .use_fullspeed = 0,
80 .port_no = 0,
81 },
82
83 .leds = {
84 {
85 .name = "96328avng::ppp-fail",
86 .gpio = 2,
87 .active_low = 1,
88 },
89 {
90 .name = "96328avng::power",
91 .gpio = 4,
92 .active_low = 1,
93 .default_trigger = "default-on",
94 },
95 {
96 .name = "96328avng::power-fail",
97 .gpio = 8,
98 .active_low = 1,
99 },
100 {
101 .name = "96328avng::wps",
102 .gpio = 9,
103 .active_low = 1,
104 },
105 {
106 .name = "96328avng::ppp",
107 .gpio = 11,
108 .active_low = 1,
109 },
110 },
111};
112#endif /* CONFIG_BCM63XX_CPU_6328 */
113
114/*
115 * known 6338 boards
116 */
117#ifdef CONFIG_BCM63XX_CPU_6338
118static struct board_info __initdata board_96338gw = {
119 .name = "96338GW",
120 .expected_cpu_id = 0x6338,
121
122 .has_ohci0 = 1,
123 .has_uart0 = 1,
124
125 .has_enet0 = 1,
126 .enet0 = {
127 .force_speed_100 = 1,
128 .force_duplex_full = 1,
129 },
130
131 .leds = {
132 {
133 .name = "adsl",
134 .gpio = 3,
135 .active_low = 1,
136 },
137 {
138 .name = "ses",
139 .gpio = 5,
140 .active_low = 1,
141 },
142 {
143 .name = "ppp-fail",
144 .gpio = 4,
145 .active_low = 1,
146 },
147 {
148 .name = "power",
149 .gpio = 0,
150 .active_low = 1,
151 .default_trigger = "default-on",
152 },
153 {
154 .name = "stop",
155 .gpio = 1,
156 .active_low = 1,
157 }
158 },
159};
160
161static struct board_info __initdata board_96338w = {
162 .name = "96338W",
163 .expected_cpu_id = 0x6338,
164
165 .has_uart0 = 1,
166
167 .has_enet0 = 1,
168 .enet0 = {
169 .force_speed_100 = 1,
170 .force_duplex_full = 1,
171 },
172
173 .leds = {
174 {
175 .name = "adsl",
176 .gpio = 3,
177 .active_low = 1,
178 },
179 {
180 .name = "ses",
181 .gpio = 5,
182 .active_low = 1,
183 },
184 {
185 .name = "ppp-fail",
186 .gpio = 4,
187 .active_low = 1,
188 },
189 {
190 .name = "power",
191 .gpio = 0,
192 .active_low = 1,
193 .default_trigger = "default-on",
194 },
195 {
196 .name = "stop",
197 .gpio = 1,
198 .active_low = 1,
199 },
200 },
201};
202#endif /* CONFIG_BCM63XX_CPU_6338 */
203
204/*
205 * known 6345 boards
206 */
207#ifdef CONFIG_BCM63XX_CPU_6345
208static struct board_info __initdata board_96345gw2 = {
209 .name = "96345GW2",
210 .expected_cpu_id = 0x6345,
211
212 .has_uart0 = 1,
213};
214#endif /* CONFIG_BCM63XX_CPU_6345 */
215
216/*
217 * known 6348 boards
218 */
219#ifdef CONFIG_BCM63XX_CPU_6348
220static struct board_info __initdata board_96348r = {
221 .name = "96348R",
222 .expected_cpu_id = 0x6348,
223
224 .has_pci = 1,
225 .has_uart0 = 1,
226
227 .has_enet0 = 1,
228 .enet0 = {
229 .has_phy = 1,
230 .use_internal_phy = 1,
231 },
232
233 .leds = {
234 {
235 .name = "adsl-fail",
236 .gpio = 2,
237 .active_low = 1,
238 },
239 {
240 .name = "ppp",
241 .gpio = 3,
242 .active_low = 1,
243 },
244 {
245 .name = "ppp-fail",
246 .gpio = 4,
247 .active_low = 1,
248 },
249 {
250 .name = "power",
251 .gpio = 0,
252 .active_low = 1,
253 .default_trigger = "default-on",
254
255 },
256 {
257 .name = "stop",
258 .gpio = 1,
259 .active_low = 1,
260 },
261 },
262};
263
264static struct board_info __initdata board_96348gw_10 = {
265 .name = "96348GW-10",
266 .expected_cpu_id = 0x6348,
267
268 .has_ohci0 = 1,
269 .has_pccard = 1,
270 .has_pci = 1,
271 .has_uart0 = 1,
272
273 .has_enet0 = 1,
274 .enet0 = {
275 .has_phy = 1,
276 .use_internal_phy = 1,
277 },
278
279 .has_enet1 = 1,
280 .enet1 = {
281 .force_speed_100 = 1,
282 .force_duplex_full = 1,
283 },
284
285 .leds = {
286 {
287 .name = "adsl-fail",
288 .gpio = 2,
289 .active_low = 1,
290 },
291 {
292 .name = "ppp",
293 .gpio = 3,
294 .active_low = 1,
295 },
296 {
297 .name = "ppp-fail",
298 .gpio = 4,
299 .active_low = 1,
300 },
301 {
302 .name = "power",
303 .gpio = 0,
304 .active_low = 1,
305 .default_trigger = "default-on",
306 },
307 {
308 .name = "stop",
309 .gpio = 1,
310 .active_low = 1,
311 },
312 },
313};
314
315static struct board_info __initdata board_96348gw_11 = {
316 .name = "96348GW-11",
317 .expected_cpu_id = 0x6348,
318
319 .has_ohci0 = 1,
320 .has_pccard = 1,
321 .has_pci = 1,
322 .has_uart0 = 1,
323
324 .has_enet0 = 1,
325 .enet0 = {
326 .has_phy = 1,
327 .use_internal_phy = 1,
328 },
329
330 .has_enet1 = 1,
331 .enet1 = {
332 .force_speed_100 = 1,
333 .force_duplex_full = 1,
334 },
335
336 .leds = {
337 {
338 .name = "adsl-fail",
339 .gpio = 2,
340 .active_low = 1,
341 },
342 {
343 .name = "ppp",
344 .gpio = 3,
345 .active_low = 1,
346 },
347 {
348 .name = "ppp-fail",
349 .gpio = 4,
350 .active_low = 1,
351 },
352 {
353 .name = "power",
354 .gpio = 0,
355 .active_low = 1,
356 .default_trigger = "default-on",
357 },
358 {
359 .name = "stop",
360 .gpio = 1,
361 .active_low = 1,
362 },
363 },
364};
365
366static struct board_info __initdata board_96348gw = {
367 .name = "96348GW",
368 .expected_cpu_id = 0x6348,
369
370 .has_ohci0 = 1,
371 .has_pci = 1,
372 .has_uart0 = 1,
373
374 .has_enet0 = 1,
375 .enet0 = {
376 .has_phy = 1,
377 .use_internal_phy = 1,
378 },
379
380 .has_enet1 = 1,
381 .enet1 = {
382 .force_speed_100 = 1,
383 .force_duplex_full = 1,
384 },
385
386 .leds = {
387 {
388 .name = "adsl-fail",
389 .gpio = 2,
390 .active_low = 1,
391 },
392 {
393 .name = "ppp",
394 .gpio = 3,
395 .active_low = 1,
396 },
397 {
398 .name = "ppp-fail",
399 .gpio = 4,
400 .active_low = 1,
401 },
402 {
403 .name = "power",
404 .gpio = 0,
405 .active_low = 1,
406 .default_trigger = "default-on",
407 },
408 {
409 .name = "stop",
410 .gpio = 1,
411 .active_low = 1,
412 },
413 },
414};
415
416static struct board_info __initdata board_FAST2404 = {
417 .name = "F@ST2404",
418 .expected_cpu_id = 0x6348,
419
420 .has_ohci0 = 1,
421 .has_pccard = 1,
422 .has_pci = 1,
423 .has_uart0 = 1,
424
425 .has_enet0 = 1,
426 .enet0 = {
427 .has_phy = 1,
428 .use_internal_phy = 1,
429 },
430
431 .has_enet1 = 1,
432 .enet1 = {
433 .force_speed_100 = 1,
434 .force_duplex_full = 1,
435 },
436};
437
438static struct board_info __initdata board_rta1025w_16 = {
439 .name = "RTA1025W_16",
440 .expected_cpu_id = 0x6348,
441
442 .has_pci = 1,
443
444 .has_enet0 = 1,
445 .enet0 = {
446 .has_phy = 1,
447 .use_internal_phy = 1,
448 },
449
450 .has_enet1 = 1,
451 .enet1 = {
452 .force_speed_100 = 1,
453 .force_duplex_full = 1,
454 },
455};
456
457static struct board_info __initdata board_DV201AMR = {
458 .name = "DV201AMR",
459 .expected_cpu_id = 0x6348,
460
461 .has_ohci0 = 1,
462 .has_pci = 1,
463 .has_uart0 = 1,
464
465 .has_enet0 = 1,
466 .enet0 = {
467 .has_phy = 1,
468 .use_internal_phy = 1,
469 },
470
471 .has_enet1 = 1,
472 .enet1 = {
473 .force_speed_100 = 1,
474 .force_duplex_full = 1,
475 },
476};
477
478static struct board_info __initdata board_96348gw_a = {
479 .name = "96348GW-A",
480 .expected_cpu_id = 0x6348,
481
482 .has_ohci0 = 1,
483 .has_pci = 1,
484 .has_uart0 = 1,
485
486 .has_enet0 = 1,
487 .enet0 = {
488 .has_phy = 1,
489 .use_internal_phy = 1,
490 },
491
492 .has_enet1 = 1,
493 .enet1 = {
494 .force_speed_100 = 1,
495 .force_duplex_full = 1,
496 },
497};
498#endif /* CONFIG_BCM63XX_CPU_6348 */
499
500/*
501 * known 6358 boards
502 */
503#ifdef CONFIG_BCM63XX_CPU_6358
504static struct board_info __initdata board_96358vw = {
505 .name = "96358VW",
506 .expected_cpu_id = 0x6358,
507
508 .has_ehci0 = 1,
509 .has_ohci0 = 1,
510 .has_pccard = 1,
511 .has_pci = 1,
512 .has_uart0 = 1,
513
514 .has_enet0 = 1,
515 .enet0 = {
516 .has_phy = 1,
517 .use_internal_phy = 1,
518 },
519
520 .has_enet1 = 1,
521 .enet1 = {
522 .force_speed_100 = 1,
523 .force_duplex_full = 1,
524 },
525
526 .leds = {
527 {
528 .name = "adsl-fail",
529 .gpio = 15,
530 .active_low = 1,
531 },
532 {
533 .name = "ppp",
534 .gpio = 22,
535 .active_low = 1,
536 },
537 {
538 .name = "ppp-fail",
539 .gpio = 23,
540 .active_low = 1,
541 },
542 {
543 .name = "power",
544 .gpio = 4,
545 .default_trigger = "default-on",
546 },
547 {
548 .name = "stop",
549 .gpio = 5,
550 },
551 },
552};
553
554static struct board_info __initdata board_96358vw2 = {
555 .name = "96358VW2",
556 .expected_cpu_id = 0x6358,
557
558 .has_ehci0 = 1,
559 .has_ohci0 = 1,
560 .has_pccard = 1,
561 .has_pci = 1,
562 .has_uart0 = 1,
563
564 .has_enet0 = 1,
565 .enet0 = {
566 .has_phy = 1,
567 .use_internal_phy = 1,
568 },
569
570 .has_enet1 = 1,
571 .enet1 = {
572 .force_speed_100 = 1,
573 .force_duplex_full = 1,
574 },
575
576 .leds = {
577 {
578 .name = "adsl",
579 .gpio = 22,
580 .active_low = 1,
581 },
582 {
583 .name = "ppp-fail",
584 .gpio = 23,
585 },
586 {
587 .name = "power",
588 .gpio = 5,
589 .active_low = 1,
590 .default_trigger = "default-on",
591 },
592 {
593 .name = "stop",
594 .gpio = 4,
595 .active_low = 1,
596 },
597 },
598};
599
600static struct board_info __initdata board_AGPFS0 = {
601 .name = "AGPF-S0",
602 .expected_cpu_id = 0x6358,
603
604 .has_ehci0 = 1,
605 .has_ohci0 = 1,
606 .has_pci = 1,
607 .has_uart0 = 1,
608
609 .has_enet0 = 1,
610 .enet0 = {
611 .has_phy = 1,
612 .use_internal_phy = 1,
613 },
614
615 .has_enet1 = 1,
616 .enet1 = {
617 .force_speed_100 = 1,
618 .force_duplex_full = 1,
619 },
620};
621
622static struct board_info __initdata board_DWVS0 = {
623 .name = "DWV-S0",
624 .expected_cpu_id = 0x6358,
625
626 .has_ehci0 = 1,
627 .has_ohci0 = 1,
628 .has_pci = 1,
629
630 .has_enet0 = 1,
631 .enet0 = {
632 .has_phy = 1,
633 .use_internal_phy = 1,
634 },
635
636 .has_enet1 = 1,
637 .enet1 = {
638 .force_speed_100 = 1,
639 .force_duplex_full = 1,
640 },
641};
642#endif /* CONFIG_BCM63XX_CPU_6358 */
643
644/*
645 * all boards
646 */
647static const struct board_info __initconst *bcm963xx_boards[] = {
648#ifdef CONFIG_BCM63XX_CPU_3368
649 &board_cvg834g,
650#endif /* CONFIG_BCM63XX_CPU_3368 */
651#ifdef CONFIG_BCM63XX_CPU_6328
652 &board_96328avng,
653#endif /* CONFIG_BCM63XX_CPU_6328 */
654#ifdef CONFIG_BCM63XX_CPU_6338
655 &board_96338gw,
656 &board_96338w,
657#endif /* CONFIG_BCM63XX_CPU_6338 */
658#ifdef CONFIG_BCM63XX_CPU_6345
659 &board_96345gw2,
660#endif /* CONFIG_BCM63XX_CPU_6345 */
661#ifdef CONFIG_BCM63XX_CPU_6348
662 &board_96348r,
663 &board_96348gw,
664 &board_96348gw_10,
665 &board_96348gw_11,
666 &board_FAST2404,
667 &board_DV201AMR,
668 &board_96348gw_a,
669 &board_rta1025w_16,
670#endif /* CONFIG_BCM63XX_CPU_6348 */
671#ifdef CONFIG_BCM63XX_CPU_6358
672 &board_96358vw,
673 &board_96358vw2,
674 &board_AGPFS0,
675 &board_DWVS0,
676#endif /* CONFIG_BCM63XX_CPU_6358 */
677};
678
679/*
680 * Register a sane SPROMv2 to make the on-board
681 * bcm4318 WLAN work
682 */
683#ifdef CONFIG_SSB_PCIHOST
684static struct ssb_sprom bcm63xx_sprom = {
685 .revision = 0x02,
686 .board_rev = 0x17,
687 .country_code = 0x0,
688 .ant_available_bg = 0x3,
689 .pa0b0 = 0x15ae,
690 .pa0b1 = 0xfa85,
691 .pa0b2 = 0xfe8d,
692 .pa1b0 = 0xffff,
693 .pa1b1 = 0xffff,
694 .pa1b2 = 0xffff,
695 .gpio0 = 0xff,
696 .gpio1 = 0xff,
697 .gpio2 = 0xff,
698 .gpio3 = 0xff,
699 .maxpwr_bg = 0x004c,
700 .itssi_bg = 0x00,
701 .boardflags_lo = 0x2848,
702 .boardflags_hi = 0x0000,
703};
704
705int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
706{
707 if (bus->bustype == SSB_BUSTYPE_PCI) {
708 memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
709 return 0;
710 } else {
711 pr_err("unable to fill SPROM for given bustype\n");
712 return -EINVAL;
713 }
714}
715#endif /* CONFIG_SSB_PCIHOST */
716
717/*
718 * return board name for /proc/cpuinfo
719 */
720const char *board_get_name(void)
721{
722 return board.name;
723}
724
725/*
726 * early init callback, read nvram data from flash and checksum it
727 */
728void __init board_prom_init(void)
729{
730 unsigned int i;
731 u8 *boot_addr, *cfe;
732 char cfe_version[32];
733 char *board_name = NULL;
734 u32 val;
735 struct bcm_hcs *hcs;
736
737 /* read base address of boot chip select (0)
738 * 6328/6362 do not have MPI but boot from a fixed address
739 */
740 if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
741 val = 0x18000000;
742 } else {
743 val = bcm_mpi_readl(MPI_CSBASE_REG(0));
744 val &= MPI_CSBASE_BASE_MASK;
745 }
746 boot_addr = (u8 *)KSEG1ADDR(val);
747
748 /* dump cfe version */
749 cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET;
750 if (strstarts(cfe, "cfe-")) {
751 if(cfe[4] == 'v') {
752 if(cfe[5] == 'd')
753 snprintf(cfe_version, 11, "%s",
754 (char *) &cfe[5]);
755 else if (cfe[10] > 0)
756 snprintf(cfe_version, sizeof(cfe_version),
757 "%u.%u.%u-%u.%u-%u", cfe[5], cfe[6],
758 cfe[7], cfe[8], cfe[9], cfe[10]);
759 else
760 snprintf(cfe_version, sizeof(cfe_version),
761 "%u.%u.%u-%u.%u", cfe[5], cfe[6],
762 cfe[7], cfe[8], cfe[9]);
763 } else {
764 snprintf(cfe_version, 12, "%s", (char *) &cfe[4]);
765 }
766 } else {
767 strcpy(cfe_version, "unknown");
768 }
769 pr_info("CFE version: %s\n", cfe_version);
770
771 bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET);
772
773 if (BCMCPU_IS_3368()) {
774 hcs = (struct bcm_hcs *)boot_addr;
775 board_name = hcs->filename;
776 } else {
777 board_name = bcm63xx_nvram_get_name();
778 }
779 /* find board by name */
780 for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) {
781 if (strncmp(board_name, bcm963xx_boards[i]->name, 16))
782 continue;
783 /* copy, board desc array is marked initdata */
784 memcpy(&board, bcm963xx_boards[i], sizeof(board));
785 break;
786 }
787
788 /* bail out if board is not found, will complain later */
789 if (!board.name[0]) {
790 char name[17];
791 memcpy(name, board_name, 16);
792 name[16] = 0;
793 pr_err("unknown bcm963xx board: %s\n", name);
794 return;
795 }
796
797 /* setup pin multiplexing depending on board enabled device,
798 * this has to be done this early since PCI init is done
799 * inside arch_initcall */
800 val = 0;
801
802#ifdef CONFIG_PCI
803 if (board.has_pci) {
804 bcm63xx_pci_enabled = 1;
805 if (BCMCPU_IS_6348())
806 val |= GPIO_MODE_6348_G2_PCI;
807 }
808#endif /* CONFIG_PCI */
809
810 if (board.has_pccard) {
811 if (BCMCPU_IS_6348())
812 val |= GPIO_MODE_6348_G1_MII_PCCARD;
813 }
814
815 if (board.has_enet0 && !board.enet0.use_internal_phy) {
816 if (BCMCPU_IS_6348())
817 val |= GPIO_MODE_6348_G3_EXT_MII |
818 GPIO_MODE_6348_G0_EXT_MII;
819 }
820
821 if (board.has_enet1 && !board.enet1.use_internal_phy) {
822 if (BCMCPU_IS_6348())
823 val |= GPIO_MODE_6348_G3_EXT_MII |
824 GPIO_MODE_6348_G0_EXT_MII;
825 }
826
827 bcm_gpio_writel(val, GPIO_MODE_REG);
828}
829
830/*
831 * second stage init callback, good time to panic if we couldn't
832 * identify on which board we're running since early printk is working
833 */
834void __init board_setup(void)
835{
836 if (!board.name[0])
837 panic("unable to detect bcm963xx board");
838 pr_info("board name: %s\n", board.name);
839
840 /* make sure we're running on expected cpu */
841 if (bcm63xx_get_cpu_id() != board.expected_cpu_id)
842 panic("unexpected CPU for bcm963xx board");
843}
844
845static struct gpio_led_platform_data bcm63xx_led_data;
846
847static struct platform_device bcm63xx_gpio_leds = {
848 .name = "leds-gpio",
849 .id = 0,
850 .dev.platform_data = &bcm63xx_led_data,
851};
852
853/*
854 * third stage init callback, register all board devices.
855 */
856int __init board_register_devices(void)
857{
858 if (board.has_uart0)
859 bcm63xx_uart_register(0);
860
861 if (board.has_uart1)
862 bcm63xx_uart_register(1);
863
864 if (board.has_pccard)
865 bcm63xx_pcmcia_register();
866
867 if (board.has_enet0 &&
868 !bcm63xx_nvram_get_mac_address(board.enet0.mac_addr))
869 bcm63xx_enet_register(0, &board.enet0);
870
871 if (board.has_enet1 &&
872 !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
873 bcm63xx_enet_register(1, &board.enet1);
874
875 if (board.has_enetsw &&
876 !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
877 bcm63xx_enetsw_register(&board.enetsw);
878
879 if (board.has_usbd)
880 bcm63xx_usbd_register(&board.usbd);
881
882 /* Generate MAC address for WLAN and register our SPROM,
883 * do this after registering enet devices
884 */
885#ifdef CONFIG_SSB_PCIHOST
886 if (!bcm63xx_nvram_get_mac_address(bcm63xx_sprom.il0mac)) {
887 memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
888 memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
889 if (ssb_arch_register_fallback_sprom(
890 &bcm63xx_get_fallback_sprom) < 0)
891 pr_err("failed to register fallback SPROM\n");
892 }
893#endif /* CONFIG_SSB_PCIHOST */
894
895 bcm63xx_spi_register();
896
897 bcm63xx_hsspi_register();
898
899 bcm63xx_flash_register();
900
901 bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
902 bcm63xx_led_data.leds = board.leds;
903
904 platform_device_register(&bcm63xx_gpio_leds);
905
906 if (board.ephy_reset_gpio && board.ephy_reset_gpio_flags)
907 gpio_request_one(board.ephy_reset_gpio,
908 board.ephy_reset_gpio_flags, "ephy-reset");
909
910 return 0;
911}
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
new file mode 100644
index 000000000..f183c4550
--- /dev/null
+++ b/arch/mips/bcm63xx/clk.c
@@ -0,0 +1,579 @@
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/export.h>
11#include <linux/mutex.h>
12#include <linux/err.h>
13#include <linux/clk.h>
14#include <linux/clkdev.h>
15#include <linux/delay.h>
16#include <bcm63xx_cpu.h>
17#include <bcm63xx_io.h>
18#include <bcm63xx_regs.h>
19#include <bcm63xx_reset.h>
20
21struct clk {
22 void (*set)(struct clk *, int);
23 unsigned int rate;
24 unsigned int usage;
25 int id;
26};
27
28static DEFINE_MUTEX(clocks_mutex);
29
30
31static void clk_enable_unlocked(struct clk *clk)
32{
33 if (clk->set && (clk->usage++) == 0)
34 clk->set(clk, 1);
35}
36
37static void clk_disable_unlocked(struct clk *clk)
38{
39 if (clk->set && (--clk->usage) == 0)
40 clk->set(clk, 0);
41}
42
43static void bcm_hwclock_set(u32 mask, int enable)
44{
45 u32 reg;
46
47 reg = bcm_perf_readl(PERF_CKCTL_REG);
48 if (enable)
49 reg |= mask;
50 else
51 reg &= ~mask;
52 bcm_perf_writel(reg, PERF_CKCTL_REG);
53}
54
55/*
56 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
57 */
58static void enet_misc_set(struct clk *clk, int enable)
59{
60 u32 mask;
61
62 if (BCMCPU_IS_6338())
63 mask = CKCTL_6338_ENET_EN;
64 else if (BCMCPU_IS_6345())
65 mask = CKCTL_6345_ENET_EN;
66 else if (BCMCPU_IS_6348())
67 mask = CKCTL_6348_ENET_EN;
68 else
69 /* BCMCPU_IS_6358 */
70 mask = CKCTL_6358_EMUSB_EN;
71 bcm_hwclock_set(mask, enable);
72}
73
74static struct clk clk_enet_misc = {
75 .set = enet_misc_set,
76};
77
78/*
79 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
80 * clocks
81 */
82static void enetx_set(struct clk *clk, int enable)
83{
84 if (enable)
85 clk_enable_unlocked(&clk_enet_misc);
86 else
87 clk_disable_unlocked(&clk_enet_misc);
88
89 if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
90 u32 mask;
91
92 if (clk->id == 0)
93 mask = CKCTL_6358_ENET0_EN;
94 else
95 mask = CKCTL_6358_ENET1_EN;
96 bcm_hwclock_set(mask, enable);
97 }
98}
99
100static struct clk clk_enet0 = {
101 .id = 0,
102 .set = enetx_set,
103};
104
105static struct clk clk_enet1 = {
106 .id = 1,
107 .set = enetx_set,
108};
109
110/*
111 * Ethernet PHY clock
112 */
113static void ephy_set(struct clk *clk, int enable)
114{
115 if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
116 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
117}
118
119
120static struct clk clk_ephy = {
121 .set = ephy_set,
122};
123
124/*
125 * Ethernet switch SAR clock
126 */
127static void swpkt_sar_set(struct clk *clk, int enable)
128{
129 if (BCMCPU_IS_6368())
130 bcm_hwclock_set(CKCTL_6368_SWPKT_SAR_EN, enable);
131 else
132 return;
133}
134
135static struct clk clk_swpkt_sar = {
136 .set = swpkt_sar_set,
137};
138
139/*
140 * Ethernet switch USB clock
141 */
142static void swpkt_usb_set(struct clk *clk, int enable)
143{
144 if (BCMCPU_IS_6368())
145 bcm_hwclock_set(CKCTL_6368_SWPKT_USB_EN, enable);
146 else
147 return;
148}
149
150static struct clk clk_swpkt_usb = {
151 .set = swpkt_usb_set,
152};
153
154/*
155 * Ethernet switch clock
156 */
157static void enetsw_set(struct clk *clk, int enable)
158{
159 if (BCMCPU_IS_6328()) {
160 bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable);
161 } else if (BCMCPU_IS_6362()) {
162 bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable);
163 } else if (BCMCPU_IS_6368()) {
164 if (enable) {
165 clk_enable_unlocked(&clk_swpkt_sar);
166 clk_enable_unlocked(&clk_swpkt_usb);
167 } else {
168 clk_disable_unlocked(&clk_swpkt_usb);
169 clk_disable_unlocked(&clk_swpkt_sar);
170 }
171 bcm_hwclock_set(CKCTL_6368_ROBOSW_EN, enable);
172 } else {
173 return;
174 }
175
176 if (enable) {
177 /* reset switch core afer clock change */
178 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
179 msleep(10);
180 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
181 msleep(10);
182 }
183}
184
185static struct clk clk_enetsw = {
186 .set = enetsw_set,
187};
188
189/*
190 * PCM clock
191 */
192static void pcm_set(struct clk *clk, int enable)
193{
194 if (BCMCPU_IS_3368())
195 bcm_hwclock_set(CKCTL_3368_PCM_EN, enable);
196 if (BCMCPU_IS_6358())
197 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
198}
199
200static struct clk clk_pcm = {
201 .set = pcm_set,
202};
203
204/*
205 * USB host clock
206 */
207static void usbh_set(struct clk *clk, int enable)
208{
209 if (BCMCPU_IS_6328())
210 bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
211 else if (BCMCPU_IS_6348())
212 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
213 else if (BCMCPU_IS_6362())
214 bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
215 else if (BCMCPU_IS_6368())
216 bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
217}
218
219static struct clk clk_usbh = {
220 .set = usbh_set,
221};
222
223/*
224 * USB device clock
225 */
226static void usbd_set(struct clk *clk, int enable)
227{
228 if (BCMCPU_IS_6328())
229 bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
230 else if (BCMCPU_IS_6362())
231 bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
232 else if (BCMCPU_IS_6368())
233 bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
234}
235
236static struct clk clk_usbd = {
237 .set = usbd_set,
238};
239
240/*
241 * SPI clock
242 */
243static void spi_set(struct clk *clk, int enable)
244{
245 u32 mask;
246
247 if (BCMCPU_IS_6338())
248 mask = CKCTL_6338_SPI_EN;
249 else if (BCMCPU_IS_6348())
250 mask = CKCTL_6348_SPI_EN;
251 else if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
252 mask = CKCTL_6358_SPI_EN;
253 else if (BCMCPU_IS_6362())
254 mask = CKCTL_6362_SPI_EN;
255 else
256 /* BCMCPU_IS_6368 */
257 mask = CKCTL_6368_SPI_EN;
258 bcm_hwclock_set(mask, enable);
259}
260
261static struct clk clk_spi = {
262 .set = spi_set,
263};
264
265/*
266 * HSSPI clock
267 */
268static void hsspi_set(struct clk *clk, int enable)
269{
270 u32 mask;
271
272 if (BCMCPU_IS_6328())
273 mask = CKCTL_6328_HSSPI_EN;
274 else if (BCMCPU_IS_6362())
275 mask = CKCTL_6362_HSSPI_EN;
276 else
277 return;
278
279 bcm_hwclock_set(mask, enable);
280}
281
282static struct clk clk_hsspi = {
283 .set = hsspi_set,
284};
285
286/*
287 * HSSPI PLL
288 */
289static struct clk clk_hsspi_pll;
290
291/*
292 * XTM clock
293 */
294static void xtm_set(struct clk *clk, int enable)
295{
296 if (!BCMCPU_IS_6368())
297 return;
298
299 if (enable)
300 clk_enable_unlocked(&clk_swpkt_sar);
301 else
302 clk_disable_unlocked(&clk_swpkt_sar);
303
304 bcm_hwclock_set(CKCTL_6368_SAR_EN, enable);
305
306 if (enable) {
307 /* reset sar core afer clock change */
308 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
309 mdelay(1);
310 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
311 mdelay(1);
312 }
313}
314
315
316static struct clk clk_xtm = {
317 .set = xtm_set,
318};
319
320/*
321 * IPsec clock
322 */
323static void ipsec_set(struct clk *clk, int enable)
324{
325 if (BCMCPU_IS_6362())
326 bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable);
327 else if (BCMCPU_IS_6368())
328 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
329}
330
331static struct clk clk_ipsec = {
332 .set = ipsec_set,
333};
334
335/*
336 * PCIe clock
337 */
338
339static void pcie_set(struct clk *clk, int enable)
340{
341 if (BCMCPU_IS_6328())
342 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
343 else if (BCMCPU_IS_6362())
344 bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
345}
346
347static struct clk clk_pcie = {
348 .set = pcie_set,
349};
350
351/*
352 * Internal peripheral clock
353 */
354static struct clk clk_periph = {
355 .rate = (50 * 1000 * 1000),
356};
357
358
359/*
360 * Linux clock API implementation
361 */
362int clk_enable(struct clk *clk)
363{
364 if (!clk)
365 return 0;
366 mutex_lock(&clocks_mutex);
367 clk_enable_unlocked(clk);
368 mutex_unlock(&clocks_mutex);
369 return 0;
370}
371
372EXPORT_SYMBOL(clk_enable);
373
374void clk_disable(struct clk *clk)
375{
376 if (!clk)
377 return;
378
379 mutex_lock(&clocks_mutex);
380 clk_disable_unlocked(clk);
381 mutex_unlock(&clocks_mutex);
382}
383
384EXPORT_SYMBOL(clk_disable);
385
386struct clk *clk_get_parent(struct clk *clk)
387{
388 return NULL;
389}
390EXPORT_SYMBOL(clk_get_parent);
391
392int clk_set_parent(struct clk *clk, struct clk *parent)
393{
394 return 0;
395}
396EXPORT_SYMBOL(clk_set_parent);
397
398unsigned long clk_get_rate(struct clk *clk)
399{
400 if (!clk)
401 return 0;
402
403 return clk->rate;
404}
405
406EXPORT_SYMBOL(clk_get_rate);
407
408int clk_set_rate(struct clk *clk, unsigned long rate)
409{
410 return 0;
411}
412EXPORT_SYMBOL_GPL(clk_set_rate);
413
414long clk_round_rate(struct clk *clk, unsigned long rate)
415{
416 return 0;
417}
418EXPORT_SYMBOL_GPL(clk_round_rate);
419
420static struct clk_lookup bcm3368_clks[] = {
421 /* fixed rate clocks */
422 CLKDEV_INIT(NULL, "periph", &clk_periph),
423 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
424 CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
425 /* gated clocks */
426 CLKDEV_INIT(NULL, "enet0", &clk_enet0),
427 CLKDEV_INIT(NULL, "enet1", &clk_enet1),
428 CLKDEV_INIT(NULL, "ephy", &clk_ephy),
429 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
430 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
431 CLKDEV_INIT(NULL, "spi", &clk_spi),
432 CLKDEV_INIT(NULL, "pcm", &clk_pcm),
433 CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet0),
434 CLKDEV_INIT("bcm63xx_enet.1", "enet", &clk_enet1),
435};
436
437static struct clk_lookup bcm6328_clks[] = {
438 /* fixed rate clocks */
439 CLKDEV_INIT(NULL, "periph", &clk_periph),
440 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
441 CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
442 CLKDEV_INIT("bcm63xx-hsspi.0", "pll", &clk_hsspi_pll),
443 /* gated clocks */
444 CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
445 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
446 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
447 CLKDEV_INIT(NULL, "hsspi", &clk_hsspi),
448 CLKDEV_INIT(NULL, "pcie", &clk_pcie),
449};
450
451static struct clk_lookup bcm6338_clks[] = {
452 /* fixed rate clocks */
453 CLKDEV_INIT(NULL, "periph", &clk_periph),
454 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
455 /* gated clocks */
456 CLKDEV_INIT(NULL, "enet0", &clk_enet0),
457 CLKDEV_INIT(NULL, "enet1", &clk_enet1),
458 CLKDEV_INIT(NULL, "ephy", &clk_ephy),
459 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
460 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
461 CLKDEV_INIT(NULL, "spi", &clk_spi),
462 CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet_misc),
463};
464
465static struct clk_lookup bcm6345_clks[] = {
466 /* fixed rate clocks */
467 CLKDEV_INIT(NULL, "periph", &clk_periph),
468 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
469 /* gated clocks */
470 CLKDEV_INIT(NULL, "enet0", &clk_enet0),
471 CLKDEV_INIT(NULL, "enet1", &clk_enet1),
472 CLKDEV_INIT(NULL, "ephy", &clk_ephy),
473 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
474 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
475 CLKDEV_INIT(NULL, "spi", &clk_spi),
476 CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet_misc),
477};
478
479static struct clk_lookup bcm6348_clks[] = {
480 /* fixed rate clocks */
481 CLKDEV_INIT(NULL, "periph", &clk_periph),
482 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
483 /* gated clocks */
484 CLKDEV_INIT(NULL, "enet0", &clk_enet0),
485 CLKDEV_INIT(NULL, "enet1", &clk_enet1),
486 CLKDEV_INIT(NULL, "ephy", &clk_ephy),
487 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
488 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
489 CLKDEV_INIT(NULL, "spi", &clk_spi),
490 CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet_misc),
491 CLKDEV_INIT("bcm63xx_enet.1", "enet", &clk_enet_misc),
492};
493
494static struct clk_lookup bcm6358_clks[] = {
495 /* fixed rate clocks */
496 CLKDEV_INIT(NULL, "periph", &clk_periph),
497 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
498 CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
499 /* gated clocks */
500 CLKDEV_INIT(NULL, "enet0", &clk_enet0),
501 CLKDEV_INIT(NULL, "enet1", &clk_enet1),
502 CLKDEV_INIT(NULL, "ephy", &clk_ephy),
503 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
504 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
505 CLKDEV_INIT(NULL, "spi", &clk_spi),
506 CLKDEV_INIT(NULL, "pcm", &clk_pcm),
507 CLKDEV_INIT(NULL, "swpkt_sar", &clk_swpkt_sar),
508 CLKDEV_INIT(NULL, "swpkt_usb", &clk_swpkt_usb),
509 CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet0),
510 CLKDEV_INIT("bcm63xx_enet.1", "enet", &clk_enet1),
511};
512
513static struct clk_lookup bcm6362_clks[] = {
514 /* fixed rate clocks */
515 CLKDEV_INIT(NULL, "periph", &clk_periph),
516 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
517 CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
518 CLKDEV_INIT("bcm63xx-hsspi.0", "pll", &clk_hsspi_pll),
519 /* gated clocks */
520 CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
521 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
522 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
523 CLKDEV_INIT(NULL, "spi", &clk_spi),
524 CLKDEV_INIT(NULL, "hsspi", &clk_hsspi),
525 CLKDEV_INIT(NULL, "pcie", &clk_pcie),
526 CLKDEV_INIT(NULL, "ipsec", &clk_ipsec),
527};
528
529static struct clk_lookup bcm6368_clks[] = {
530 /* fixed rate clocks */
531 CLKDEV_INIT(NULL, "periph", &clk_periph),
532 CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
533 CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
534 /* gated clocks */
535 CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
536 CLKDEV_INIT(NULL, "usbh", &clk_usbh),
537 CLKDEV_INIT(NULL, "usbd", &clk_usbd),
538 CLKDEV_INIT(NULL, "spi", &clk_spi),
539 CLKDEV_INIT(NULL, "xtm", &clk_xtm),
540 CLKDEV_INIT(NULL, "ipsec", &clk_ipsec),
541};
542
543#define HSSPI_PLL_HZ_6328 133333333
544#define HSSPI_PLL_HZ_6362 400000000
545
546static int __init bcm63xx_clk_init(void)
547{
548 switch (bcm63xx_get_cpu_id()) {
549 case BCM3368_CPU_ID:
550 clkdev_add_table(bcm3368_clks, ARRAY_SIZE(bcm3368_clks));
551 break;
552 case BCM6328_CPU_ID:
553 clk_hsspi_pll.rate = HSSPI_PLL_HZ_6328;
554 clkdev_add_table(bcm6328_clks, ARRAY_SIZE(bcm6328_clks));
555 break;
556 case BCM6338_CPU_ID:
557 clkdev_add_table(bcm6338_clks, ARRAY_SIZE(bcm6338_clks));
558 break;
559 case BCM6345_CPU_ID:
560 clkdev_add_table(bcm6345_clks, ARRAY_SIZE(bcm6345_clks));
561 break;
562 case BCM6348_CPU_ID:
563 clkdev_add_table(bcm6348_clks, ARRAY_SIZE(bcm6348_clks));
564 break;
565 case BCM6358_CPU_ID:
566 clkdev_add_table(bcm6358_clks, ARRAY_SIZE(bcm6358_clks));
567 break;
568 case BCM6362_CPU_ID:
569 clk_hsspi_pll.rate = HSSPI_PLL_HZ_6362;
570 clkdev_add_table(bcm6362_clks, ARRAY_SIZE(bcm6362_clks));
571 break;
572 case BCM6368_CPU_ID:
573 clkdev_add_table(bcm6368_clks, ARRAY_SIZE(bcm6368_clks));
574 break;
575 }
576
577 return 0;
578}
579arch_initcall(bcm63xx_clk_init);
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
new file mode 100644
index 000000000..8e3e199dd
--- /dev/null
+++ b/arch/mips/bcm63xx/cpu.c
@@ -0,0 +1,385 @@
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/export.h>
12#include <linux/cpu.h>
13#include <asm/cpu.h>
14#include <asm/cpu-info.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
21const unsigned long *bcm63xx_regs_base;
22EXPORT_SYMBOL(bcm63xx_regs_base);
23
24const int *bcm63xx_irqs;
25EXPORT_SYMBOL(bcm63xx_irqs);
26
27u16 bcm63xx_cpu_id __read_mostly;
28EXPORT_SYMBOL(bcm63xx_cpu_id);
29
30static u8 bcm63xx_cpu_rev;
31static unsigned int bcm63xx_cpu_freq;
32static unsigned int bcm63xx_memory_size;
33
34static const unsigned long bcm3368_regs_base[] = {
35 __GEN_CPU_REGS_TABLE(3368)
36};
37
38static const int bcm3368_irqs[] = {
39 __GEN_CPU_IRQ_TABLE(3368)
40};
41
42static const unsigned long bcm6328_regs_base[] = {
43 __GEN_CPU_REGS_TABLE(6328)
44};
45
46static const int bcm6328_irqs[] = {
47 __GEN_CPU_IRQ_TABLE(6328)
48};
49
50static const unsigned long bcm6338_regs_base[] = {
51 __GEN_CPU_REGS_TABLE(6338)
52};
53
54static const int bcm6338_irqs[] = {
55 __GEN_CPU_IRQ_TABLE(6338)
56};
57
58static const unsigned long bcm6345_regs_base[] = {
59 __GEN_CPU_REGS_TABLE(6345)
60};
61
62static const int bcm6345_irqs[] = {
63 __GEN_CPU_IRQ_TABLE(6345)
64};
65
66static const unsigned long bcm6348_regs_base[] = {
67 __GEN_CPU_REGS_TABLE(6348)
68};
69
70static const int bcm6348_irqs[] = {
71 __GEN_CPU_IRQ_TABLE(6348)
72
73};
74
75static const unsigned long bcm6358_regs_base[] = {
76 __GEN_CPU_REGS_TABLE(6358)
77};
78
79static const int bcm6358_irqs[] = {
80 __GEN_CPU_IRQ_TABLE(6358)
81
82};
83
84static const unsigned long bcm6362_regs_base[] = {
85 __GEN_CPU_REGS_TABLE(6362)
86};
87
88static const int bcm6362_irqs[] = {
89 __GEN_CPU_IRQ_TABLE(6362)
90
91};
92
93static const unsigned long bcm6368_regs_base[] = {
94 __GEN_CPU_REGS_TABLE(6368)
95};
96
97static const int bcm6368_irqs[] = {
98 __GEN_CPU_IRQ_TABLE(6368)
99
100};
101
102u8 bcm63xx_get_cpu_rev(void)
103{
104 return bcm63xx_cpu_rev;
105}
106
107EXPORT_SYMBOL(bcm63xx_get_cpu_rev);
108
109unsigned int bcm63xx_get_cpu_freq(void)
110{
111 return bcm63xx_cpu_freq;
112}
113
114unsigned int bcm63xx_get_memory_size(void)
115{
116 return bcm63xx_memory_size;
117}
118
119static unsigned int detect_cpu_clock(void)
120{
121 u16 cpu_id = bcm63xx_get_cpu_id();
122
123 switch (cpu_id) {
124 case BCM3368_CPU_ID:
125 return 300000000;
126
127 case BCM6328_CPU_ID:
128 {
129 unsigned int tmp, mips_pll_fcvo;
130
131 tmp = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
132 mips_pll_fcvo = (tmp & STRAPBUS_6328_FCVO_MASK)
133 >> STRAPBUS_6328_FCVO_SHIFT;
134
135 switch (mips_pll_fcvo) {
136 case 0x12:
137 case 0x14:
138 case 0x19:
139 return 160000000;
140 case 0x1c:
141 return 192000000;
142 case 0x13:
143 case 0x15:
144 return 200000000;
145 case 0x1a:
146 return 384000000;
147 case 0x16:
148 return 400000000;
149 default:
150 return 320000000;
151 }
152
153 }
154 case BCM6338_CPU_ID:
155 /* BCM6338 has a fixed 240 Mhz frequency */
156 return 240000000;
157
158 case BCM6345_CPU_ID:
159 /* BCM6345 has a fixed 140Mhz frequency */
160 return 140000000;
161
162 case BCM6348_CPU_ID:
163 {
164 unsigned int tmp, n1, n2, m1;
165
166 /* 16MHz * (N1 + 1) * (N2 + 2) / (M1_CPU + 1) */
167 tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG);
168 n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT;
169 n2 = (tmp & MIPSPLLCTL_N2_MASK) >> MIPSPLLCTL_N2_SHIFT;
170 m1 = (tmp & MIPSPLLCTL_M1CPU_MASK) >> MIPSPLLCTL_M1CPU_SHIFT;
171 n1 += 1;
172 n2 += 2;
173 m1 += 1;
174 return (16 * 1000000 * n1 * n2) / m1;
175 }
176
177 case BCM6358_CPU_ID:
178 {
179 unsigned int tmp, n1, n2, m1;
180
181 /* 16MHz * N1 * N2 / M1_CPU */
182 tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_REG);
183 n1 = (tmp & DMIPSPLLCFG_N1_MASK) >> DMIPSPLLCFG_N1_SHIFT;
184 n2 = (tmp & DMIPSPLLCFG_N2_MASK) >> DMIPSPLLCFG_N2_SHIFT;
185 m1 = (tmp & DMIPSPLLCFG_M1_MASK) >> DMIPSPLLCFG_M1_SHIFT;
186 return (16 * 1000000 * n1 * n2) / m1;
187 }
188
189 case BCM6362_CPU_ID:
190 {
191 unsigned int tmp, mips_pll_fcvo;
192
193 tmp = bcm_misc_readl(MISC_STRAPBUS_6362_REG);
194 mips_pll_fcvo = (tmp & STRAPBUS_6362_FCVO_MASK)
195 >> STRAPBUS_6362_FCVO_SHIFT;
196 switch (mips_pll_fcvo) {
197 case 0x03:
198 case 0x0b:
199 case 0x13:
200 case 0x1b:
201 return 240000000;
202 case 0x04:
203 case 0x0c:
204 case 0x14:
205 case 0x1c:
206 return 160000000;
207 case 0x05:
208 case 0x0e:
209 case 0x16:
210 case 0x1e:
211 case 0x1f:
212 return 400000000;
213 case 0x06:
214 return 440000000;
215 case 0x07:
216 case 0x17:
217 return 384000000;
218 case 0x15:
219 case 0x1d:
220 return 200000000;
221 default:
222 return 320000000;
223 }
224 }
225 case BCM6368_CPU_ID:
226 {
227 unsigned int tmp, p1, p2, ndiv, m1;
228
229 /* (64MHz / P1) * P2 * NDIV / M1_CPU */
230 tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_6368_REG);
231
232 p1 = (tmp & DMIPSPLLCFG_6368_P1_MASK) >>
233 DMIPSPLLCFG_6368_P1_SHIFT;
234
235 p2 = (tmp & DMIPSPLLCFG_6368_P2_MASK) >>
236 DMIPSPLLCFG_6368_P2_SHIFT;
237
238 ndiv = (tmp & DMIPSPLLCFG_6368_NDIV_MASK) >>
239 DMIPSPLLCFG_6368_NDIV_SHIFT;
240
241 tmp = bcm_ddr_readl(DDR_DMIPSPLLDIV_6368_REG);
242 m1 = (tmp & DMIPSPLLDIV_6368_MDIV_MASK) >>
243 DMIPSPLLDIV_6368_MDIV_SHIFT;
244
245 return (((64 * 1000000) / p1) * p2 * ndiv) / m1;
246 }
247
248 default:
249 panic("Failed to detect clock for CPU with id=%04X\n", cpu_id);
250 }
251}
252
253/*
254 * attempt to detect the amount of memory installed
255 */
256static unsigned int detect_memory_size(void)
257{
258 unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
259 u32 val;
260
261 if (BCMCPU_IS_6328() || BCMCPU_IS_6362())
262 return bcm_ddr_readl(DDR_CSEND_REG) << 24;
263
264 if (BCMCPU_IS_6345()) {
265 val = bcm_sdram_readl(SDRAM_MBASE_REG);
266 return val * 8 * 1024 * 1024;
267 }
268
269 if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
270 val = bcm_sdram_readl(SDRAM_CFG_REG);
271 rows = (val & SDRAM_CFG_ROW_MASK) >> SDRAM_CFG_ROW_SHIFT;
272 cols = (val & SDRAM_CFG_COL_MASK) >> SDRAM_CFG_COL_SHIFT;
273 is_32bits = (val & SDRAM_CFG_32B_MASK) ? 1 : 0;
274 banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1;
275 }
276
277 if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
278 val = bcm_memc_readl(MEMC_CFG_REG);
279 rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
280 cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
281 is_32bits = (val & MEMC_CFG_32B_MASK) ? 0 : 1;
282 banks = 2;
283 }
284
285 /* 0 => 11 address bits ... 2 => 13 address bits */
286 rows += 11;
287
288 /* 0 => 8 address bits ... 2 => 10 address bits */
289 cols += 8;
290
291 return 1 << (cols + rows + (is_32bits + 1) + banks);
292}
293
294void __init bcm63xx_cpu_init(void)
295{
296 unsigned int tmp;
297 unsigned int cpu = smp_processor_id();
298 u32 chipid_reg;
299
300 /* soc registers location depends on cpu type */
301 chipid_reg = 0;
302
303 switch (current_cpu_type()) {
304 case CPU_BMIPS3300:
305 if ((read_c0_prid() & PRID_IMP_MASK) != PRID_IMP_BMIPS3300_ALT)
306 __cpu_name[cpu] = "Broadcom BCM6338";
307 fallthrough;
308 case CPU_BMIPS32:
309 chipid_reg = BCM_6345_PERF_BASE;
310 break;
311 case CPU_BMIPS4350:
312 switch ((read_c0_prid() & PRID_REV_MASK)) {
313 case 0x04:
314 chipid_reg = BCM_3368_PERF_BASE;
315 break;
316 case 0x10:
317 chipid_reg = BCM_6345_PERF_BASE;
318 break;
319 default:
320 chipid_reg = BCM_6368_PERF_BASE;
321 break;
322 }
323 break;
324 }
325
326 /*
327 * really early to panic, but delaying panic would not help since we
328 * will never get any working console
329 */
330 if (!chipid_reg)
331 panic("unsupported Broadcom CPU");
332
333 /* read out CPU type */
334 tmp = bcm_readl(chipid_reg);
335 bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
336 bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT;
337
338 switch (bcm63xx_cpu_id) {
339 case BCM3368_CPU_ID:
340 bcm63xx_regs_base = bcm3368_regs_base;
341 bcm63xx_irqs = bcm3368_irqs;
342 break;
343 case BCM6328_CPU_ID:
344 bcm63xx_regs_base = bcm6328_regs_base;
345 bcm63xx_irqs = bcm6328_irqs;
346 break;
347 case BCM6338_CPU_ID:
348 bcm63xx_regs_base = bcm6338_regs_base;
349 bcm63xx_irqs = bcm6338_irqs;
350 break;
351 case BCM6345_CPU_ID:
352 bcm63xx_regs_base = bcm6345_regs_base;
353 bcm63xx_irqs = bcm6345_irqs;
354 break;
355 case BCM6348_CPU_ID:
356 bcm63xx_regs_base = bcm6348_regs_base;
357 bcm63xx_irqs = bcm6348_irqs;
358 break;
359 case BCM6358_CPU_ID:
360 bcm63xx_regs_base = bcm6358_regs_base;
361 bcm63xx_irqs = bcm6358_irqs;
362 break;
363 case BCM6362_CPU_ID:
364 bcm63xx_regs_base = bcm6362_regs_base;
365 bcm63xx_irqs = bcm6362_irqs;
366 break;
367 case BCM6368_CPU_ID:
368 bcm63xx_regs_base = bcm6368_regs_base;
369 bcm63xx_irqs = bcm6368_irqs;
370 break;
371 default:
372 panic("unsupported broadcom CPU %x", bcm63xx_cpu_id);
373 break;
374 }
375
376 bcm63xx_cpu_freq = detect_cpu_clock();
377 bcm63xx_memory_size = detect_memory_size();
378
379 pr_info("Detected Broadcom 0x%04x CPU revision %02x\n",
380 bcm63xx_cpu_id, bcm63xx_cpu_rev);
381 pr_info("CPU frequency is %u MHz\n",
382 bcm63xx_cpu_freq / 1000000);
383 pr_info("%uMB of RAM installed\n",
384 bcm63xx_memory_size >> 20);
385}
diff --git a/arch/mips/bcm63xx/cs.c b/arch/mips/bcm63xx/cs.c
new file mode 100644
index 000000000..29205badc
--- /dev/null
+++ b/arch/mips/bcm63xx/cs.c
@@ -0,0 +1,145 @@
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/errno.h>
11#include <linux/export.h>
12#include <linux/spinlock.h>
13#include <linux/log2.h>
14#include <bcm63xx_cpu.h>
15#include <bcm63xx_io.h>
16#include <bcm63xx_regs.h>
17#include <bcm63xx_cs.h>
18
19static DEFINE_SPINLOCK(bcm63xx_cs_lock);
20
21/*
22 * check if given chip select exists
23 */
24static int is_valid_cs(unsigned int cs)
25{
26 if (cs > 6)
27 return 0;
28 return 1;
29}
30
31/*
32 * Configure chipselect base address and size (bytes).
33 * Size must be a power of two between 8k and 256M.
34 */
35int bcm63xx_set_cs_base(unsigned int cs, u32 base, unsigned int size)
36{
37 unsigned long flags;
38 u32 val;
39
40 if (!is_valid_cs(cs))
41 return -EINVAL;
42
43 /* sanity check on size */
44 if (size != roundup_pow_of_two(size))
45 return -EINVAL;
46
47 if (size < 8 * 1024 || size > 256 * 1024 * 1024)
48 return -EINVAL;
49
50 val = (base & MPI_CSBASE_BASE_MASK);
51 /* 8k => 0 - 256M => 15 */
52 val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT;
53
54 spin_lock_irqsave(&bcm63xx_cs_lock, flags);
55 bcm_mpi_writel(val, MPI_CSBASE_REG(cs));
56 spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
57
58 return 0;
59}
60
61EXPORT_SYMBOL(bcm63xx_set_cs_base);
62
63/*
64 * configure chipselect timing (ns)
65 */
66int bcm63xx_set_cs_timing(unsigned int cs, unsigned int wait,
67 unsigned int setup, unsigned int hold)
68{
69 unsigned long flags;
70 u32 val;
71
72 if (!is_valid_cs(cs))
73 return -EINVAL;
74
75 spin_lock_irqsave(&bcm63xx_cs_lock, flags);
76 val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
77 val &= ~(MPI_CSCTL_WAIT_MASK);
78 val &= ~(MPI_CSCTL_SETUP_MASK);
79 val &= ~(MPI_CSCTL_HOLD_MASK);
80 val |= wait << MPI_CSCTL_WAIT_SHIFT;
81 val |= setup << MPI_CSCTL_SETUP_SHIFT;
82 val |= hold << MPI_CSCTL_HOLD_SHIFT;
83 bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
84 spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
85
86 return 0;
87}
88
89EXPORT_SYMBOL(bcm63xx_set_cs_timing);
90
91/*
92 * configure other chipselect parameter (data bus size, ...)
93 */
94int bcm63xx_set_cs_param(unsigned int cs, u32 params)
95{
96 unsigned long flags;
97 u32 val;
98
99 if (!is_valid_cs(cs))
100 return -EINVAL;
101
102 /* none of this fields apply to pcmcia */
103 if (cs == MPI_CS_PCMCIA_COMMON ||
104 cs == MPI_CS_PCMCIA_ATTR ||
105 cs == MPI_CS_PCMCIA_IO)
106 return -EINVAL;
107
108 spin_lock_irqsave(&bcm63xx_cs_lock, flags);
109 val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
110 val &= ~(MPI_CSCTL_DATA16_MASK);
111 val &= ~(MPI_CSCTL_SYNCMODE_MASK);
112 val &= ~(MPI_CSCTL_TSIZE_MASK);
113 val &= ~(MPI_CSCTL_ENDIANSWAP_MASK);
114 val |= params;
115 bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
116 spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
117
118 return 0;
119}
120
121EXPORT_SYMBOL(bcm63xx_set_cs_param);
122
123/*
124 * set cs status (enable/disable)
125 */
126int bcm63xx_set_cs_status(unsigned int cs, int enable)
127{
128 unsigned long flags;
129 u32 val;
130
131 if (!is_valid_cs(cs))
132 return -EINVAL;
133
134 spin_lock_irqsave(&bcm63xx_cs_lock, flags);
135 val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
136 if (enable)
137 val |= MPI_CSCTL_ENABLE_MASK;
138 else
139 val &= ~MPI_CSCTL_ENABLE_MASK;
140 bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
141 spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
142 return 0;
143}
144
145EXPORT_SYMBOL(bcm63xx_set_cs_status);
diff --git a/arch/mips/bcm63xx/dev-enet.c b/arch/mips/bcm63xx/dev-enet.c
new file mode 100644
index 000000000..8e73d65f3
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-enet.c
@@ -0,0 +1,327 @@
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/platform_device.h>
12#include <linux/export.h>
13#include <bcm63xx_dev_enet.h>
14#include <bcm63xx_io.h>
15#include <bcm63xx_regs.h>
16
17static const unsigned long bcm6348_regs_enetdmac[] = {
18 [ENETDMAC_CHANCFG] = ENETDMAC_CHANCFG_REG,
19 [ENETDMAC_IR] = ENETDMAC_IR_REG,
20 [ENETDMAC_IRMASK] = ENETDMAC_IRMASK_REG,
21 [ENETDMAC_MAXBURST] = ENETDMAC_MAXBURST_REG,
22};
23
24static const unsigned long bcm6345_regs_enetdmac[] = {
25 [ENETDMAC_CHANCFG] = ENETDMA_6345_CHANCFG_REG,
26 [ENETDMAC_IR] = ENETDMA_6345_IR_REG,
27 [ENETDMAC_IRMASK] = ENETDMA_6345_IRMASK_REG,
28 [ENETDMAC_MAXBURST] = ENETDMA_6345_MAXBURST_REG,
29 [ENETDMAC_BUFALLOC] = ENETDMA_6345_BUFALLOC_REG,
30 [ENETDMAC_RSTART] = ENETDMA_6345_RSTART_REG,
31 [ENETDMAC_FC] = ENETDMA_6345_FC_REG,
32 [ENETDMAC_LEN] = ENETDMA_6345_LEN_REG,
33};
34
35const unsigned long *bcm63xx_regs_enetdmac;
36EXPORT_SYMBOL(bcm63xx_regs_enetdmac);
37
38static __init void bcm63xx_enetdmac_regs_init(void)
39{
40 if (BCMCPU_IS_6345())
41 bcm63xx_regs_enetdmac = bcm6345_regs_enetdmac;
42 else
43 bcm63xx_regs_enetdmac = bcm6348_regs_enetdmac;
44}
45
46static struct resource shared_res[] = {
47 {
48 .start = -1, /* filled at runtime */
49 .end = -1, /* filled at runtime */
50 .flags = IORESOURCE_MEM,
51 },
52 {
53 .start = -1, /* filled at runtime */
54 .end = -1, /* filled at runtime */
55 .flags = IORESOURCE_MEM,
56 },
57 {
58 .start = -1, /* filled at runtime */
59 .end = -1, /* filled at runtime */
60 .flags = IORESOURCE_MEM,
61 },
62};
63
64static struct platform_device bcm63xx_enet_shared_device = {
65 .name = "bcm63xx_enet_shared",
66 .id = 0,
67 .num_resources = ARRAY_SIZE(shared_res),
68 .resource = shared_res,
69};
70
71static int shared_device_registered;
72
73static u64 enet_dmamask = DMA_BIT_MASK(32);
74
75static struct resource enet0_res[] = {
76 {
77 .start = -1, /* filled at runtime */
78 .end = -1, /* filled at runtime */
79 .flags = IORESOURCE_MEM,
80 },
81 {
82 .start = -1, /* filled at runtime */
83 .flags = IORESOURCE_IRQ,
84 },
85 {
86 .start = -1, /* filled at runtime */
87 .flags = IORESOURCE_IRQ,
88 },
89 {
90 .start = -1, /* filled at runtime */
91 .flags = IORESOURCE_IRQ,
92 },
93};
94
95static struct bcm63xx_enet_platform_data enet0_pd;
96
97static struct platform_device bcm63xx_enet0_device = {
98 .name = "bcm63xx_enet",
99 .id = 0,
100 .num_resources = ARRAY_SIZE(enet0_res),
101 .resource = enet0_res,
102 .dev = {
103 .platform_data = &enet0_pd,
104 .dma_mask = &enet_dmamask,
105 .coherent_dma_mask = DMA_BIT_MASK(32),
106 },
107};
108
109static struct resource enet1_res[] = {
110 {
111 .start = -1, /* filled at runtime */
112 .end = -1, /* filled at runtime */
113 .flags = IORESOURCE_MEM,
114 },
115 {
116 .start = -1, /* filled at runtime */
117 .flags = IORESOURCE_IRQ,
118 },
119 {
120 .start = -1, /* filled at runtime */
121 .flags = IORESOURCE_IRQ,
122 },
123 {
124 .start = -1, /* filled at runtime */
125 .flags = IORESOURCE_IRQ,
126 },
127};
128
129static struct bcm63xx_enet_platform_data enet1_pd;
130
131static struct platform_device bcm63xx_enet1_device = {
132 .name = "bcm63xx_enet",
133 .id = 1,
134 .num_resources = ARRAY_SIZE(enet1_res),
135 .resource = enet1_res,
136 .dev = {
137 .platform_data = &enet1_pd,
138 .dma_mask = &enet_dmamask,
139 .coherent_dma_mask = DMA_BIT_MASK(32),
140 },
141};
142
143static struct resource enetsw_res[] = {
144 {
145 /* start & end filled at runtime */
146 .flags = IORESOURCE_MEM,
147 },
148 {
149 /* start filled at runtime */
150 .flags = IORESOURCE_IRQ,
151 },
152 {
153 /* start filled at runtime */
154 .flags = IORESOURCE_IRQ,
155 },
156};
157
158static struct bcm63xx_enetsw_platform_data enetsw_pd;
159
160static struct platform_device bcm63xx_enetsw_device = {
161 .name = "bcm63xx_enetsw",
162 .num_resources = ARRAY_SIZE(enetsw_res),
163 .resource = enetsw_res,
164 .dev = {
165 .platform_data = &enetsw_pd,
166 .dma_mask = &enet_dmamask,
167 .coherent_dma_mask = DMA_BIT_MASK(32),
168 },
169};
170
171static int __init register_shared(void)
172{
173 int ret, chan_count;
174
175 if (shared_device_registered)
176 return 0;
177
178 bcm63xx_enetdmac_regs_init();
179
180 shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
181 shared_res[0].end = shared_res[0].start;
182 if (BCMCPU_IS_6345())
183 shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1;
184 else
185 shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
186
187 if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
188 chan_count = 32;
189 else if (BCMCPU_IS_6345())
190 chan_count = 8;
191 else
192 chan_count = 16;
193
194 shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
195 shared_res[1].end = shared_res[1].start;
196 shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count) - 1;
197
198 shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
199 shared_res[2].end = shared_res[2].start;
200 shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count) - 1;
201
202 ret = platform_device_register(&bcm63xx_enet_shared_device);
203 if (ret)
204 return ret;
205 shared_device_registered = 1;
206
207 return 0;
208}
209
210int __init bcm63xx_enet_register(int unit,
211 const struct bcm63xx_enet_platform_data *pd)
212{
213 struct platform_device *pdev;
214 struct bcm63xx_enet_platform_data *dpd;
215 int ret;
216
217 if (unit > 1)
218 return -ENODEV;
219
220 if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345()))
221 return -ENODEV;
222
223 ret = register_shared();
224 if (ret)
225 return ret;
226
227 if (unit == 0) {
228 enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
229 enet0_res[0].end = enet0_res[0].start;
230 enet0_res[0].end += RSET_ENET_SIZE - 1;
231 enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0);
232 enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA);
233 enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA);
234 pdev = &bcm63xx_enet0_device;
235 } else {
236 enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1);
237 enet1_res[0].end = enet1_res[0].start;
238 enet1_res[0].end += RSET_ENET_SIZE - 1;
239 enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1);
240 enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA);
241 enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA);
242 pdev = &bcm63xx_enet1_device;
243 }
244
245 /* copy given platform data */
246 dpd = pdev->dev.platform_data;
247 memcpy(dpd, pd, sizeof(*pd));
248
249 /* adjust them in case internal phy is used */
250 if (dpd->use_internal_phy) {
251
252 /* internal phy only exists for enet0 */
253 if (unit == 1)
254 return -ENODEV;
255
256 dpd->phy_id = 1;
257 dpd->has_phy_interrupt = 1;
258 dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);
259 }
260
261 dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
262 dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
263 if (BCMCPU_IS_6345()) {
264 dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK;
265 dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK;
266 dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK;
267 dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK;
268 dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK;
269 dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH;
270 dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT;
271 } else {
272 dpd->dma_has_sram = true;
273 dpd->dma_chan_width = ENETDMA_CHAN_WIDTH;
274 }
275
276 if (unit == 0) {
277 dpd->rx_chan = 0;
278 dpd->tx_chan = 1;
279 } else {
280 dpd->rx_chan = 2;
281 dpd->tx_chan = 3;
282 }
283
284 ret = platform_device_register(pdev);
285 if (ret)
286 return ret;
287 return 0;
288}
289
290int __init
291bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
292{
293 int ret;
294
295 if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
296 return -ENODEV;
297
298 ret = register_shared();
299 if (ret)
300 return ret;
301
302 enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW);
303 enetsw_res[0].end = enetsw_res[0].start;
304 enetsw_res[0].end += RSET_ENETSW_SIZE - 1;
305 enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0);
306 enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0);
307 if (!enetsw_res[2].start)
308 enetsw_res[2].start = -1;
309
310 memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
311
312 if (BCMCPU_IS_6328())
313 enetsw_pd.num_ports = ENETSW_PORTS_6328;
314 else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
315 enetsw_pd.num_ports = ENETSW_PORTS_6368;
316
317 enetsw_pd.dma_has_sram = true;
318 enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH;
319 enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
320 enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
321
322 ret = platform_device_register(&bcm63xx_enetsw_device);
323 if (ret)
324 return ret;
325
326 return 0;
327}
diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c
new file mode 100644
index 000000000..f9cc015d3
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-flash.c
@@ -0,0 +1,131 @@
1/*
2 * Broadcom BCM63xx flash 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) 2008 Maxime Bizon <mbizon@freebox.fr>
9 * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
10 * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
11 */
12
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/platform_device.h>
16#include <linux/mtd/mtd.h>
17#include <linux/mtd/partitions.h>
18#include <linux/mtd/physmap.h>
19
20#include <bcm63xx_cpu.h>
21#include <bcm63xx_dev_flash.h>
22#include <bcm63xx_regs.h>
23#include <bcm63xx_io.h>
24
25static struct mtd_partition mtd_partitions[] = {
26 {
27 .name = "cfe",
28 .offset = 0x0,
29 .size = 0x40000,
30 }
31};
32
33static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL };
34
35static struct physmap_flash_data flash_data = {
36 .width = 2,
37 .parts = mtd_partitions,
38 .part_probe_types = bcm63xx_part_types,
39};
40
41static struct resource mtd_resources[] = {
42 {
43 .start = 0, /* filled at runtime */
44 .end = 0, /* filled at runtime */
45 .flags = IORESOURCE_MEM,
46 }
47};
48
49static struct platform_device mtd_dev = {
50 .name = "physmap-flash",
51 .resource = mtd_resources,
52 .num_resources = ARRAY_SIZE(mtd_resources),
53 .dev = {
54 .platform_data = &flash_data,
55 },
56};
57
58static int __init bcm63xx_detect_flash_type(void)
59{
60 u32 val;
61
62 switch (bcm63xx_get_cpu_id()) {
63 case BCM6328_CPU_ID:
64 val = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
65 if (val & STRAPBUS_6328_BOOT_SEL_SERIAL)
66 return BCM63XX_FLASH_TYPE_SERIAL;
67 else
68 return BCM63XX_FLASH_TYPE_NAND;
69 case BCM6338_CPU_ID:
70 case BCM6345_CPU_ID:
71 case BCM6348_CPU_ID:
72 /* no way to auto detect so assume parallel */
73 return BCM63XX_FLASH_TYPE_PARALLEL;
74 case BCM3368_CPU_ID:
75 case BCM6358_CPU_ID:
76 val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
77 if (val & STRAPBUS_6358_BOOT_SEL_PARALLEL)
78 return BCM63XX_FLASH_TYPE_PARALLEL;
79 else
80 return BCM63XX_FLASH_TYPE_SERIAL;
81 case BCM6362_CPU_ID:
82 val = bcm_misc_readl(MISC_STRAPBUS_6362_REG);
83 if (val & STRAPBUS_6362_BOOT_SEL_SERIAL)
84 return BCM63XX_FLASH_TYPE_SERIAL;
85 else
86 return BCM63XX_FLASH_TYPE_NAND;
87 case BCM6368_CPU_ID:
88 val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
89 switch (val & STRAPBUS_6368_BOOT_SEL_MASK) {
90 case STRAPBUS_6368_BOOT_SEL_NAND:
91 return BCM63XX_FLASH_TYPE_NAND;
92 case STRAPBUS_6368_BOOT_SEL_SERIAL:
93 return BCM63XX_FLASH_TYPE_SERIAL;
94 case STRAPBUS_6368_BOOT_SEL_PARALLEL:
95 return BCM63XX_FLASH_TYPE_PARALLEL;
96 }
97 fallthrough;
98 default:
99 return -EINVAL;
100 }
101}
102
103int __init bcm63xx_flash_register(void)
104{
105 int flash_type;
106 u32 val;
107
108 flash_type = bcm63xx_detect_flash_type();
109
110 switch (flash_type) {
111 case BCM63XX_FLASH_TYPE_PARALLEL:
112 /* read base address of boot chip select (0) */
113 val = bcm_mpi_readl(MPI_CSBASE_REG(0));
114 val &= MPI_CSBASE_BASE_MASK;
115
116 mtd_resources[0].start = val;
117 mtd_resources[0].end = 0x1FFFFFFF;
118
119 return platform_device_register(&mtd_dev);
120 case BCM63XX_FLASH_TYPE_SERIAL:
121 pr_warn("unsupported serial flash detected\n");
122 return -ENODEV;
123 case BCM63XX_FLASH_TYPE_NAND:
124 pr_warn("unsupported NAND flash detected\n");
125 return -ENODEV;
126 default:
127 pr_err("flash detection failed for BCM%x: %d\n",
128 bcm63xx_get_cpu_id(), flash_type);
129 return -ENODEV;
130 }
131}
diff --git a/arch/mips/bcm63xx/dev-hsspi.c b/arch/mips/bcm63xx/dev-hsspi.c
new file mode 100644
index 000000000..696abc48e
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-hsspi.c
@@ -0,0 +1,47 @@
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) 2012 Jonas Gorski <jonas.gorski@gmail.com>
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/platform_device.h>
12
13#include <bcm63xx_cpu.h>
14#include <bcm63xx_dev_hsspi.h>
15#include <bcm63xx_regs.h>
16
17static struct resource spi_resources[] = {
18 {
19 .start = -1, /* filled at runtime */
20 .end = -1, /* filled at runtime */
21 .flags = IORESOURCE_MEM,
22 },
23 {
24 .start = -1, /* filled at runtime */
25 .flags = IORESOURCE_IRQ,
26 },
27};
28
29static struct platform_device bcm63xx_hsspi_device = {
30 .name = "bcm63xx-hsspi",
31 .id = 0,
32 .num_resources = ARRAY_SIZE(spi_resources),
33 .resource = spi_resources,
34};
35
36int __init bcm63xx_hsspi_register(void)
37{
38 if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362())
39 return -ENODEV;
40
41 spi_resources[0].start = bcm63xx_regset_address(RSET_HSSPI);
42 spi_resources[0].end = spi_resources[0].start;
43 spi_resources[0].end += RSET_HSSPI_SIZE - 1;
44 spi_resources[1].start = bcm63xx_get_irq_number(IRQ_HSSPI);
45
46 return platform_device_register(&bcm63xx_hsspi_device);
47}
diff --git a/arch/mips/bcm63xx/dev-pcmcia.c b/arch/mips/bcm63xx/dev-pcmcia.c
new file mode 100644
index 000000000..9496cd236
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-pcmcia.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/init.h>
10#include <linux/kernel.h>
11#include <asm/bootinfo.h>
12#include <linux/platform_device.h>
13#include <bcm63xx_cs.h>
14#include <bcm63xx_cpu.h>
15#include <bcm63xx_dev_pcmcia.h>
16#include <bcm63xx_io.h>
17#include <bcm63xx_regs.h>
18
19static struct resource pcmcia_resources[] = {
20 /* pcmcia registers */
21 {
22 /* start & end filled at runtime */
23 .flags = IORESOURCE_MEM,
24 },
25
26 /* pcmcia memory zone resources */
27 {
28 .start = BCM_PCMCIA_COMMON_BASE_PA,
29 .end = BCM_PCMCIA_COMMON_END_PA,
30 .flags = IORESOURCE_MEM,
31 },
32 {
33 .start = BCM_PCMCIA_ATTR_BASE_PA,
34 .end = BCM_PCMCIA_ATTR_END_PA,
35 .flags = IORESOURCE_MEM,
36 },
37 {
38 .start = BCM_PCMCIA_IO_BASE_PA,
39 .end = BCM_PCMCIA_IO_END_PA,
40 .flags = IORESOURCE_MEM,
41 },
42
43 /* PCMCIA irq */
44 {
45 /* start filled at runtime */
46 .flags = IORESOURCE_IRQ,
47 },
48
49 /* declare PCMCIA IO resource also */
50 {
51 .start = BCM_PCMCIA_IO_BASE_PA,
52 .end = BCM_PCMCIA_IO_END_PA,
53 .flags = IORESOURCE_IO,
54 },
55};
56
57static struct bcm63xx_pcmcia_platform_data pd;
58
59static struct platform_device bcm63xx_pcmcia_device = {
60 .name = "bcm63xx_pcmcia",
61 .id = 0,
62 .num_resources = ARRAY_SIZE(pcmcia_resources),
63 .resource = pcmcia_resources,
64 .dev = {
65 .platform_data = &pd,
66 },
67};
68
69static int __init config_pcmcia_cs(unsigned int cs,
70 u32 base, unsigned int size)
71{
72 int ret;
73
74 ret = bcm63xx_set_cs_status(cs, 0);
75 if (!ret)
76 ret = bcm63xx_set_cs_base(cs, base, size);
77 if (!ret)
78 ret = bcm63xx_set_cs_status(cs, 1);
79 return ret;
80}
81
82static const struct {
83 unsigned int cs;
84 unsigned int base;
85 unsigned int size;
86} pcmcia_cs[3] __initconst = {
87 {
88 .cs = MPI_CS_PCMCIA_COMMON,
89 .base = BCM_PCMCIA_COMMON_BASE_PA,
90 .size = BCM_PCMCIA_COMMON_SIZE
91 },
92 {
93 .cs = MPI_CS_PCMCIA_ATTR,
94 .base = BCM_PCMCIA_ATTR_BASE_PA,
95 .size = BCM_PCMCIA_ATTR_SIZE
96 },
97 {
98 .cs = MPI_CS_PCMCIA_IO,
99 .base = BCM_PCMCIA_IO_BASE_PA,
100 .size = BCM_PCMCIA_IO_SIZE
101 },
102};
103
104int __init bcm63xx_pcmcia_register(void)
105{
106 int ret, i;
107
108 if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358())
109 return 0;
110
111 /* use correct pcmcia ready gpio depending on processor */
112 switch (bcm63xx_get_cpu_id()) {
113 case BCM6348_CPU_ID:
114 pd.ready_gpio = 22;
115 break;
116
117 case BCM6358_CPU_ID:
118 pd.ready_gpio = 18;
119 break;
120
121 default:
122 return -ENODEV;
123 }
124
125 pcmcia_resources[0].start = bcm63xx_regset_address(RSET_PCMCIA);
126 pcmcia_resources[0].end = pcmcia_resources[0].start +
127 RSET_PCMCIA_SIZE - 1;
128 pcmcia_resources[4].start = bcm63xx_get_irq_number(IRQ_PCMCIA);
129
130 /* configure pcmcia chip selects */
131 for (i = 0; i < 3; i++) {
132 ret = config_pcmcia_cs(pcmcia_cs[i].cs,
133 pcmcia_cs[i].base,
134 pcmcia_cs[i].size);
135 if (ret)
136 goto out_err;
137 }
138
139 return platform_device_register(&bcm63xx_pcmcia_device);
140
141out_err:
142 pr_err("unable to set pcmcia chip select\n");
143 return ret;
144}
diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c
new file mode 100644
index 000000000..d277b4dc6
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-rng.c
@@ -0,0 +1,40 @@
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) 2011 Florian Fainelli <florian@openwrt.org>
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/platform_device.h>
12#include <bcm63xx_cpu.h>
13
14static struct resource rng_resources[] = {
15 {
16 .start = -1, /* filled at runtime */
17 .end = -1, /* filled at runtime */
18 .flags = IORESOURCE_MEM,
19 },
20};
21
22static struct platform_device bcm63xx_rng_device = {
23 .name = "bcm63xx-rng",
24 .id = -1,
25 .num_resources = ARRAY_SIZE(rng_resources),
26 .resource = rng_resources,
27};
28
29int __init bcm63xx_rng_register(void)
30{
31 if (!BCMCPU_IS_6368())
32 return -ENODEV;
33
34 rng_resources[0].start = bcm63xx_regset_address(RSET_RNG);
35 rng_resources[0].end = rng_resources[0].start;
36 rng_resources[0].end += RSET_RNG_SIZE - 1;
37
38 return platform_device_register(&bcm63xx_rng_device);
39}
40arch_initcall(bcm63xx_rng_register);
diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c
new file mode 100644
index 000000000..232385441
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-spi.c
@@ -0,0 +1,60 @@
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) 2009-2011 Florian Fainelli <florian@openwrt.org>
7 * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
8 */
9
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/export.h>
13#include <linux/platform_device.h>
14#include <linux/err.h>
15#include <linux/clk.h>
16
17#include <bcm63xx_cpu.h>
18#include <bcm63xx_dev_spi.h>
19#include <bcm63xx_regs.h>
20
21static struct resource spi_resources[] = {
22 {
23 .start = -1, /* filled at runtime */
24 .end = -1, /* filled at runtime */
25 .flags = IORESOURCE_MEM,
26 },
27 {
28 .start = -1, /* filled at runtime */
29 .flags = IORESOURCE_IRQ,
30 },
31};
32
33static struct platform_device bcm63xx_spi_device = {
34 .id = -1,
35 .num_resources = ARRAY_SIZE(spi_resources),
36 .resource = spi_resources,
37};
38
39int __init bcm63xx_spi_register(void)
40{
41 if (BCMCPU_IS_6328() || BCMCPU_IS_6345())
42 return -ENODEV;
43
44 spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
45 spi_resources[0].end = spi_resources[0].start;
46 spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
47
48 if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
49 bcm63xx_spi_device.name = "bcm6348-spi",
50 spi_resources[0].end += BCM_6348_RSET_SPI_SIZE - 1;
51 }
52
53 if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6362() ||
54 BCMCPU_IS_6368()) {
55 bcm63xx_spi_device.name = "bcm6358-spi",
56 spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
57 }
58
59 return platform_device_register(&bcm63xx_spi_device);
60}
diff --git a/arch/mips/bcm63xx/dev-uart.c b/arch/mips/bcm63xx/dev-uart.c
new file mode 100644
index 000000000..3bc7f3bfc
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-uart.c
@@ -0,0 +1,76 @@
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/platform_device.h>
12#include <bcm63xx_cpu.h>
13
14static struct resource uart0_resources[] = {
15 {
16 /* start & end filled at runtime */
17 .flags = IORESOURCE_MEM,
18 },
19 {
20 /* start filled at runtime */
21 .flags = IORESOURCE_IRQ,
22 },
23};
24
25static struct resource uart1_resources[] = {
26 {
27 /* start & end filled at runtime */
28 .flags = IORESOURCE_MEM,
29 },
30 {
31 /* start filled at runtime */
32 .flags = IORESOURCE_IRQ,
33 },
34};
35
36static struct platform_device bcm63xx_uart_devices[] = {
37 {
38 .name = "bcm63xx_uart",
39 .id = 0,
40 .num_resources = ARRAY_SIZE(uart0_resources),
41 .resource = uart0_resources,
42 },
43
44 {
45 .name = "bcm63xx_uart",
46 .id = 1,
47 .num_resources = ARRAY_SIZE(uart1_resources),
48 .resource = uart1_resources,
49 }
50};
51
52int __init bcm63xx_uart_register(unsigned int id)
53{
54 if (id >= ARRAY_SIZE(bcm63xx_uart_devices))
55 return -ENODEV;
56
57 if (id == 1 && (!BCMCPU_IS_3368() && !BCMCPU_IS_6358() &&
58 !BCMCPU_IS_6368()))
59 return -ENODEV;
60
61 if (id == 0) {
62 uart0_resources[0].start = bcm63xx_regset_address(RSET_UART0);
63 uart0_resources[0].end = uart0_resources[0].start +
64 RSET_UART_SIZE - 1;
65 uart0_resources[1].start = bcm63xx_get_irq_number(IRQ_UART0);
66 }
67
68 if (id == 1) {
69 uart1_resources[0].start = bcm63xx_regset_address(RSET_UART1);
70 uart1_resources[0].end = uart1_resources[0].start +
71 RSET_UART_SIZE - 1;
72 uart1_resources[1].start = bcm63xx_get_irq_number(IRQ_UART1);
73 }
74
75 return platform_device_register(&bcm63xx_uart_devices[id]);
76}
diff --git a/arch/mips/bcm63xx/dev-usb-usbd.c b/arch/mips/bcm63xx/dev-usb-usbd.c
new file mode 100644
index 000000000..508bd9d8d
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-usb-usbd.c
@@ -0,0 +1,65 @@
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) 2012 Kevin Cernekee <cernekee@gmail.com>
8 * Copyright (C) 2012 Broadcom Corporation
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/platform_device.h>
14#include <linux/dma-mapping.h>
15#include <bcm63xx_cpu.h>
16#include <bcm63xx_dev_usb_usbd.h>
17
18#define NUM_MMIO 2
19#define NUM_IRQ 7
20
21static struct resource usbd_resources[NUM_MMIO + NUM_IRQ];
22
23static u64 usbd_dmamask = DMA_BIT_MASK(32);
24
25static struct platform_device bcm63xx_usbd_device = {
26 .name = "bcm63xx_udc",
27 .id = -1,
28 .num_resources = ARRAY_SIZE(usbd_resources),
29 .resource = usbd_resources,
30 .dev = {
31 .dma_mask = &usbd_dmamask,
32 .coherent_dma_mask = DMA_BIT_MASK(32),
33 },
34};
35
36int __init bcm63xx_usbd_register(const struct bcm63xx_usbd_platform_data *pd)
37{
38 const int irq_list[NUM_IRQ] = { IRQ_USBD,
39 IRQ_USBD_RXDMA0, IRQ_USBD_TXDMA0,
40 IRQ_USBD_RXDMA1, IRQ_USBD_TXDMA1,
41 IRQ_USBD_RXDMA2, IRQ_USBD_TXDMA2 };
42 int i;
43
44 if (!BCMCPU_IS_6328() && !BCMCPU_IS_6368())
45 return 0;
46
47 usbd_resources[0].start = bcm63xx_regset_address(RSET_USBD);
48 usbd_resources[0].end = usbd_resources[0].start + RSET_USBD_SIZE - 1;
49 usbd_resources[0].flags = IORESOURCE_MEM;
50
51 usbd_resources[1].start = bcm63xx_regset_address(RSET_USBDMA);
52 usbd_resources[1].end = usbd_resources[1].start + RSET_USBDMA_SIZE - 1;
53 usbd_resources[1].flags = IORESOURCE_MEM;
54
55 for (i = 0; i < NUM_IRQ; i++) {
56 struct resource *r = &usbd_resources[NUM_MMIO + i];
57
58 r->start = r->end = bcm63xx_get_irq_number(irq_list[i]);
59 r->flags = IORESOURCE_IRQ;
60 }
61
62 platform_device_add_data(&bcm63xx_usbd_device, pd, sizeof(*pd));
63
64 return platform_device_register(&bcm63xx_usbd_device);
65}
diff --git a/arch/mips/bcm63xx/dev-wdt.c b/arch/mips/bcm63xx/dev-wdt.c
new file mode 100644
index 000000000..2a2346a99
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-wdt.c
@@ -0,0 +1,37 @@
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 Florian Fainelli <florian@openwrt.org>
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/platform_device.h>
12#include <bcm63xx_cpu.h>
13
14static struct resource wdt_resources[] = {
15 {
16 .start = -1, /* filled at runtime */
17 .end = -1, /* filled at runtime */
18 .flags = IORESOURCE_MEM,
19 },
20};
21
22static struct platform_device bcm63xx_wdt_device = {
23 .name = "bcm63xx-wdt",
24 .id = -1,
25 .num_resources = ARRAY_SIZE(wdt_resources),
26 .resource = wdt_resources,
27};
28
29int __init bcm63xx_wdt_register(void)
30{
31 wdt_resources[0].start = bcm63xx_regset_address(RSET_WDT);
32 wdt_resources[0].end = wdt_resources[0].start;
33 wdt_resources[0].end += RSET_WDT_SIZE - 1;
34
35 return platform_device_register(&bcm63xx_wdt_device);
36}
37arch_initcall(bcm63xx_wdt_register);
diff --git a/arch/mips/bcm63xx/early_printk.c b/arch/mips/bcm63xx/early_printk.c
new file mode 100644
index 000000000..9e9ec27c2
--- /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 <bcm63xx_io.h>
10#include <linux/serial_bcm63xx.h>
11#include <asm/setup.h>
12
13static void 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 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 000000000..16f353ac3
--- /dev/null
+++ b/arch/mips/bcm63xx/gpio.c
@@ -0,0 +1,151 @@
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-2011 Florian Fainelli <florian@openwrt.org>
8 */
9
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/spinlock.h>
13#include <linux/platform_device.h>
14#include <linux/gpio/driver.h>
15
16#include <bcm63xx_cpu.h>
17#include <bcm63xx_gpio.h>
18#include <bcm63xx_io.h>
19#include <bcm63xx_regs.h>
20
21static u32 gpio_out_low_reg;
22
23static void bcm63xx_gpio_out_low_reg_init(void)
24{
25 switch (bcm63xx_get_cpu_id()) {
26 case BCM6345_CPU_ID:
27 gpio_out_low_reg = GPIO_DATA_LO_REG_6345;
28 break;
29 default:
30 gpio_out_low_reg = GPIO_DATA_LO_REG;
31 break;
32 }
33}
34
35static DEFINE_SPINLOCK(bcm63xx_gpio_lock);
36static u32 gpio_out_low, gpio_out_high;
37
38static void bcm63xx_gpio_set(struct gpio_chip *chip,
39 unsigned gpio, int val)
40{
41 u32 reg;
42 u32 mask;
43 u32 *v;
44 unsigned long flags;
45
46 if (gpio >= chip->ngpio)
47 BUG();
48
49 if (gpio < 32) {
50 reg = gpio_out_low_reg;
51 mask = 1 << gpio;
52 v = &gpio_out_low;
53 } else {
54 reg = GPIO_DATA_HI_REG;
55 mask = 1 << (gpio - 32);
56 v = &gpio_out_high;
57 }
58
59 spin_lock_irqsave(&bcm63xx_gpio_lock, flags);
60 if (val)
61 *v |= mask;
62 else
63 *v &= ~mask;
64 bcm_gpio_writel(*v, reg);
65 spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags);
66}
67
68static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio)
69{
70 u32 reg;
71 u32 mask;
72
73 if (gpio >= chip->ngpio)
74 BUG();
75
76 if (gpio < 32) {
77 reg = gpio_out_low_reg;
78 mask = 1 << gpio;
79 } else {
80 reg = GPIO_DATA_HI_REG;
81 mask = 1 << (gpio - 32);
82 }
83
84 return !!(bcm_gpio_readl(reg) & mask);
85}
86
87static int bcm63xx_gpio_set_direction(struct gpio_chip *chip,
88 unsigned gpio, int dir)
89{
90 u32 reg;
91 u32 mask;
92 u32 tmp;
93 unsigned long flags;
94
95 if (gpio >= chip->ngpio)
96 BUG();
97
98 if (gpio < 32) {
99 reg = GPIO_CTL_LO_REG;
100 mask = 1 << gpio;
101 } else {
102 reg = GPIO_CTL_HI_REG;
103 mask = 1 << (gpio - 32);
104 }
105
106 spin_lock_irqsave(&bcm63xx_gpio_lock, flags);
107 tmp = bcm_gpio_readl(reg);
108 if (dir == BCM63XX_GPIO_DIR_IN)
109 tmp &= ~mask;
110 else
111 tmp |= mask;
112 bcm_gpio_writel(tmp, reg);
113 spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags);
114
115 return 0;
116}
117
118static int bcm63xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
119{
120 return bcm63xx_gpio_set_direction(chip, gpio, BCM63XX_GPIO_DIR_IN);
121}
122
123static int bcm63xx_gpio_direction_output(struct gpio_chip *chip,
124 unsigned gpio, int value)
125{
126 bcm63xx_gpio_set(chip, gpio, value);
127 return bcm63xx_gpio_set_direction(chip, gpio, BCM63XX_GPIO_DIR_OUT);
128}
129
130
131static struct gpio_chip bcm63xx_gpio_chip = {
132 .label = "bcm63xx-gpio",
133 .direction_input = bcm63xx_gpio_direction_input,
134 .direction_output = bcm63xx_gpio_direction_output,
135 .get = bcm63xx_gpio_get,
136 .set = bcm63xx_gpio_set,
137 .base = 0,
138};
139
140int __init bcm63xx_gpio_init(void)
141{
142 bcm63xx_gpio_out_low_reg_init();
143
144 gpio_out_low = bcm_gpio_readl(gpio_out_low_reg);
145 if (!BCMCPU_IS_6345())
146 gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG);
147 bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();
148 pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio);
149
150 return gpiochip_add_data(&bcm63xx_gpio_chip, NULL);
151}
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
new file mode 100644
index 000000000..254801344
--- /dev/null
+++ b/arch/mips/bcm63xx/irq.c
@@ -0,0 +1,553 @@
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/irq.h>
14#include <linux/spinlock.h>
15#include <asm/irq_cpu.h>
16#include <asm/mipsregs.h>
17#include <bcm63xx_cpu.h>
18#include <bcm63xx_regs.h>
19#include <bcm63xx_io.h>
20#include <bcm63xx_irq.h>
21
22
23static DEFINE_SPINLOCK(ipic_lock);
24static DEFINE_SPINLOCK(epic_lock);
25
26static u32 irq_stat_addr[2];
27static u32 irq_mask_addr[2];
28static void (*dispatch_internal)(int cpu);
29static int is_ext_irq_cascaded;
30static unsigned int ext_irq_count;
31static unsigned int ext_irq_start, ext_irq_end;
32static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
33static void (*internal_irq_mask)(struct irq_data *d);
34static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m);
35
36
37static inline u32 get_ext_irq_perf_reg(int irq)
38{
39 if (irq < 4)
40 return ext_irq_cfg_reg1;
41 return ext_irq_cfg_reg2;
42}
43
44static inline void handle_internal(int intbit)
45{
46 if (is_ext_irq_cascaded &&
47 intbit >= ext_irq_start && intbit <= ext_irq_end)
48 do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
49 else
50 do_IRQ(intbit + IRQ_INTERNAL_BASE);
51}
52
53static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
54 const struct cpumask *m)
55{
56 bool enable = cpu_online(cpu);
57
58#ifdef CONFIG_SMP
59 if (m)
60 enable &= cpumask_test_cpu(cpu, m);
61 else if (irqd_affinity_was_set(d))
62 enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d));
63#endif
64 return enable;
65}
66
67/*
68 * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
69 * prioritize any interrupt relatively to another. the static counter
70 * will resume the loop where it ended the last time we left this
71 * function.
72 */
73
74#define BUILD_IPIC_INTERNAL(width) \
75void __dispatch_internal_##width(int cpu) \
76{ \
77 u32 pending[width / 32]; \
78 unsigned int src, tgt; \
79 bool irqs_pending = false; \
80 static unsigned int i[2]; \
81 unsigned int *next = &i[cpu]; \
82 unsigned long flags; \
83 \
84 /* read registers in reverse order */ \
85 spin_lock_irqsave(&ipic_lock, flags); \
86 for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
87 u32 val; \
88 \
89 val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \
90 val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \
91 pending[--tgt] = val; \
92 \
93 if (val) \
94 irqs_pending = true; \
95 } \
96 spin_unlock_irqrestore(&ipic_lock, flags); \
97 \
98 if (!irqs_pending) \
99 return; \
100 \
101 while (1) { \
102 unsigned int to_call = *next; \
103 \
104 *next = (*next + 1) & (width - 1); \
105 if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \
106 handle_internal(to_call); \
107 break; \
108 } \
109 } \
110} \
111 \
112static void __internal_irq_mask_##width(struct irq_data *d) \
113{ \
114 u32 val; \
115 unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
116 unsigned reg = (irq / 32) ^ (width/32 - 1); \
117 unsigned bit = irq & 0x1f; \
118 unsigned long flags; \
119 int cpu; \
120 \
121 spin_lock_irqsave(&ipic_lock, flags); \
122 for_each_present_cpu(cpu) { \
123 if (!irq_mask_addr[cpu]) \
124 break; \
125 \
126 val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
127 val &= ~(1 << bit); \
128 bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
129 } \
130 spin_unlock_irqrestore(&ipic_lock, flags); \
131} \
132 \
133static void __internal_irq_unmask_##width(struct irq_data *d, \
134 const struct cpumask *m) \
135{ \
136 u32 val; \
137 unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
138 unsigned reg = (irq / 32) ^ (width/32 - 1); \
139 unsigned bit = irq & 0x1f; \
140 unsigned long flags; \
141 int cpu; \
142 \
143 spin_lock_irqsave(&ipic_lock, flags); \
144 for_each_present_cpu(cpu) { \
145 if (!irq_mask_addr[cpu]) \
146 break; \
147 \
148 val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
149 if (enable_irq_for_cpu(cpu, d, m)) \
150 val |= (1 << bit); \
151 else \
152 val &= ~(1 << bit); \
153 bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
154 } \
155 spin_unlock_irqrestore(&ipic_lock, flags); \
156}
157
158BUILD_IPIC_INTERNAL(32);
159BUILD_IPIC_INTERNAL(64);
160
161asmlinkage void plat_irq_dispatch(void)
162{
163 u32 cause;
164
165 do {
166 cause = read_c0_cause() & read_c0_status() & ST0_IM;
167
168 if (!cause)
169 break;
170
171 if (cause & CAUSEF_IP7)
172 do_IRQ(7);
173 if (cause & CAUSEF_IP0)
174 do_IRQ(0);
175 if (cause & CAUSEF_IP1)
176 do_IRQ(1);
177 if (cause & CAUSEF_IP2)
178 dispatch_internal(0);
179 if (is_ext_irq_cascaded) {
180 if (cause & CAUSEF_IP3)
181 dispatch_internal(1);
182 } else {
183 if (cause & CAUSEF_IP3)
184 do_IRQ(IRQ_EXT_0);
185 if (cause & CAUSEF_IP4)
186 do_IRQ(IRQ_EXT_1);
187 if (cause & CAUSEF_IP5)
188 do_IRQ(IRQ_EXT_2);
189 if (cause & CAUSEF_IP6)
190 do_IRQ(IRQ_EXT_3);
191 }
192 } while (1);
193}
194
195/*
196 * internal IRQs operations: only mask/unmask on PERF irq mask
197 * register.
198 */
199static void bcm63xx_internal_irq_mask(struct irq_data *d)
200{
201 internal_irq_mask(d);
202}
203
204static void bcm63xx_internal_irq_unmask(struct irq_data *d)
205{
206 internal_irq_unmask(d, NULL);
207}
208
209/*
210 * external IRQs operations: mask/unmask and clear on PERF external
211 * irq control register.
212 */
213static void bcm63xx_external_irq_mask(struct irq_data *d)
214{
215 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
216 u32 reg, regaddr;
217 unsigned long flags;
218
219 regaddr = get_ext_irq_perf_reg(irq);
220 spin_lock_irqsave(&epic_lock, flags);
221 reg = bcm_perf_readl(regaddr);
222
223 if (BCMCPU_IS_6348())
224 reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
225 else
226 reg &= ~EXTIRQ_CFG_MASK(irq % 4);
227
228 bcm_perf_writel(reg, regaddr);
229 spin_unlock_irqrestore(&epic_lock, flags);
230
231 if (is_ext_irq_cascaded)
232 internal_irq_mask(irq_get_irq_data(irq + ext_irq_start));
233}
234
235static void bcm63xx_external_irq_unmask(struct irq_data *d)
236{
237 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
238 u32 reg, regaddr;
239 unsigned long flags;
240
241 regaddr = get_ext_irq_perf_reg(irq);
242 spin_lock_irqsave(&epic_lock, flags);
243 reg = bcm_perf_readl(regaddr);
244
245 if (BCMCPU_IS_6348())
246 reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
247 else
248 reg |= EXTIRQ_CFG_MASK(irq % 4);
249
250 bcm_perf_writel(reg, regaddr);
251 spin_unlock_irqrestore(&epic_lock, flags);
252
253 if (is_ext_irq_cascaded)
254 internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start),
255 NULL);
256}
257
258static void bcm63xx_external_irq_clear(struct irq_data *d)
259{
260 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
261 u32 reg, regaddr;
262 unsigned long flags;
263
264 regaddr = get_ext_irq_perf_reg(irq);
265 spin_lock_irqsave(&epic_lock, flags);
266 reg = bcm_perf_readl(regaddr);
267
268 if (BCMCPU_IS_6348())
269 reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
270 else
271 reg |= EXTIRQ_CFG_CLEAR(irq % 4);
272
273 bcm_perf_writel(reg, regaddr);
274 spin_unlock_irqrestore(&epic_lock, flags);
275}
276
277static int bcm63xx_external_irq_set_type(struct irq_data *d,
278 unsigned int flow_type)
279{
280 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
281 u32 reg, regaddr;
282 int levelsense, sense, bothedge;
283 unsigned long flags;
284
285 flow_type &= IRQ_TYPE_SENSE_MASK;
286
287 if (flow_type == IRQ_TYPE_NONE)
288 flow_type = IRQ_TYPE_LEVEL_LOW;
289
290 levelsense = sense = bothedge = 0;
291 switch (flow_type) {
292 case IRQ_TYPE_EDGE_BOTH:
293 bothedge = 1;
294 break;
295
296 case IRQ_TYPE_EDGE_RISING:
297 sense = 1;
298 break;
299
300 case IRQ_TYPE_EDGE_FALLING:
301 break;
302
303 case IRQ_TYPE_LEVEL_HIGH:
304 levelsense = 1;
305 sense = 1;
306 break;
307
308 case IRQ_TYPE_LEVEL_LOW:
309 levelsense = 1;
310 break;
311
312 default:
313 pr_err("bogus flow type combination given !\n");
314 return -EINVAL;
315 }
316
317 regaddr = get_ext_irq_perf_reg(irq);
318 spin_lock_irqsave(&epic_lock, flags);
319 reg = bcm_perf_readl(regaddr);
320 irq %= 4;
321
322 switch (bcm63xx_get_cpu_id()) {
323 case BCM6348_CPU_ID:
324 if (levelsense)
325 reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
326 else
327 reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
328 if (sense)
329 reg |= EXTIRQ_CFG_SENSE_6348(irq);
330 else
331 reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
332 if (bothedge)
333 reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
334 else
335 reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
336 break;
337
338 case BCM3368_CPU_ID:
339 case BCM6328_CPU_ID:
340 case BCM6338_CPU_ID:
341 case BCM6345_CPU_ID:
342 case BCM6358_CPU_ID:
343 case BCM6362_CPU_ID:
344 case BCM6368_CPU_ID:
345 if (levelsense)
346 reg |= EXTIRQ_CFG_LEVELSENSE(irq);
347 else
348 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
349 if (sense)
350 reg |= EXTIRQ_CFG_SENSE(irq);
351 else
352 reg &= ~EXTIRQ_CFG_SENSE(irq);
353 if (bothedge)
354 reg |= EXTIRQ_CFG_BOTHEDGE(irq);
355 else
356 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
357 break;
358 default:
359 BUG();
360 }
361
362 bcm_perf_writel(reg, regaddr);
363 spin_unlock_irqrestore(&epic_lock, flags);
364
365 irqd_set_trigger_type(d, flow_type);
366 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
367 irq_set_handler_locked(d, handle_level_irq);
368 else
369 irq_set_handler_locked(d, handle_edge_irq);
370
371 return IRQ_SET_MASK_OK_NOCOPY;
372}
373
374#ifdef CONFIG_SMP
375static int bcm63xx_internal_set_affinity(struct irq_data *data,
376 const struct cpumask *dest,
377 bool force)
378{
379 if (!irqd_irq_disabled(data))
380 internal_irq_unmask(data, dest);
381
382 return 0;
383}
384#endif
385
386static struct irq_chip bcm63xx_internal_irq_chip = {
387 .name = "bcm63xx_ipic",
388 .irq_mask = bcm63xx_internal_irq_mask,
389 .irq_unmask = bcm63xx_internal_irq_unmask,
390};
391
392static struct irq_chip bcm63xx_external_irq_chip = {
393 .name = "bcm63xx_epic",
394 .irq_ack = bcm63xx_external_irq_clear,
395
396 .irq_mask = bcm63xx_external_irq_mask,
397 .irq_unmask = bcm63xx_external_irq_unmask,
398
399 .irq_set_type = bcm63xx_external_irq_set_type,
400};
401
402static void bcm63xx_init_irq(void)
403{
404 int irq_bits;
405
406 irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
407 irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
408 irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
409 irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
410
411 switch (bcm63xx_get_cpu_id()) {
412 case BCM3368_CPU_ID:
413 irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
414 irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
415 irq_stat_addr[1] = 0;
416 irq_mask_addr[1] = 0;
417 irq_bits = 32;
418 ext_irq_count = 4;
419 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
420 break;
421 case BCM6328_CPU_ID:
422 irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
423 irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
424 irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
425 irq_mask_addr[1] += PERF_IRQMASK_6328_REG(1);
426 irq_bits = 64;
427 ext_irq_count = 4;
428 is_ext_irq_cascaded = 1;
429 ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
430 ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
431 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
432 break;
433 case BCM6338_CPU_ID:
434 irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
435 irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
436 irq_stat_addr[1] = 0;
437 irq_mask_addr[1] = 0;
438 irq_bits = 32;
439 ext_irq_count = 4;
440 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
441 break;
442 case BCM6345_CPU_ID:
443 irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
444 irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
445 irq_stat_addr[1] = 0;
446 irq_mask_addr[1] = 0;
447 irq_bits = 32;
448 ext_irq_count = 4;
449 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
450 break;
451 case BCM6348_CPU_ID:
452 irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
453 irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
454 irq_stat_addr[1] = 0;
455 irq_mask_addr[1] = 0;
456 irq_bits = 32;
457 ext_irq_count = 4;
458 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
459 break;
460 case BCM6358_CPU_ID:
461 irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
462 irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
463 irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
464 irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
465 irq_bits = 32;
466 ext_irq_count = 4;
467 is_ext_irq_cascaded = 1;
468 ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
469 ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
470 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
471 break;
472 case BCM6362_CPU_ID:
473 irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
474 irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
475 irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
476 irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
477 irq_bits = 64;
478 ext_irq_count = 4;
479 is_ext_irq_cascaded = 1;
480 ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
481 ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
482 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
483 break;
484 case BCM6368_CPU_ID:
485 irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
486 irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
487 irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
488 irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
489 irq_bits = 64;
490 ext_irq_count = 6;
491 is_ext_irq_cascaded = 1;
492 ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
493 ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
494 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
495 ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
496 break;
497 default:
498 BUG();
499 }
500
501 if (irq_bits == 32) {
502 dispatch_internal = __dispatch_internal_32;
503 internal_irq_mask = __internal_irq_mask_32;
504 internal_irq_unmask = __internal_irq_unmask_32;
505 } else {
506 dispatch_internal = __dispatch_internal_64;
507 internal_irq_mask = __internal_irq_mask_64;
508 internal_irq_unmask = __internal_irq_unmask_64;
509 }
510}
511
512void __init arch_init_irq(void)
513{
514 int i, irq;
515
516 bcm63xx_init_irq();
517 mips_cpu_irq_init();
518 for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
519 irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
520 handle_level_irq);
521
522 for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
523 irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
524 handle_edge_irq);
525
526 if (!is_ext_irq_cascaded) {
527 for (i = 3; i < 3 + ext_irq_count; ++i) {
528 irq = MIPS_CPU_IRQ_BASE + i;
529 if (request_irq(irq, no_action, IRQF_NO_THREAD,
530 "cascade_extirq", NULL)) {
531 pr_err("Failed to request irq %d (cascade_extirq)\n",
532 irq);
533 }
534 }
535 }
536
537 irq = MIPS_CPU_IRQ_BASE + 2;
538 if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade_ip2", NULL))
539 pr_err("Failed to request irq %d (cascade_ip2)\n", irq);
540#ifdef CONFIG_SMP
541 if (is_ext_irq_cascaded) {
542 irq = MIPS_CPU_IRQ_BASE + 3;
543 if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade_ip3",
544 NULL))
545 pr_err("Failed to request irq %d (cascade_ip3)\n", irq);
546 bcm63xx_internal_irq_chip.irq_set_affinity =
547 bcm63xx_internal_set_affinity;
548
549 cpumask_clear(irq_default_affinity);
550 cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
551 }
552#endif
553}
diff --git a/arch/mips/bcm63xx/nvram.c b/arch/mips/bcm63xx/nvram.c
new file mode 100644
index 000000000..05757aed0
--- /dev/null
+++ b/arch/mips/bcm63xx/nvram.c
@@ -0,0 +1,98 @@
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 * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
9 */
10
11#define pr_fmt(fmt) "bcm63xx_nvram: " fmt
12
13#include <linux/bcm963xx_nvram.h>
14#include <linux/init.h>
15#include <linux/crc32.h>
16#include <linux/export.h>
17#include <linux/kernel.h>
18#include <linux/if_ether.h>
19
20#include <bcm63xx_nvram.h>
21
22#define BCM63XX_DEFAULT_PSI_SIZE 64
23
24static struct bcm963xx_nvram nvram;
25static int mac_addr_used;
26
27void __init bcm63xx_nvram_init(void *addr)
28{
29 u32 crc, expected_crc;
30 u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff };
31
32 /* extract nvram data */
33 memcpy(&nvram, addr, BCM963XX_NVRAM_V5_SIZE);
34
35 /* check checksum before using data */
36 if (bcm963xx_nvram_checksum(&nvram, &expected_crc, &crc))
37 pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
38 expected_crc, crc);
39
40 /* Cable modems have a different NVRAM which is embedded in the eCos
41 * firmware and not easily extractible, give at least a MAC address
42 * pool.
43 */
44 if (BCMCPU_IS_3368()) {
45 memcpy(nvram.mac_addr_base, hcs_mac_addr, ETH_ALEN);
46 nvram.mac_addr_count = 2;
47 }
48}
49
50u8 *bcm63xx_nvram_get_name(void)
51{
52 return nvram.name;
53}
54EXPORT_SYMBOL(bcm63xx_nvram_get_name);
55
56int bcm63xx_nvram_get_mac_address(u8 *mac)
57{
58 u8 *oui;
59 int count;
60
61 if (mac_addr_used >= nvram.mac_addr_count) {
62 pr_err("not enough mac addresses\n");
63 return -ENODEV;
64 }
65
66 memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
67 oui = mac + ETH_ALEN/2 - 1;
68 count = mac_addr_used;
69
70 while (count--) {
71 u8 *p = mac + ETH_ALEN - 1;
72
73 do {
74 (*p)++;
75 if (*p != 0)
76 break;
77 p--;
78 } while (p != oui);
79
80 if (p == oui) {
81 pr_err("unable to fetch mac address\n");
82 return -ENODEV;
83 }
84 }
85
86 mac_addr_used++;
87 return 0;
88}
89EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
90
91int bcm63xx_nvram_get_psi_size(void)
92{
93 if (nvram.psi_size > 0)
94 return nvram.psi_size;
95
96 return BCM63XX_DEFAULT_PSI_SIZE;
97}
98EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);
diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c
new file mode 100644
index 000000000..df69eaa45
--- /dev/null
+++ b/arch/mips/bcm63xx/prom.c
@@ -0,0 +1,100 @@
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/memblock.h>
11#include <linux/smp.h>
12#include <asm/bootinfo.h>
13#include <asm/bmips.h>
14#include <asm/smp-ops.h>
15#include <asm/mipsregs.h>
16#include <bcm63xx_board.h>
17#include <bcm63xx_cpu.h>
18#include <bcm63xx_io.h>
19#include <bcm63xx_regs.h>
20
21void __init prom_init(void)
22{
23 u32 reg, mask;
24
25 bcm63xx_cpu_init();
26
27 /* stop any running watchdog */
28 bcm_wdt_writel(WDT_STOP_1, WDT_CTL_REG);
29 bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG);
30
31 /* disable all hardware blocks clock for now */
32 if (BCMCPU_IS_3368())
33 mask = CKCTL_3368_ALL_SAFE_EN;
34 else if (BCMCPU_IS_6328())
35 mask = CKCTL_6328_ALL_SAFE_EN;
36 else if (BCMCPU_IS_6338())
37 mask = CKCTL_6338_ALL_SAFE_EN;
38 else if (BCMCPU_IS_6345())
39 mask = CKCTL_6345_ALL_SAFE_EN;
40 else if (BCMCPU_IS_6348())
41 mask = CKCTL_6348_ALL_SAFE_EN;
42 else if (BCMCPU_IS_6358())
43 mask = CKCTL_6358_ALL_SAFE_EN;
44 else if (BCMCPU_IS_6362())
45 mask = CKCTL_6362_ALL_SAFE_EN;
46 else if (BCMCPU_IS_6368())
47 mask = CKCTL_6368_ALL_SAFE_EN;
48 else
49 mask = 0;
50
51 reg = bcm_perf_readl(PERF_CKCTL_REG);
52 reg &= ~mask;
53 bcm_perf_writel(reg, PERF_CKCTL_REG);
54
55 /* do low level board init */
56 board_prom_init();
57
58 /* set up SMP */
59 if (!register_bmips_smp_ops()) {
60 /*
61 * BCM6328 might not have its second CPU enabled, while BCM3368
62 * and BCM6358 need special handling for their shared TLB, so
63 * disable SMP for now.
64 */
65 if (BCMCPU_IS_6328()) {
66 reg = bcm_readl(BCM_6328_OTP_BASE +
67 OTP_USER_BITS_6328_REG(3));
68
69 if (reg & OTP_6328_REG3_TP1_DISABLED)
70 bmips_smp_enabled = 0;
71 } else if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
72 bmips_smp_enabled = 0;
73 }
74
75 if (!bmips_smp_enabled)
76 return;
77
78 /*
79 * The bootloader has set up the CPU1 reset vector at
80 * 0xa000_0200.
81 * This conflicts with the special interrupt vector (IV).
82 * The bootloader has also set up CPU1 to respond to the wrong
83 * IPI interrupt.
84 * Here we will start up CPU1 in the background and ask it to
85 * reconfigure itself then go back to sleep.
86 */
87 memcpy((void *)0xa0000200, bmips_smp_movevec, 0x20);
88 __sync();
89 set_c0_cause(C_SW0);
90 cpumask_set_cpu(1, &bmips_booted_mask);
91
92 /*
93 * FIXME: we really should have some sort of hazard barrier here
94 */
95 }
96}
97
98void __init prom_free_prom_memory(void)
99{
100}
diff --git a/arch/mips/bcm63xx/reset.c b/arch/mips/bcm63xx/reset.c
new file mode 100644
index 000000000..64574e74c
--- /dev/null
+++ b/arch/mips/bcm63xx/reset.c
@@ -0,0 +1,219 @@
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) 2012 Jonas Gorski <jonas.gorski@gmail.com>
7 */
8
9#include <linux/init.h>
10#include <linux/export.h>
11#include <linux/mutex.h>
12#include <linux/err.h>
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <bcm63xx_cpu.h>
16#include <bcm63xx_io.h>
17#include <bcm63xx_regs.h>
18#include <bcm63xx_reset.h>
19
20#define __GEN_RESET_BITS_TABLE(__cpu) \
21 [BCM63XX_RESET_SPI] = BCM## __cpu ##_RESET_SPI, \
22 [BCM63XX_RESET_ENET] = BCM## __cpu ##_RESET_ENET, \
23 [BCM63XX_RESET_USBH] = BCM## __cpu ##_RESET_USBH, \
24 [BCM63XX_RESET_USBD] = BCM## __cpu ##_RESET_USBD, \
25 [BCM63XX_RESET_DSL] = BCM## __cpu ##_RESET_DSL, \
26 [BCM63XX_RESET_SAR] = BCM## __cpu ##_RESET_SAR, \
27 [BCM63XX_RESET_EPHY] = BCM## __cpu ##_RESET_EPHY, \
28 [BCM63XX_RESET_ENETSW] = BCM## __cpu ##_RESET_ENETSW, \
29 [BCM63XX_RESET_PCM] = BCM## __cpu ##_RESET_PCM, \
30 [BCM63XX_RESET_MPI] = BCM## __cpu ##_RESET_MPI, \
31 [BCM63XX_RESET_PCIE] = BCM## __cpu ##_RESET_PCIE, \
32 [BCM63XX_RESET_PCIE_EXT] = BCM## __cpu ##_RESET_PCIE_EXT,
33
34#define BCM3368_RESET_SPI SOFTRESET_3368_SPI_MASK
35#define BCM3368_RESET_ENET SOFTRESET_3368_ENET_MASK
36#define BCM3368_RESET_USBH 0
37#define BCM3368_RESET_USBD SOFTRESET_3368_USBS_MASK
38#define BCM3368_RESET_DSL 0
39#define BCM3368_RESET_SAR 0
40#define BCM3368_RESET_EPHY SOFTRESET_3368_EPHY_MASK
41#define BCM3368_RESET_ENETSW 0
42#define BCM3368_RESET_PCM SOFTRESET_3368_PCM_MASK
43#define BCM3368_RESET_MPI SOFTRESET_3368_MPI_MASK
44#define BCM3368_RESET_PCIE 0
45#define BCM3368_RESET_PCIE_EXT 0
46
47#define BCM6328_RESET_SPI SOFTRESET_6328_SPI_MASK
48#define BCM6328_RESET_ENET 0
49#define BCM6328_RESET_USBH SOFTRESET_6328_USBH_MASK
50#define BCM6328_RESET_USBD SOFTRESET_6328_USBS_MASK
51#define BCM6328_RESET_DSL 0
52#define BCM6328_RESET_SAR SOFTRESET_6328_SAR_MASK
53#define BCM6328_RESET_EPHY SOFTRESET_6328_EPHY_MASK
54#define BCM6328_RESET_ENETSW SOFTRESET_6328_ENETSW_MASK
55#define BCM6328_RESET_PCM SOFTRESET_6328_PCM_MASK
56#define BCM6328_RESET_MPI 0
57#define BCM6328_RESET_PCIE \
58 (SOFTRESET_6328_PCIE_MASK | \
59 SOFTRESET_6328_PCIE_CORE_MASK | \
60 SOFTRESET_6328_PCIE_HARD_MASK)
61#define BCM6328_RESET_PCIE_EXT SOFTRESET_6328_PCIE_EXT_MASK
62
63#define BCM6338_RESET_SPI SOFTRESET_6338_SPI_MASK
64#define BCM6338_RESET_ENET SOFTRESET_6338_ENET_MASK
65#define BCM6338_RESET_USBH SOFTRESET_6338_USBH_MASK
66#define BCM6338_RESET_USBD SOFTRESET_6338_USBS_MASK
67#define BCM6338_RESET_DSL SOFTRESET_6338_ADSL_MASK
68#define BCM6338_RESET_SAR SOFTRESET_6338_SAR_MASK
69#define BCM6338_RESET_EPHY 0
70#define BCM6338_RESET_ENETSW 0
71#define BCM6338_RESET_PCM 0
72#define BCM6338_RESET_MPI 0
73#define BCM6338_RESET_PCIE 0
74#define BCM6338_RESET_PCIE_EXT 0
75
76#define BCM6348_RESET_SPI SOFTRESET_6348_SPI_MASK
77#define BCM6348_RESET_ENET SOFTRESET_6348_ENET_MASK
78#define BCM6348_RESET_USBH SOFTRESET_6348_USBH_MASK
79#define BCM6348_RESET_USBD SOFTRESET_6348_USBS_MASK
80#define BCM6348_RESET_DSL SOFTRESET_6348_ADSL_MASK
81#define BCM6348_RESET_SAR SOFTRESET_6348_SAR_MASK
82#define BCM6348_RESET_EPHY 0
83#define BCM6348_RESET_ENETSW 0
84#define BCM6348_RESET_PCM 0
85#define BCM6348_RESET_MPI 0
86#define BCM6348_RESET_PCIE 0
87#define BCM6348_RESET_PCIE_EXT 0
88
89#define BCM6358_RESET_SPI SOFTRESET_6358_SPI_MASK
90#define BCM6358_RESET_ENET SOFTRESET_6358_ENET_MASK
91#define BCM6358_RESET_USBH SOFTRESET_6358_USBH_MASK
92#define BCM6358_RESET_USBD 0
93#define BCM6358_RESET_DSL SOFTRESET_6358_ADSL_MASK
94#define BCM6358_RESET_SAR SOFTRESET_6358_SAR_MASK
95#define BCM6358_RESET_EPHY SOFTRESET_6358_EPHY_MASK
96#define BCM6358_RESET_ENETSW 0
97#define BCM6358_RESET_PCM SOFTRESET_6358_PCM_MASK
98#define BCM6358_RESET_MPI SOFTRESET_6358_MPI_MASK
99#define BCM6358_RESET_PCIE 0
100#define BCM6358_RESET_PCIE_EXT 0
101
102#define BCM6362_RESET_SPI SOFTRESET_6362_SPI_MASK
103#define BCM6362_RESET_ENET 0
104#define BCM6362_RESET_USBH SOFTRESET_6362_USBH_MASK
105#define BCM6362_RESET_USBD SOFTRESET_6362_USBS_MASK
106#define BCM6362_RESET_DSL 0
107#define BCM6362_RESET_SAR SOFTRESET_6362_SAR_MASK
108#define BCM6362_RESET_EPHY SOFTRESET_6362_EPHY_MASK
109#define BCM6362_RESET_ENETSW SOFTRESET_6362_ENETSW_MASK
110#define BCM6362_RESET_PCM SOFTRESET_6362_PCM_MASK
111#define BCM6362_RESET_MPI 0
112#define BCM6362_RESET_PCIE (SOFTRESET_6362_PCIE_MASK | \
113 SOFTRESET_6362_PCIE_CORE_MASK)
114#define BCM6362_RESET_PCIE_EXT SOFTRESET_6362_PCIE_EXT_MASK
115
116#define BCM6368_RESET_SPI SOFTRESET_6368_SPI_MASK
117#define BCM6368_RESET_ENET 0
118#define BCM6368_RESET_USBH SOFTRESET_6368_USBH_MASK
119#define BCM6368_RESET_USBD SOFTRESET_6368_USBS_MASK
120#define BCM6368_RESET_DSL 0
121#define BCM6368_RESET_SAR SOFTRESET_6368_SAR_MASK
122#define BCM6368_RESET_EPHY SOFTRESET_6368_EPHY_MASK
123#define BCM6368_RESET_ENETSW SOFTRESET_6368_ENETSW_MASK
124#define BCM6368_RESET_PCM SOFTRESET_6368_PCM_MASK
125#define BCM6368_RESET_MPI SOFTRESET_6368_MPI_MASK
126#define BCM6368_RESET_PCIE 0
127#define BCM6368_RESET_PCIE_EXT 0
128
129/*
130 * core reset bits
131 */
132static const u32 bcm3368_reset_bits[] = {
133 __GEN_RESET_BITS_TABLE(3368)
134};
135
136static const u32 bcm6328_reset_bits[] = {
137 __GEN_RESET_BITS_TABLE(6328)
138};
139
140static const u32 bcm6338_reset_bits[] = {
141 __GEN_RESET_BITS_TABLE(6338)
142};
143
144static const u32 bcm6348_reset_bits[] = {
145 __GEN_RESET_BITS_TABLE(6348)
146};
147
148static const u32 bcm6358_reset_bits[] = {
149 __GEN_RESET_BITS_TABLE(6358)
150};
151
152static const u32 bcm6362_reset_bits[] = {
153 __GEN_RESET_BITS_TABLE(6362)
154};
155
156static const u32 bcm6368_reset_bits[] = {
157 __GEN_RESET_BITS_TABLE(6368)
158};
159
160const u32 *bcm63xx_reset_bits;
161static int reset_reg;
162
163static int __init bcm63xx_reset_bits_init(void)
164{
165 if (BCMCPU_IS_3368()) {
166 reset_reg = PERF_SOFTRESET_6358_REG;
167 bcm63xx_reset_bits = bcm3368_reset_bits;
168 } else if (BCMCPU_IS_6328()) {
169 reset_reg = PERF_SOFTRESET_6328_REG;
170 bcm63xx_reset_bits = bcm6328_reset_bits;
171 } else if (BCMCPU_IS_6338()) {
172 reset_reg = PERF_SOFTRESET_REG;
173 bcm63xx_reset_bits = bcm6338_reset_bits;
174 } else if (BCMCPU_IS_6348()) {
175 reset_reg = PERF_SOFTRESET_REG;
176 bcm63xx_reset_bits = bcm6348_reset_bits;
177 } else if (BCMCPU_IS_6358()) {
178 reset_reg = PERF_SOFTRESET_6358_REG;
179 bcm63xx_reset_bits = bcm6358_reset_bits;
180 } else if (BCMCPU_IS_6362()) {
181 reset_reg = PERF_SOFTRESET_6362_REG;
182 bcm63xx_reset_bits = bcm6362_reset_bits;
183 } else if (BCMCPU_IS_6368()) {
184 reset_reg = PERF_SOFTRESET_6368_REG;
185 bcm63xx_reset_bits = bcm6368_reset_bits;
186 }
187
188 return 0;
189}
190
191static DEFINE_SPINLOCK(reset_mutex);
192
193static void __bcm63xx_core_set_reset(u32 mask, int enable)
194{
195 unsigned long flags;
196 u32 val;
197
198 if (!mask)
199 return;
200
201 spin_lock_irqsave(&reset_mutex, flags);
202 val = bcm_perf_readl(reset_reg);
203
204 if (enable)
205 val &= ~mask;
206 else
207 val |= mask;
208
209 bcm_perf_writel(val, reset_reg);
210 spin_unlock_irqrestore(&reset_mutex, flags);
211}
212
213void bcm63xx_core_set_reset(enum bcm63xx_core_reset core, int reset)
214{
215 __bcm63xx_core_set_reset(bcm63xx_reset_bits[core], reset);
216}
217EXPORT_SYMBOL(bcm63xx_core_set_reset);
218
219postcore_initcall(bcm63xx_reset_bits_init);
diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c
new file mode 100644
index 000000000..d811e3e03
--- /dev/null
+++ b/arch/mips/bcm63xx/setup.c
@@ -0,0 +1,170 @@
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/memblock.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#include <bcm63xx_gpio.h>
24
25void bcm63xx_machine_halt(void)
26{
27 pr_info("System halted\n");
28 while (1)
29 ;
30}
31
32static void bcm6348_a1_reboot(void)
33{
34 u32 reg;
35
36 /* soft reset all blocks */
37 pr_info("soft-resetting all blocks ...\n");
38 reg = bcm_perf_readl(PERF_SOFTRESET_REG);
39 reg &= ~SOFTRESET_6348_ALL;
40 bcm_perf_writel(reg, PERF_SOFTRESET_REG);
41 mdelay(10);
42
43 reg = bcm_perf_readl(PERF_SOFTRESET_REG);
44 reg |= SOFTRESET_6348_ALL;
45 bcm_perf_writel(reg, PERF_SOFTRESET_REG);
46 mdelay(10);
47
48 /* Jump to the power on address. */
49 pr_info("jumping to reset vector.\n");
50 /* set high vectors (base at 0xbfc00000 */
51 set_c0_status(ST0_BEV | ST0_ERL);
52 /* run uncached in kseg0 */
53 change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
54 __flush_cache_all();
55 /* remove all wired TLB entries */
56 write_c0_wired(0);
57 __asm__ __volatile__(
58 "jr\t%0"
59 :
60 : "r" (0xbfc00000));
61 while (1)
62 ;
63}
64
65void bcm63xx_machine_reboot(void)
66{
67 u32 reg, perf_regs[2] = { 0, 0 };
68 unsigned int i;
69
70 /* mask and clear all external irq */
71 switch (bcm63xx_get_cpu_id()) {
72 case BCM3368_CPU_ID:
73 perf_regs[0] = PERF_EXTIRQ_CFG_REG_3368;
74 break;
75 case BCM6328_CPU_ID:
76 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328;
77 break;
78 case BCM6338_CPU_ID:
79 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338;
80 break;
81 case BCM6345_CPU_ID:
82 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6345;
83 break;
84 case BCM6348_CPU_ID:
85 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348;
86 break;
87 case BCM6358_CPU_ID:
88 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358;
89 break;
90 case BCM6362_CPU_ID:
91 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6362;
92 break;
93 }
94
95 for (i = 0; i < 2; i++) {
96 if (!perf_regs[i])
97 break;
98
99 reg = bcm_perf_readl(perf_regs[i]);
100 if (BCMCPU_IS_6348()) {
101 reg &= ~EXTIRQ_CFG_MASK_ALL_6348;
102 reg |= EXTIRQ_CFG_CLEAR_ALL_6348;
103 } else {
104 reg &= ~EXTIRQ_CFG_MASK_ALL;
105 reg |= EXTIRQ_CFG_CLEAR_ALL;
106 }
107 bcm_perf_writel(reg, perf_regs[i]);
108 }
109
110 if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1))
111 bcm6348_a1_reboot();
112
113 pr_info("triggering watchdog soft-reset...\n");
114 if (BCMCPU_IS_6328()) {
115 bcm_wdt_writel(1, WDT_SOFTRESET_REG);
116 } else {
117 reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG);
118 reg |= SYS_PLL_SOFT_RESET;
119 bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG);
120 }
121 while (1)
122 ;
123}
124
125static void __bcm63xx_machine_reboot(char *p)
126{
127 bcm63xx_machine_reboot();
128}
129
130/*
131 * return system type in /proc/cpuinfo
132 */
133const char *get_system_type(void)
134{
135 static char buf[128];
136 snprintf(buf, sizeof(buf), "bcm63xx/%s (0x%04x/0x%02X)",
137 board_get_name(),
138 bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev());
139 return buf;
140}
141
142void __init plat_time_init(void)
143{
144 mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2;
145}
146
147void __init plat_mem_setup(void)
148{
149 memblock_add(0, bcm63xx_get_memory_size());
150
151 _machine_halt = bcm63xx_machine_halt;
152 _machine_restart = __bcm63xx_machine_reboot;
153 pm_power_off = bcm63xx_machine_halt;
154
155 set_io_port_base(0);
156 ioport_resource.start = 0;
157 ioport_resource.end = ~0;
158
159 board_setup();
160}
161
162int __init bcm63xx_register_devices(void)
163{
164 /* register gpiochip */
165 bcm63xx_gpio_init();
166
167 return board_register_devices();
168}
169
170arch_initcall(bcm63xx_register_devices);
diff --git a/arch/mips/bcm63xx/timer.c b/arch/mips/bcm63xx/timer.c
new file mode 100644
index 000000000..a86065854
--- /dev/null
+++ b/arch/mips/bcm63xx/timer.c
@@ -0,0 +1,206 @@
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/init.h>
12#include <linux/export.h>
13#include <linux/spinlock.h>
14#include <linux/interrupt.h>
15#include <linux/clk.h>
16#include <bcm63xx_cpu.h>
17#include <bcm63xx_io.h>
18#include <bcm63xx_timer.h>
19#include <bcm63xx_regs.h>
20
21static DEFINE_RAW_SPINLOCK(timer_reg_lock);
22static DEFINE_RAW_SPINLOCK(timer_data_lock);
23static struct clk *periph_clk;
24
25static struct timer_data {
26 void (*cb)(void *);
27 void *data;
28} timer_data[BCM63XX_TIMER_COUNT];
29
30static irqreturn_t timer_interrupt(int irq, void *dev_id)
31{
32 u32 stat;
33 int i;
34
35 raw_spin_lock(&timer_reg_lock);
36 stat = bcm_timer_readl(TIMER_IRQSTAT_REG);
37 bcm_timer_writel(stat, TIMER_IRQSTAT_REG);
38 raw_spin_unlock(&timer_reg_lock);
39
40 for (i = 0; i < BCM63XX_TIMER_COUNT; i++) {
41 if (!(stat & TIMER_IRQSTAT_TIMER_CAUSE(i)))
42 continue;
43
44 raw_spin_lock(&timer_data_lock);
45 if (!timer_data[i].cb) {
46 raw_spin_unlock(&timer_data_lock);
47 continue;
48 }
49
50 timer_data[i].cb(timer_data[i].data);
51 raw_spin_unlock(&timer_data_lock);
52 }
53
54 return IRQ_HANDLED;
55}
56
57int bcm63xx_timer_enable(int id)
58{
59 u32 reg;
60 unsigned long flags;
61
62 if (id >= BCM63XX_TIMER_COUNT)
63 return -EINVAL;
64
65 raw_spin_lock_irqsave(&timer_reg_lock, flags);
66
67 reg = bcm_timer_readl(TIMER_CTLx_REG(id));
68 reg |= TIMER_CTL_ENABLE_MASK;
69 bcm_timer_writel(reg, TIMER_CTLx_REG(id));
70
71 reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
72 reg |= TIMER_IRQSTAT_TIMER_IR_EN(id);
73 bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
74
75 raw_spin_unlock_irqrestore(&timer_reg_lock, flags);
76 return 0;
77}
78
79EXPORT_SYMBOL(bcm63xx_timer_enable);
80
81int bcm63xx_timer_disable(int id)
82{
83 u32 reg;
84 unsigned long flags;
85
86 if (id >= BCM63XX_TIMER_COUNT)
87 return -EINVAL;
88
89 raw_spin_lock_irqsave(&timer_reg_lock, flags);
90
91 reg = bcm_timer_readl(TIMER_CTLx_REG(id));
92 reg &= ~TIMER_CTL_ENABLE_MASK;
93 bcm_timer_writel(reg, TIMER_CTLx_REG(id));
94
95 reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
96 reg &= ~TIMER_IRQSTAT_TIMER_IR_EN(id);
97 bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
98
99 raw_spin_unlock_irqrestore(&timer_reg_lock, flags);
100 return 0;
101}
102
103EXPORT_SYMBOL(bcm63xx_timer_disable);
104
105int bcm63xx_timer_register(int id, void (*callback)(void *data), void *data)
106{
107 unsigned long flags;
108 int ret;
109
110 if (id >= BCM63XX_TIMER_COUNT || !callback)
111 return -EINVAL;
112
113 ret = 0;
114 raw_spin_lock_irqsave(&timer_data_lock, flags);
115 if (timer_data[id].cb) {
116 ret = -EBUSY;
117 goto out;
118 }
119
120 timer_data[id].cb = callback;
121 timer_data[id].data = data;
122
123out:
124 raw_spin_unlock_irqrestore(&timer_data_lock, flags);
125 return ret;
126}
127
128EXPORT_SYMBOL(bcm63xx_timer_register);
129
130void bcm63xx_timer_unregister(int id)
131{
132 unsigned long flags;
133
134 if (id >= BCM63XX_TIMER_COUNT)
135 return;
136
137 raw_spin_lock_irqsave(&timer_data_lock, flags);
138 timer_data[id].cb = NULL;
139 raw_spin_unlock_irqrestore(&timer_data_lock, flags);
140}
141
142EXPORT_SYMBOL(bcm63xx_timer_unregister);
143
144unsigned int bcm63xx_timer_countdown(unsigned int countdown_us)
145{
146 return (clk_get_rate(periph_clk) / (1000 * 1000)) * countdown_us;
147}
148
149EXPORT_SYMBOL(bcm63xx_timer_countdown);
150
151int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us)
152{
153 u32 reg, countdown;
154 unsigned long flags;
155
156 if (id >= BCM63XX_TIMER_COUNT)
157 return -EINVAL;
158
159 countdown = bcm63xx_timer_countdown(countdown_us);
160 if (countdown & ~TIMER_CTL_COUNTDOWN_MASK)
161 return -EINVAL;
162
163 raw_spin_lock_irqsave(&timer_reg_lock, flags);
164 reg = bcm_timer_readl(TIMER_CTLx_REG(id));
165
166 if (monotonic)
167 reg &= ~TIMER_CTL_MONOTONIC_MASK;
168 else
169 reg |= TIMER_CTL_MONOTONIC_MASK;
170
171 reg &= ~TIMER_CTL_COUNTDOWN_MASK;
172 reg |= countdown;
173 bcm_timer_writel(reg, TIMER_CTLx_REG(id));
174
175 raw_spin_unlock_irqrestore(&timer_reg_lock, flags);
176 return 0;
177}
178
179EXPORT_SYMBOL(bcm63xx_timer_set);
180
181int bcm63xx_timer_init(void)
182{
183 int ret, irq;
184 u32 reg;
185
186 reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
187 reg &= ~TIMER_IRQSTAT_TIMER0_IR_EN;
188 reg &= ~TIMER_IRQSTAT_TIMER1_IR_EN;
189 reg &= ~TIMER_IRQSTAT_TIMER2_IR_EN;
190 bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
191
192 periph_clk = clk_get(NULL, "periph");
193 if (IS_ERR(periph_clk))
194 return -ENODEV;
195
196 irq = bcm63xx_get_irq_number(IRQ_TIMER);
197 ret = request_irq(irq, timer_interrupt, 0, "bcm63xx_timer", NULL);
198 if (ret) {
199 pr_err("%s: failed to register irq\n", __func__);
200 return ret;
201 }
202
203 return 0;
204}
205
206arch_initcall(bcm63xx_timer_init);