1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7  * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
8  */
9 
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/platform_device.h>
14 #include <linux/ssb/ssb.h>
15 #include <asm/addrspace.h>
16 #include <bcm63xx_board.h>
17 #include <bcm63xx_cpu.h>
18 #include <bcm63xx_dev_uart.h>
19 #include <bcm63xx_regs.h>
20 #include <bcm63xx_io.h>
21 #include <bcm63xx_nvram.h>
22 #include <bcm63xx_dev_pci.h>
23 #include <bcm63xx_dev_enet.h>
24 #include <bcm63xx_dev_dsp.h>
25 #include <bcm63xx_dev_flash.h>
26 #include <bcm63xx_dev_pcmcia.h>
27 #include <bcm63xx_dev_spi.h>
28 #include <bcm63xx_dev_usb_usbd.h>
29 #include <board_bcm963xx.h>
30 
31 #include <uapi/linux/bcm933xx_hcs.h>
32 
33 #define PFX	"board_bcm963xx: "
34 
35 #define HCS_OFFSET_128K			0x20000
36 
37 static struct board_info board;
38 
39 /*
40  * known 3368 boards
41  */
42 #ifdef CONFIG_BCM63XX_CPU_3368
43 static struct board_info __initdata board_cvg834g = {
44 	.name				= "CVG834G_E15R3921",
45 	.expected_cpu_id		= 0x3368,
46 
47 	.has_uart0			= 1,
48 	.has_uart1			= 1,
49 
50 	.has_enet0			= 1,
51 	.has_pci			= 1,
52 
53 	.enet0 = {
54 		.has_phy		= 1,
55 		.use_internal_phy	= 1,
56 	},
57 
58 	.leds = {
59 		{
60 			.name		= "CVG834G:green:power",
61 			.gpio		= 37,
62 			.default_trigger= "default-on",
63 		},
64 	},
65 
66 	.ephy_reset_gpio		= 36,
67 	.ephy_reset_gpio_flags		= GPIOF_INIT_HIGH,
68 };
69 #endif
70 
71 /*
72  * known 6328 boards
73  */
74 #ifdef CONFIG_BCM63XX_CPU_6328
75 static struct board_info __initdata board_96328avng = {
76 	.name				= "96328avng",
77 	.expected_cpu_id		= 0x6328,
78 
79 	.has_uart0			= 1,
80 	.has_pci			= 1,
81 	.has_usbd			= 0,
82 
83 	.usbd = {
84 		.use_fullspeed		= 0,
85 		.port_no		= 0,
86 	},
87 
88 	.leds = {
89 		{
90 			.name		= "96328avng::ppp-fail",
91 			.gpio		= 2,
92 			.active_low	= 1,
93 		},
94 		{
95 			.name		= "96328avng::power",
96 			.gpio		= 4,
97 			.active_low	= 1,
98 			.default_trigger = "default-on",
99 		},
100 		{
101 			.name		= "96328avng::power-fail",
102 			.gpio		= 8,
103 			.active_low	= 1,
104 		},
105 		{
106 			.name		= "96328avng::wps",
107 			.gpio		= 9,
108 			.active_low	= 1,
109 		},
110 		{
111 			.name		= "96328avng::ppp",
112 			.gpio		= 11,
113 			.active_low	= 1,
114 		},
115 	},
116 };
117 #endif
118 
119 /*
120  * known 6338 boards
121  */
122 #ifdef CONFIG_BCM63XX_CPU_6338
123 static struct board_info __initdata board_96338gw = {
124 	.name				= "96338GW",
125 	.expected_cpu_id		= 0x6338,
126 
127 	.has_uart0			= 1,
128 	.has_enet0			= 1,
129 	.enet0 = {
130 		.force_speed_100	= 1,
131 		.force_duplex_full	= 1,
132 	},
133 
134 	.has_ohci0			= 1,
135 
136 	.leds = {
137 		{
138 			.name		= "adsl",
139 			.gpio		= 3,
140 			.active_low	= 1,
141 		},
142 		{
143 			.name		= "ses",
144 			.gpio		= 5,
145 			.active_low	= 1,
146 		},
147 		{
148 			.name		= "ppp-fail",
149 			.gpio		= 4,
150 			.active_low	= 1,
151 		},
152 		{
153 			.name		= "power",
154 			.gpio		= 0,
155 			.active_low	= 1,
156 			.default_trigger = "default-on",
157 		},
158 		{
159 			.name		= "stop",
160 			.gpio		= 1,
161 			.active_low	= 1,
162 		}
163 	},
164 };
165 
166 static struct board_info __initdata board_96338w = {
167 	.name				= "96338W",
168 	.expected_cpu_id		= 0x6338,
169 
170 	.has_uart0			= 1,
171 	.has_enet0			= 1,
172 	.enet0 = {
173 		.force_speed_100	= 1,
174 		.force_duplex_full	= 1,
175 	},
176 
177 	.leds = {
178 		{
179 			.name		= "adsl",
180 			.gpio		= 3,
181 			.active_low	= 1,
182 		},
183 		{
184 			.name		= "ses",
185 			.gpio		= 5,
186 			.active_low	= 1,
187 		},
188 		{
189 			.name		= "ppp-fail",
190 			.gpio		= 4,
191 			.active_low	= 1,
192 		},
193 		{
194 			.name		= "power",
195 			.gpio		= 0,
196 			.active_low	= 1,
197 			.default_trigger = "default-on",
198 		},
199 		{
200 			.name		= "stop",
201 			.gpio		= 1,
202 			.active_low	= 1,
203 		},
204 	},
205 };
206 #endif
207 
208 /*
209  * known 6345 boards
210  */
211 #ifdef CONFIG_BCM63XX_CPU_6345
212 static struct board_info __initdata board_96345gw2 = {
213 	.name				= "96345GW2",
214 	.expected_cpu_id		= 0x6345,
215 
216 	.has_uart0			= 1,
217 };
218 #endif
219 
220 /*
221  * known 6348 boards
222  */
223 #ifdef CONFIG_BCM63XX_CPU_6348
224 static struct board_info __initdata board_96348r = {
225 	.name				= "96348R",
226 	.expected_cpu_id		= 0x6348,
227 
228 	.has_uart0			= 1,
229 	.has_enet0			= 1,
230 	.has_pci			= 1,
231 
232 	.enet0 = {
233 		.has_phy		= 1,
234 		.use_internal_phy	= 1,
235 	},
236 
237 	.leds = {
238 		{
239 			.name		= "adsl-fail",
240 			.gpio		= 2,
241 			.active_low	= 1,
242 		},
243 		{
244 			.name		= "ppp",
245 			.gpio		= 3,
246 			.active_low	= 1,
247 		},
248 		{
249 			.name		= "ppp-fail",
250 			.gpio		= 4,
251 			.active_low	= 1,
252 		},
253 		{
254 			.name		= "power",
255 			.gpio		= 0,
256 			.active_low	= 1,
257 			.default_trigger = "default-on",
258 
259 		},
260 		{
261 			.name		= "stop",
262 			.gpio		= 1,
263 			.active_low	= 1,
264 		},
265 	},
266 };
267 
268 static struct board_info __initdata board_96348gw_10 = {
269 	.name				= "96348GW-10",
270 	.expected_cpu_id		= 0x6348,
271 
272 	.has_uart0			= 1,
273 	.has_enet0			= 1,
274 	.has_enet1			= 1,
275 	.has_pci			= 1,
276 
277 	.enet0 = {
278 		.has_phy		= 1,
279 		.use_internal_phy	= 1,
280 	},
281 	.enet1 = {
282 		.force_speed_100	= 1,
283 		.force_duplex_full	= 1,
284 	},
285 
286 	.has_ohci0			= 1,
287 	.has_pccard			= 1,
288 	.has_ehci0			= 1,
289 
290 	.has_dsp			= 1,
291 	.dsp = {
292 		.gpio_rst		= 6,
293 		.gpio_int		= 34,
294 		.cs			= 2,
295 		.ext_irq		= 2,
296 	},
297 
298 	.leds = {
299 		{
300 			.name		= "adsl-fail",
301 			.gpio		= 2,
302 			.active_low	= 1,
303 		},
304 		{
305 			.name		= "ppp",
306 			.gpio		= 3,
307 			.active_low	= 1,
308 		},
309 		{
310 			.name		= "ppp-fail",
311 			.gpio		= 4,
312 			.active_low	= 1,
313 		},
314 		{
315 			.name		= "power",
316 			.gpio		= 0,
317 			.active_low	= 1,
318 			.default_trigger = "default-on",
319 		},
320 		{
321 			.name		= "stop",
322 			.gpio		= 1,
323 			.active_low	= 1,
324 		},
325 	},
326 };
327 
328 static struct board_info __initdata board_96348gw_11 = {
329 	.name				= "96348GW-11",
330 	.expected_cpu_id		= 0x6348,
331 
332 	.has_uart0			= 1,
333 	.has_enet0			= 1,
334 	.has_enet1			= 1,
335 	.has_pci			= 1,
336 
337 	.enet0 = {
338 		.has_phy		= 1,
339 		.use_internal_phy	= 1,
340 	},
341 
342 	.enet1 = {
343 		.force_speed_100	= 1,
344 		.force_duplex_full	= 1,
345 	},
346 
347 
348 	.has_ohci0 = 1,
349 	.has_pccard = 1,
350 	.has_ehci0 = 1,
351 
352 	.leds = {
353 		{
354 			.name		= "adsl-fail",
355 			.gpio		= 2,
356 			.active_low	= 1,
357 		},
358 		{
359 			.name		= "ppp",
360 			.gpio		= 3,
361 			.active_low	= 1,
362 		},
363 		{
364 			.name		= "ppp-fail",
365 			.gpio		= 4,
366 			.active_low	= 1,
367 		},
368 		{
369 			.name		= "power",
370 			.gpio		= 0,
371 			.active_low	= 1,
372 			.default_trigger = "default-on",
373 		},
374 		{
375 			.name		= "stop",
376 			.gpio		= 1,
377 			.active_low	= 1,
378 		},
379 	},
380 };
381 
382 static struct board_info __initdata board_96348gw = {
383 	.name				= "96348GW",
384 	.expected_cpu_id		= 0x6348,
385 
386 	.has_uart0			= 1,
387 	.has_enet0			= 1,
388 	.has_enet1			= 1,
389 	.has_pci			= 1,
390 
391 	.enet0 = {
392 		.has_phy		= 1,
393 		.use_internal_phy	= 1,
394 	},
395 	.enet1 = {
396 		.force_speed_100	= 1,
397 		.force_duplex_full	= 1,
398 	},
399 
400 	.has_ohci0 = 1,
401 
402 	.has_dsp			= 1,
403 	.dsp = {
404 		.gpio_rst		= 6,
405 		.gpio_int		= 34,
406 		.ext_irq		= 2,
407 		.cs			= 2,
408 	},
409 
410 	.leds = {
411 		{
412 			.name		= "adsl-fail",
413 			.gpio		= 2,
414 			.active_low	= 1,
415 		},
416 		{
417 			.name		= "ppp",
418 			.gpio		= 3,
419 			.active_low	= 1,
420 		},
421 		{
422 			.name		= "ppp-fail",
423 			.gpio		= 4,
424 			.active_low	= 1,
425 		},
426 		{
427 			.name		= "power",
428 			.gpio		= 0,
429 			.active_low	= 1,
430 			.default_trigger = "default-on",
431 		},
432 		{
433 			.name		= "stop",
434 			.gpio		= 1,
435 			.active_low	= 1,
436 		},
437 	},
438 };
439 
440 static struct board_info __initdata board_FAST2404 = {
441 	.name				= "F@ST2404",
442 	.expected_cpu_id		= 0x6348,
443 
444 	.has_uart0			= 1,
445 	.has_enet0			= 1,
446 	.has_enet1			= 1,
447 	.has_pci			= 1,
448 
449 	.enet0 = {
450 		.has_phy		= 1,
451 		.use_internal_phy	= 1,
452 	},
453 
454 	.enet1 = {
455 		.force_speed_100	= 1,
456 		.force_duplex_full	= 1,
457 	},
458 
459 	.has_ohci0			= 1,
460 	.has_pccard			= 1,
461 	.has_ehci0			= 1,
462 };
463 
464 static struct board_info __initdata board_rta1025w_16 = {
465 	.name				= "RTA1025W_16",
466 	.expected_cpu_id		= 0x6348,
467 
468 	.has_enet0			= 1,
469 	.has_enet1			= 1,
470 	.has_pci			= 1,
471 
472 	.enet0 = {
473 		.has_phy		= 1,
474 		.use_internal_phy	= 1,
475 	},
476 	.enet1 = {
477 		.force_speed_100	= 1,
478 		.force_duplex_full	= 1,
479 	},
480 };
481 
482 
483 static struct board_info __initdata board_DV201AMR = {
484 	.name				= "DV201AMR",
485 	.expected_cpu_id		= 0x6348,
486 
487 	.has_uart0			= 1,
488 	.has_pci			= 1,
489 	.has_ohci0			= 1,
490 
491 	.has_enet0			= 1,
492 	.has_enet1			= 1,
493 	.enet0 = {
494 		.has_phy		= 1,
495 		.use_internal_phy	= 1,
496 	},
497 	.enet1 = {
498 		.force_speed_100	= 1,
499 		.force_duplex_full	= 1,
500 	},
501 };
502 
503 static struct board_info __initdata board_96348gw_a = {
504 	.name				= "96348GW-A",
505 	.expected_cpu_id		= 0x6348,
506 
507 	.has_uart0			= 1,
508 	.has_enet0			= 1,
509 	.has_enet1			= 1,
510 	.has_pci			= 1,
511 
512 	.enet0 = {
513 		.has_phy		= 1,
514 		.use_internal_phy	= 1,
515 	},
516 	.enet1 = {
517 		.force_speed_100	= 1,
518 		.force_duplex_full	= 1,
519 	},
520 
521 	.has_ohci0 = 1,
522 };
523 #endif
524 
525 /*
526  * known 6358 boards
527  */
528 #ifdef CONFIG_BCM63XX_CPU_6358
529 static struct board_info __initdata board_96358vw = {
530 	.name				= "96358VW",
531 	.expected_cpu_id		= 0x6358,
532 
533 	.has_uart0			= 1,
534 	.has_enet0			= 1,
535 	.has_enet1			= 1,
536 	.has_pci			= 1,
537 
538 	.enet0 = {
539 		.has_phy		= 1,
540 		.use_internal_phy	= 1,
541 	},
542 
543 	.enet1 = {
544 		.force_speed_100	= 1,
545 		.force_duplex_full	= 1,
546 	},
547 
548 
549 	.has_ohci0 = 1,
550 	.has_pccard = 1,
551 	.has_ehci0 = 1,
552 
553 	.leds = {
554 		{
555 			.name		= "adsl-fail",
556 			.gpio		= 15,
557 			.active_low	= 1,
558 		},
559 		{
560 			.name		= "ppp",
561 			.gpio		= 22,
562 			.active_low	= 1,
563 		},
564 		{
565 			.name		= "ppp-fail",
566 			.gpio		= 23,
567 			.active_low	= 1,
568 		},
569 		{
570 			.name		= "power",
571 			.gpio		= 4,
572 			.default_trigger = "default-on",
573 		},
574 		{
575 			.name		= "stop",
576 			.gpio		= 5,
577 		},
578 	},
579 };
580 
581 static struct board_info __initdata board_96358vw2 = {
582 	.name				= "96358VW2",
583 	.expected_cpu_id		= 0x6358,
584 
585 	.has_uart0			= 1,
586 	.has_enet0			= 1,
587 	.has_enet1			= 1,
588 	.has_pci			= 1,
589 
590 	.enet0 = {
591 		.has_phy		= 1,
592 		.use_internal_phy	= 1,
593 	},
594 
595 	.enet1 = {
596 		.force_speed_100	= 1,
597 		.force_duplex_full	= 1,
598 	},
599 
600 
601 	.has_ohci0 = 1,
602 	.has_pccard = 1,
603 	.has_ehci0 = 1,
604 
605 	.leds = {
606 		{
607 			.name		= "adsl",
608 			.gpio		= 22,
609 			.active_low	= 1,
610 		},
611 		{
612 			.name		= "ppp-fail",
613 			.gpio		= 23,
614 		},
615 		{
616 			.name		= "power",
617 			.gpio		= 5,
618 			.active_low	= 1,
619 			.default_trigger = "default-on",
620 		},
621 		{
622 			.name		= "stop",
623 			.gpio		= 4,
624 			.active_low	= 1,
625 		},
626 	},
627 };
628 
629 static struct board_info __initdata board_AGPFS0 = {
630 	.name				= "AGPF-S0",
631 	.expected_cpu_id		= 0x6358,
632 
633 	.has_uart0			= 1,
634 	.has_enet0			= 1,
635 	.has_enet1			= 1,
636 	.has_pci			= 1,
637 
638 	.enet0 = {
639 		.has_phy		= 1,
640 		.use_internal_phy	= 1,
641 	},
642 
643 	.enet1 = {
644 		.force_speed_100	= 1,
645 		.force_duplex_full	= 1,
646 	},
647 
648 	.has_ohci0 = 1,
649 	.has_ehci0 = 1,
650 };
651 
652 static struct board_info __initdata board_DWVS0 = {
653 	.name				= "DWV-S0",
654 	.expected_cpu_id		= 0x6358,
655 
656 	.has_enet0			= 1,
657 	.has_enet1			= 1,
658 	.has_pci			= 1,
659 
660 	.enet0 = {
661 		.has_phy		= 1,
662 		.use_internal_phy	= 1,
663 	},
664 
665 	.enet1 = {
666 		.force_speed_100	= 1,
667 		.force_duplex_full	= 1,
668 	},
669 
670 	.has_ohci0			= 1,
671 };
672 #endif
673 
674 /*
675  * all boards
676  */
677 static const struct board_info __initconst *bcm963xx_boards[] = {
678 #ifdef CONFIG_BCM63XX_CPU_3368
679 	&board_cvg834g,
680 #endif
681 #ifdef CONFIG_BCM63XX_CPU_6328
682 	&board_96328avng,
683 #endif
684 #ifdef CONFIG_BCM63XX_CPU_6338
685 	&board_96338gw,
686 	&board_96338w,
687 #endif
688 #ifdef CONFIG_BCM63XX_CPU_6345
689 	&board_96345gw2,
690 #endif
691 #ifdef CONFIG_BCM63XX_CPU_6348
692 	&board_96348r,
693 	&board_96348gw,
694 	&board_96348gw_10,
695 	&board_96348gw_11,
696 	&board_FAST2404,
697 	&board_DV201AMR,
698 	&board_96348gw_a,
699 	&board_rta1025w_16,
700 #endif
701 
702 #ifdef CONFIG_BCM63XX_CPU_6358
703 	&board_96358vw,
704 	&board_96358vw2,
705 	&board_AGPFS0,
706 	&board_DWVS0,
707 #endif
708 };
709 
710 /*
711  * Register a sane SPROMv2 to make the on-board
712  * bcm4318 WLAN work
713  */
714 #ifdef CONFIG_SSB_PCIHOST
715 static struct ssb_sprom bcm63xx_sprom = {
716 	.revision		= 0x02,
717 	.board_rev		= 0x17,
718 	.country_code		= 0x0,
719 	.ant_available_bg	= 0x3,
720 	.pa0b0			= 0x15ae,
721 	.pa0b1			= 0xfa85,
722 	.pa0b2			= 0xfe8d,
723 	.pa1b0			= 0xffff,
724 	.pa1b1			= 0xffff,
725 	.pa1b2			= 0xffff,
726 	.gpio0			= 0xff,
727 	.gpio1			= 0xff,
728 	.gpio2			= 0xff,
729 	.gpio3			= 0xff,
730 	.maxpwr_bg		= 0x004c,
731 	.itssi_bg		= 0x00,
732 	.boardflags_lo		= 0x2848,
733 	.boardflags_hi		= 0x0000,
734 };
735 
736 int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
737 {
738 	if (bus->bustype == SSB_BUSTYPE_PCI) {
739 		memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
740 		return 0;
741 	} else {
742 		printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
743 		return -EINVAL;
744 	}
745 }
746 #endif
747 
748 /*
749  * return board name for /proc/cpuinfo
750  */
751 const char *board_get_name(void)
752 {
753 	return board.name;
754 }
755 
756 /*
757  * early init callback, read nvram data from flash and checksum it
758  */
759 void __init board_prom_init(void)
760 {
761 	unsigned int i;
762 	u8 *boot_addr, *cfe;
763 	char cfe_version[32];
764 	char *board_name = NULL;
765 	u32 val;
766 	struct bcm_hcs *hcs;
767 
768 	/* read base address of boot chip select (0)
769 	 * 6328/6362 do not have MPI but boot from a fixed address
770 	 */
771 	if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
772 		val = 0x18000000;
773 	} else {
774 		val = bcm_mpi_readl(MPI_CSBASE_REG(0));
775 		val &= MPI_CSBASE_BASE_MASK;
776 	}
777 	boot_addr = (u8 *)KSEG1ADDR(val);
778 
779 	/* dump cfe version */
780 	cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET;
781 	if (!memcmp(cfe, "cfe-v", 5))
782 		snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u",
783 			 cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]);
784 	else
785 		strcpy(cfe_version, "unknown");
786 	printk(KERN_INFO PFX "CFE version: %s\n", cfe_version);
787 
788 	bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET);
789 
790 	if (BCMCPU_IS_3368()) {
791 		hcs = (struct bcm_hcs *)boot_addr;
792 		board_name = hcs->filename;
793 	} else {
794 		board_name = bcm63xx_nvram_get_name();
795 	}
796 	/* find board by name */
797 	for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) {
798 		if (strncmp(board_name, bcm963xx_boards[i]->name, 16))
799 			continue;
800 		/* copy, board desc array is marked initdata */
801 		memcpy(&board, bcm963xx_boards[i], sizeof(board));
802 		break;
803 	}
804 
805 	/* bail out if board is not found, will complain later */
806 	if (!board.name[0]) {
807 		char name[17];
808 		memcpy(name, board_name, 16);
809 		name[16] = 0;
810 		printk(KERN_ERR PFX "unknown bcm963xx board: %s\n",
811 		       name);
812 		return;
813 	}
814 
815 	/* setup pin multiplexing depending on board enabled device,
816 	 * this has to be done this early since PCI init is done
817 	 * inside arch_initcall */
818 	val = 0;
819 
820 #ifdef CONFIG_PCI
821 	if (board.has_pci) {
822 		bcm63xx_pci_enabled = 1;
823 		if (BCMCPU_IS_6348())
824 			val |= GPIO_MODE_6348_G2_PCI;
825 	}
826 #endif
827 
828 	if (board.has_pccard) {
829 		if (BCMCPU_IS_6348())
830 			val |= GPIO_MODE_6348_G1_MII_PCCARD;
831 	}
832 
833 	if (board.has_enet0 && !board.enet0.use_internal_phy) {
834 		if (BCMCPU_IS_6348())
835 			val |= GPIO_MODE_6348_G3_EXT_MII |
836 				GPIO_MODE_6348_G0_EXT_MII;
837 	}
838 
839 	if (board.has_enet1 && !board.enet1.use_internal_phy) {
840 		if (BCMCPU_IS_6348())
841 			val |= GPIO_MODE_6348_G3_EXT_MII |
842 				GPIO_MODE_6348_G0_EXT_MII;
843 	}
844 
845 	bcm_gpio_writel(val, GPIO_MODE_REG);
846 }
847 
848 /*
849  * second stage init callback, good time to panic if we couldn't
850  * identify on which board we're running since early printk is working
851  */
852 void __init board_setup(void)
853 {
854 	if (!board.name[0])
855 		panic("unable to detect bcm963xx board");
856 	printk(KERN_INFO PFX "board name: %s\n", board.name);
857 
858 	/* make sure we're running on expected cpu */
859 	if (bcm63xx_get_cpu_id() != board.expected_cpu_id)
860 		panic("unexpected CPU for bcm963xx board");
861 }
862 
863 static struct gpio_led_platform_data bcm63xx_led_data;
864 
865 static struct platform_device bcm63xx_gpio_leds = {
866 	.name			= "leds-gpio",
867 	.id			= 0,
868 	.dev.platform_data	= &bcm63xx_led_data,
869 };
870 
871 /*
872  * third stage init callback, register all board devices.
873  */
874 int __init board_register_devices(void)
875 {
876 	if (board.has_uart0)
877 		bcm63xx_uart_register(0);
878 
879 	if (board.has_uart1)
880 		bcm63xx_uart_register(1);
881 
882 	if (board.has_pccard)
883 		bcm63xx_pcmcia_register();
884 
885 	if (board.has_enet0 &&
886 	    !bcm63xx_nvram_get_mac_address(board.enet0.mac_addr))
887 		bcm63xx_enet_register(0, &board.enet0);
888 
889 	if (board.has_enet1 &&
890 	    !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
891 		bcm63xx_enet_register(1, &board.enet1);
892 
893 	if (board.has_enetsw &&
894 	    !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
895 		bcm63xx_enetsw_register(&board.enetsw);
896 
897 	if (board.has_usbd)
898 		bcm63xx_usbd_register(&board.usbd);
899 
900 	if (board.has_dsp)
901 		bcm63xx_dsp_register(&board.dsp);
902 
903 	/* Generate MAC address for WLAN and register our SPROM,
904 	 * do this after registering enet devices
905 	 */
906 #ifdef CONFIG_SSB_PCIHOST
907 	if (!bcm63xx_nvram_get_mac_address(bcm63xx_sprom.il0mac)) {
908 		memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
909 		memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
910 		if (ssb_arch_register_fallback_sprom(
911 				&bcm63xx_get_fallback_sprom) < 0)
912 			pr_err(PFX "failed to register fallback SPROM\n");
913 	}
914 #endif
915 
916 	bcm63xx_spi_register();
917 
918 	bcm63xx_flash_register();
919 
920 	bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
921 	bcm63xx_led_data.leds = board.leds;
922 
923 	platform_device_register(&bcm63xx_gpio_leds);
924 
925 	if (board.ephy_reset_gpio && board.ephy_reset_gpio_flags)
926 		gpio_request_one(board.ephy_reset_gpio,
927 				board.ephy_reset_gpio_flags, "ephy-reset");
928 
929 	return 0;
930 }
931