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