diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/bcm63xx | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/bcm63xx')
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 | ||
2 | menu "CPU support" | ||
3 | depends on BCM63XX | ||
4 | |||
5 | config BCM63XX_CPU_3368 | ||
6 | bool "support 3368 CPU" | ||
7 | select SYS_HAS_CPU_BMIPS4350 | ||
8 | select HAVE_PCI | ||
9 | |||
10 | config BCM63XX_CPU_6328 | ||
11 | bool "support 6328 CPU" | ||
12 | select SYS_HAS_CPU_BMIPS4350 | ||
13 | select HAVE_PCI | ||
14 | |||
15 | config BCM63XX_CPU_6338 | ||
16 | bool "support 6338 CPU" | ||
17 | select SYS_HAS_CPU_BMIPS32_3300 | ||
18 | select HAVE_PCI | ||
19 | |||
20 | config BCM63XX_CPU_6345 | ||
21 | bool "support 6345 CPU" | ||
22 | select SYS_HAS_CPU_BMIPS32_3300 | ||
23 | |||
24 | config BCM63XX_CPU_6348 | ||
25 | bool "support 6348 CPU" | ||
26 | select SYS_HAS_CPU_BMIPS32_3300 | ||
27 | select HAVE_PCI | ||
28 | |||
29 | config BCM63XX_CPU_6358 | ||
30 | bool "support 6358 CPU" | ||
31 | select SYS_HAS_CPU_BMIPS4350 | ||
32 | select HAVE_PCI | ||
33 | |||
34 | config BCM63XX_CPU_6362 | ||
35 | bool "support 6362 CPU" | ||
36 | select SYS_HAS_CPU_BMIPS4350 | ||
37 | select HAVE_PCI | ||
38 | |||
39 | config BCM63XX_CPU_6368 | ||
40 | bool "support 6368 CPU" | ||
41 | select SYS_HAS_CPU_BMIPS4350 | ||
42 | select HAVE_PCI | ||
43 | endmenu | ||
44 | |||
45 | source "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 | ||
2 | obj-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 | ||
6 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
7 | |||
8 | obj-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 | # | ||
4 | cflags-$(CONFIG_BCM63XX) += \ | ||
5 | -I$(srctree)/arch/mips/include/asm/mach-bcm63xx/ | ||
6 | load-$(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 | ||
2 | choice | ||
3 | prompt "Board support" | ||
4 | depends on BCM63XX | ||
5 | default BOARD_BCM963XX | ||
6 | |||
7 | config BOARD_BCM963XX | ||
8 | bool "Generic Broadcom 963xx boards" | ||
9 | select SSB | ||
10 | |||
11 | endchoice | ||
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 | ||
2 | obj-$(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 | |||
34 | static struct board_info board; | ||
35 | |||
36 | /* | ||
37 | * known 3368 boards | ||
38 | */ | ||
39 | #ifdef CONFIG_BCM63XX_CPU_3368 | ||
40 | static 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 | ||
70 | static 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 | ||
118 | static 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 | |||
161 | static 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 | ||
208 | static 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 | ||
220 | static 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 | |||
264 | static 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 | |||
315 | static 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 | |||
366 | static 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 | |||
416 | static 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 | |||
438 | static 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 | |||
457 | static 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 | |||
478 | static 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 | ||
504 | static 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 | |||
554 | static 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 | |||
600 | static 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 | |||
622 | static 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 | */ | ||
647 | static 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 | ||
684 | static 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 | |||
705 | int 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 | */ | ||
720 | const 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 | */ | ||
728 | void __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 | */ | ||
834 | void __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 | |||
845 | static struct gpio_led_platform_data bcm63xx_led_data; | ||
846 | |||
847 | static 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 | */ | ||
856 | int __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 | |||
21 | struct clk { | ||
22 | void (*set)(struct clk *, int); | ||
23 | unsigned int rate; | ||
24 | unsigned int usage; | ||
25 | int id; | ||
26 | }; | ||
27 | |||
28 | static DEFINE_MUTEX(clocks_mutex); | ||
29 | |||
30 | |||
31 | static void clk_enable_unlocked(struct clk *clk) | ||
32 | { | ||
33 | if (clk->set && (clk->usage++) == 0) | ||
34 | clk->set(clk, 1); | ||
35 | } | ||
36 | |||
37 | static void clk_disable_unlocked(struct clk *clk) | ||
38 | { | ||
39 | if (clk->set && (--clk->usage) == 0) | ||
40 | clk->set(clk, 0); | ||
41 | } | ||
42 | |||
43 | static 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 | */ | ||
58 | static 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 | |||
74 | static 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 | */ | ||
82 | static 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 | |||
100 | static struct clk clk_enet0 = { | ||
101 | .id = 0, | ||
102 | .set = enetx_set, | ||
103 | }; | ||
104 | |||
105 | static struct clk clk_enet1 = { | ||
106 | .id = 1, | ||
107 | .set = enetx_set, | ||
108 | }; | ||
109 | |||
110 | /* | ||
111 | * Ethernet PHY clock | ||
112 | */ | ||
113 | static 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 | |||
120 | static struct clk clk_ephy = { | ||
121 | .set = ephy_set, | ||
122 | }; | ||
123 | |||
124 | /* | ||
125 | * Ethernet switch SAR clock | ||
126 | */ | ||
127 | static 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 | |||
135 | static struct clk clk_swpkt_sar = { | ||
136 | .set = swpkt_sar_set, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Ethernet switch USB clock | ||
141 | */ | ||
142 | static 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 | |||
150 | static struct clk clk_swpkt_usb = { | ||
151 | .set = swpkt_usb_set, | ||
152 | }; | ||
153 | |||
154 | /* | ||
155 | * Ethernet switch clock | ||
156 | */ | ||
157 | static 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 | |||
185 | static struct clk clk_enetsw = { | ||
186 | .set = enetsw_set, | ||
187 | }; | ||
188 | |||
189 | /* | ||
190 | * PCM clock | ||
191 | */ | ||
192 | static 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 | |||
200 | static struct clk clk_pcm = { | ||
201 | .set = pcm_set, | ||
202 | }; | ||
203 | |||
204 | /* | ||
205 | * USB host clock | ||
206 | */ | ||
207 | static 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 | |||
219 | static struct clk clk_usbh = { | ||
220 | .set = usbh_set, | ||
221 | }; | ||
222 | |||
223 | /* | ||
224 | * USB device clock | ||
225 | */ | ||
226 | static 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 | |||
236 | static struct clk clk_usbd = { | ||
237 | .set = usbd_set, | ||
238 | }; | ||
239 | |||
240 | /* | ||
241 | * SPI clock | ||
242 | */ | ||
243 | static 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 | |||
261 | static struct clk clk_spi = { | ||
262 | .set = spi_set, | ||
263 | }; | ||
264 | |||
265 | /* | ||
266 | * HSSPI clock | ||
267 | */ | ||
268 | static 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 | |||
282 | static struct clk clk_hsspi = { | ||
283 | .set = hsspi_set, | ||
284 | }; | ||
285 | |||
286 | /* | ||
287 | * HSSPI PLL | ||
288 | */ | ||
289 | static struct clk clk_hsspi_pll; | ||
290 | |||
291 | /* | ||
292 | * XTM clock | ||
293 | */ | ||
294 | static 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 | |||
316 | static struct clk clk_xtm = { | ||
317 | .set = xtm_set, | ||
318 | }; | ||
319 | |||
320 | /* | ||
321 | * IPsec clock | ||
322 | */ | ||
323 | static 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 | |||
331 | static struct clk clk_ipsec = { | ||
332 | .set = ipsec_set, | ||
333 | }; | ||
334 | |||
335 | /* | ||
336 | * PCIe clock | ||
337 | */ | ||
338 | |||
339 | static 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 | |||
347 | static struct clk clk_pcie = { | ||
348 | .set = pcie_set, | ||
349 | }; | ||
350 | |||
351 | /* | ||
352 | * Internal peripheral clock | ||
353 | */ | ||
354 | static struct clk clk_periph = { | ||
355 | .rate = (50 * 1000 * 1000), | ||
356 | }; | ||
357 | |||
358 | |||
359 | /* | ||
360 | * Linux clock API implementation | ||
361 | */ | ||
362 | int 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 | |||
372 | EXPORT_SYMBOL(clk_enable); | ||
373 | |||
374 | void 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 | |||
384 | EXPORT_SYMBOL(clk_disable); | ||
385 | |||
386 | struct clk *clk_get_parent(struct clk *clk) | ||
387 | { | ||
388 | return NULL; | ||
389 | } | ||
390 | EXPORT_SYMBOL(clk_get_parent); | ||
391 | |||
392 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
393 | { | ||
394 | return 0; | ||
395 | } | ||
396 | EXPORT_SYMBOL(clk_set_parent); | ||
397 | |||
398 | unsigned long clk_get_rate(struct clk *clk) | ||
399 | { | ||
400 | if (!clk) | ||
401 | return 0; | ||
402 | |||
403 | return clk->rate; | ||
404 | } | ||
405 | |||
406 | EXPORT_SYMBOL(clk_get_rate); | ||
407 | |||
408 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
409 | { | ||
410 | return 0; | ||
411 | } | ||
412 | EXPORT_SYMBOL_GPL(clk_set_rate); | ||
413 | |||
414 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
415 | { | ||
416 | return 0; | ||
417 | } | ||
418 | EXPORT_SYMBOL_GPL(clk_round_rate); | ||
419 | |||
420 | static 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 | |||
437 | static 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 | |||
451 | static 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 | |||
465 | static 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 | |||
479 | static 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 | |||
494 | static 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 | |||
513 | static 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 | |||
529 | static 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 | |||
546 | static 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 | } | ||
579 | arch_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 | |||
21 | const unsigned long *bcm63xx_regs_base; | ||
22 | EXPORT_SYMBOL(bcm63xx_regs_base); | ||
23 | |||
24 | const int *bcm63xx_irqs; | ||
25 | EXPORT_SYMBOL(bcm63xx_irqs); | ||
26 | |||
27 | u16 bcm63xx_cpu_id __read_mostly; | ||
28 | EXPORT_SYMBOL(bcm63xx_cpu_id); | ||
29 | |||
30 | static u8 bcm63xx_cpu_rev; | ||
31 | static unsigned int bcm63xx_cpu_freq; | ||
32 | static unsigned int bcm63xx_memory_size; | ||
33 | |||
34 | static const unsigned long bcm3368_regs_base[] = { | ||
35 | __GEN_CPU_REGS_TABLE(3368) | ||
36 | }; | ||
37 | |||
38 | static const int bcm3368_irqs[] = { | ||
39 | __GEN_CPU_IRQ_TABLE(3368) | ||
40 | }; | ||
41 | |||
42 | static const unsigned long bcm6328_regs_base[] = { | ||
43 | __GEN_CPU_REGS_TABLE(6328) | ||
44 | }; | ||
45 | |||
46 | static const int bcm6328_irqs[] = { | ||
47 | __GEN_CPU_IRQ_TABLE(6328) | ||
48 | }; | ||
49 | |||
50 | static const unsigned long bcm6338_regs_base[] = { | ||
51 | __GEN_CPU_REGS_TABLE(6338) | ||
52 | }; | ||
53 | |||
54 | static const int bcm6338_irqs[] = { | ||
55 | __GEN_CPU_IRQ_TABLE(6338) | ||
56 | }; | ||
57 | |||
58 | static const unsigned long bcm6345_regs_base[] = { | ||
59 | __GEN_CPU_REGS_TABLE(6345) | ||
60 | }; | ||
61 | |||
62 | static const int bcm6345_irqs[] = { | ||
63 | __GEN_CPU_IRQ_TABLE(6345) | ||
64 | }; | ||
65 | |||
66 | static const unsigned long bcm6348_regs_base[] = { | ||
67 | __GEN_CPU_REGS_TABLE(6348) | ||
68 | }; | ||
69 | |||
70 | static const int bcm6348_irqs[] = { | ||
71 | __GEN_CPU_IRQ_TABLE(6348) | ||
72 | |||
73 | }; | ||
74 | |||
75 | static const unsigned long bcm6358_regs_base[] = { | ||
76 | __GEN_CPU_REGS_TABLE(6358) | ||
77 | }; | ||
78 | |||
79 | static const int bcm6358_irqs[] = { | ||
80 | __GEN_CPU_IRQ_TABLE(6358) | ||
81 | |||
82 | }; | ||
83 | |||
84 | static const unsigned long bcm6362_regs_base[] = { | ||
85 | __GEN_CPU_REGS_TABLE(6362) | ||
86 | }; | ||
87 | |||
88 | static const int bcm6362_irqs[] = { | ||
89 | __GEN_CPU_IRQ_TABLE(6362) | ||
90 | |||
91 | }; | ||
92 | |||
93 | static const unsigned long bcm6368_regs_base[] = { | ||
94 | __GEN_CPU_REGS_TABLE(6368) | ||
95 | }; | ||
96 | |||
97 | static const int bcm6368_irqs[] = { | ||
98 | __GEN_CPU_IRQ_TABLE(6368) | ||
99 | |||
100 | }; | ||
101 | |||
102 | u8 bcm63xx_get_cpu_rev(void) | ||
103 | { | ||
104 | return bcm63xx_cpu_rev; | ||
105 | } | ||
106 | |||
107 | EXPORT_SYMBOL(bcm63xx_get_cpu_rev); | ||
108 | |||
109 | unsigned int bcm63xx_get_cpu_freq(void) | ||
110 | { | ||
111 | return bcm63xx_cpu_freq; | ||
112 | } | ||
113 | |||
114 | unsigned int bcm63xx_get_memory_size(void) | ||
115 | { | ||
116 | return bcm63xx_memory_size; | ||
117 | } | ||
118 | |||
119 | static 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 | */ | ||
256 | static 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 | |||
294 | void __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 | |||
19 | static DEFINE_SPINLOCK(bcm63xx_cs_lock); | ||
20 | |||
21 | /* | ||
22 | * check if given chip select exists | ||
23 | */ | ||
24 | static 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 | */ | ||
35 | int 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 | |||
61 | EXPORT_SYMBOL(bcm63xx_set_cs_base); | ||
62 | |||
63 | /* | ||
64 | * configure chipselect timing (ns) | ||
65 | */ | ||
66 | int 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 | |||
89 | EXPORT_SYMBOL(bcm63xx_set_cs_timing); | ||
90 | |||
91 | /* | ||
92 | * configure other chipselect parameter (data bus size, ...) | ||
93 | */ | ||
94 | int 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 | |||
121 | EXPORT_SYMBOL(bcm63xx_set_cs_param); | ||
122 | |||
123 | /* | ||
124 | * set cs status (enable/disable) | ||
125 | */ | ||
126 | int 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 | |||
145 | EXPORT_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 | |||
17 | static 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 | |||
24 | static 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 | |||
35 | const unsigned long *bcm63xx_regs_enetdmac; | ||
36 | EXPORT_SYMBOL(bcm63xx_regs_enetdmac); | ||
37 | |||
38 | static __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 | |||
46 | static 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 | |||
64 | static 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 | |||
71 | static int shared_device_registered; | ||
72 | |||
73 | static u64 enet_dmamask = DMA_BIT_MASK(32); | ||
74 | |||
75 | static 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 | |||
95 | static struct bcm63xx_enet_platform_data enet0_pd; | ||
96 | |||
97 | static 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 | |||
109 | static 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 | |||
129 | static struct bcm63xx_enet_platform_data enet1_pd; | ||
130 | |||
131 | static 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 | |||
143 | static 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 | |||
158 | static struct bcm63xx_enetsw_platform_data enetsw_pd; | ||
159 | |||
160 | static 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 | |||
171 | static 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 | |||
210 | int __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 | |||
290 | int __init | ||
291 | bcm63xx_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 | |||
25 | static struct mtd_partition mtd_partitions[] = { | ||
26 | { | ||
27 | .name = "cfe", | ||
28 | .offset = 0x0, | ||
29 | .size = 0x40000, | ||
30 | } | ||
31 | }; | ||
32 | |||
33 | static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL }; | ||
34 | |||
35 | static struct physmap_flash_data flash_data = { | ||
36 | .width = 2, | ||
37 | .parts = mtd_partitions, | ||
38 | .part_probe_types = bcm63xx_part_types, | ||
39 | }; | ||
40 | |||
41 | static struct resource mtd_resources[] = { | ||
42 | { | ||
43 | .start = 0, /* filled at runtime */ | ||
44 | .end = 0, /* filled at runtime */ | ||
45 | .flags = IORESOURCE_MEM, | ||
46 | } | ||
47 | }; | ||
48 | |||
49 | static 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 | |||
58 | static 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 | |||
103 | int __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 | |||
17 | static 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 | |||
29 | static 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 | |||
36 | int __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 | |||
19 | static 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 | |||
57 | static struct bcm63xx_pcmcia_platform_data pd; | ||
58 | |||
59 | static 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 | |||
69 | static 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 | |||
82 | static 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 | |||
104 | int __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 | |||
141 | out_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 | |||
14 | static struct resource rng_resources[] = { | ||
15 | { | ||
16 | .start = -1, /* filled at runtime */ | ||
17 | .end = -1, /* filled at runtime */ | ||
18 | .flags = IORESOURCE_MEM, | ||
19 | }, | ||
20 | }; | ||
21 | |||
22 | static 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 | |||
29 | int __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 | } | ||
40 | arch_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 | |||
21 | static 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 | |||
33 | static struct platform_device bcm63xx_spi_device = { | ||
34 | .id = -1, | ||
35 | .num_resources = ARRAY_SIZE(spi_resources), | ||
36 | .resource = spi_resources, | ||
37 | }; | ||
38 | |||
39 | int __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 | |||
14 | static 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 | |||
25 | static 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 | |||
36 | static 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 | |||
52 | int __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 | |||
21 | static struct resource usbd_resources[NUM_MMIO + NUM_IRQ]; | ||
22 | |||
23 | static u64 usbd_dmamask = DMA_BIT_MASK(32); | ||
24 | |||
25 | static 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 | |||
36 | int __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 | |||
14 | static struct resource wdt_resources[] = { | ||
15 | { | ||
16 | .start = -1, /* filled at runtime */ | ||
17 | .end = -1, /* filled at runtime */ | ||
18 | .flags = IORESOURCE_MEM, | ||
19 | }, | ||
20 | }; | ||
21 | |||
22 | static 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 | |||
29 | int __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 | } | ||
37 | arch_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 | |||
13 | static 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 | |||
25 | void 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 | |||
21 | static u32 gpio_out_low_reg; | ||
22 | |||
23 | static 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 | |||
35 | static DEFINE_SPINLOCK(bcm63xx_gpio_lock); | ||
36 | static u32 gpio_out_low, gpio_out_high; | ||
37 | |||
38 | static 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 | |||
68 | static 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 | |||
87 | static 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 | |||
118 | static 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 | |||
123 | static 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 | |||
131 | static 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 | |||
140 | int __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 | |||
23 | static DEFINE_SPINLOCK(ipic_lock); | ||
24 | static DEFINE_SPINLOCK(epic_lock); | ||
25 | |||
26 | static u32 irq_stat_addr[2]; | ||
27 | static u32 irq_mask_addr[2]; | ||
28 | static void (*dispatch_internal)(int cpu); | ||
29 | static int is_ext_irq_cascaded; | ||
30 | static unsigned int ext_irq_count; | ||
31 | static unsigned int ext_irq_start, ext_irq_end; | ||
32 | static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; | ||
33 | static void (*internal_irq_mask)(struct irq_data *d); | ||
34 | static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m); | ||
35 | |||
36 | |||
37 | static 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 | |||
44 | static 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 | |||
53 | static 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) \ | ||
75 | void __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 | \ | ||
112 | static 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 | \ | ||
133 | static 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 | |||
158 | BUILD_IPIC_INTERNAL(32); | ||
159 | BUILD_IPIC_INTERNAL(64); | ||
160 | |||
161 | asmlinkage 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 | */ | ||
199 | static void bcm63xx_internal_irq_mask(struct irq_data *d) | ||
200 | { | ||
201 | internal_irq_mask(d); | ||
202 | } | ||
203 | |||
204 | static 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 | */ | ||
213 | static 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 | |||
235 | static 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 | |||
258 | static 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 | |||
277 | static 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 | ||
375 | static 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 | |||
386 | static 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 | |||
392 | static 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 | |||
402 | static 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 | |||
512 | void __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 | |||
24 | static struct bcm963xx_nvram nvram; | ||
25 | static int mac_addr_used; | ||
26 | |||
27 | void __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 | |||
50 | u8 *bcm63xx_nvram_get_name(void) | ||
51 | { | ||
52 | return nvram.name; | ||
53 | } | ||
54 | EXPORT_SYMBOL(bcm63xx_nvram_get_name); | ||
55 | |||
56 | int 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 | } | ||
89 | EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address); | ||
90 | |||
91 | int 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 | } | ||
98 | EXPORT_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 | |||
21 | void __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 | |||
98 | void __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 | */ | ||
132 | static const u32 bcm3368_reset_bits[] = { | ||
133 | __GEN_RESET_BITS_TABLE(3368) | ||
134 | }; | ||
135 | |||
136 | static const u32 bcm6328_reset_bits[] = { | ||
137 | __GEN_RESET_BITS_TABLE(6328) | ||
138 | }; | ||
139 | |||
140 | static const u32 bcm6338_reset_bits[] = { | ||
141 | __GEN_RESET_BITS_TABLE(6338) | ||
142 | }; | ||
143 | |||
144 | static const u32 bcm6348_reset_bits[] = { | ||
145 | __GEN_RESET_BITS_TABLE(6348) | ||
146 | }; | ||
147 | |||
148 | static const u32 bcm6358_reset_bits[] = { | ||
149 | __GEN_RESET_BITS_TABLE(6358) | ||
150 | }; | ||
151 | |||
152 | static const u32 bcm6362_reset_bits[] = { | ||
153 | __GEN_RESET_BITS_TABLE(6362) | ||
154 | }; | ||
155 | |||
156 | static const u32 bcm6368_reset_bits[] = { | ||
157 | __GEN_RESET_BITS_TABLE(6368) | ||
158 | }; | ||
159 | |||
160 | const u32 *bcm63xx_reset_bits; | ||
161 | static int reset_reg; | ||
162 | |||
163 | static 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 | |||
191 | static DEFINE_SPINLOCK(reset_mutex); | ||
192 | |||
193 | static 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 | |||
213 | void bcm63xx_core_set_reset(enum bcm63xx_core_reset core, int reset) | ||
214 | { | ||
215 | __bcm63xx_core_set_reset(bcm63xx_reset_bits[core], reset); | ||
216 | } | ||
217 | EXPORT_SYMBOL(bcm63xx_core_set_reset); | ||
218 | |||
219 | postcore_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 | |||
25 | void bcm63xx_machine_halt(void) | ||
26 | { | ||
27 | pr_info("System halted\n"); | ||
28 | while (1) | ||
29 | ; | ||
30 | } | ||
31 | |||
32 | static 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 | |||
65 | void 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 | |||
125 | static void __bcm63xx_machine_reboot(char *p) | ||
126 | { | ||
127 | bcm63xx_machine_reboot(); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * return system type in /proc/cpuinfo | ||
132 | */ | ||
133 | const 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 | |||
142 | void __init plat_time_init(void) | ||
143 | { | ||
144 | mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2; | ||
145 | } | ||
146 | |||
147 | void __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 | |||
162 | int __init bcm63xx_register_devices(void) | ||
163 | { | ||
164 | /* register gpiochip */ | ||
165 | bcm63xx_gpio_init(); | ||
166 | |||
167 | return board_register_devices(); | ||
168 | } | ||
169 | |||
170 | arch_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 | |||
21 | static DEFINE_RAW_SPINLOCK(timer_reg_lock); | ||
22 | static DEFINE_RAW_SPINLOCK(timer_data_lock); | ||
23 | static struct clk *periph_clk; | ||
24 | |||
25 | static struct timer_data { | ||
26 | void (*cb)(void *); | ||
27 | void *data; | ||
28 | } timer_data[BCM63XX_TIMER_COUNT]; | ||
29 | |||
30 | static 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 | |||
57 | int 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 | |||
79 | EXPORT_SYMBOL(bcm63xx_timer_enable); | ||
80 | |||
81 | int 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 | |||
103 | EXPORT_SYMBOL(bcm63xx_timer_disable); | ||
104 | |||
105 | int 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 | |||
123 | out: | ||
124 | raw_spin_unlock_irqrestore(&timer_data_lock, flags); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | EXPORT_SYMBOL(bcm63xx_timer_register); | ||
129 | |||
130 | void 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 | |||
142 | EXPORT_SYMBOL(bcm63xx_timer_unregister); | ||
143 | |||
144 | unsigned int bcm63xx_timer_countdown(unsigned int countdown_us) | ||
145 | { | ||
146 | return (clk_get_rate(periph_clk) / (1000 * 1000)) * countdown_us; | ||
147 | } | ||
148 | |||
149 | EXPORT_SYMBOL(bcm63xx_timer_countdown); | ||
150 | |||
151 | int 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 | |||
179 | EXPORT_SYMBOL(bcm63xx_timer_set); | ||
180 | |||
181 | int 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 | |||
206 | arch_initcall(bcm63xx_timer_init); | ||