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