5a327f3a7167e521ed5bb3e3982e927e4290b40e
[linux-2.6.git] / arch / mips / bcm63xx / boards / board_bcm963xx.c
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_dev_pci.h>
24 #include <bcm63xx_dev_enet.h>
25 #include <bcm63xx_dev_dsp.h>
26 #include <bcm63xx_dev_uart.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         bcm63xx_uart_register();
797
798         if (board.has_enet0 &&
799             !board_get_mac_address(board.enet0.mac_addr))
800                 bcm63xx_enet_register(0, &board.enet0);
801
802         if (board.has_enet1 &&
803             !board_get_mac_address(board.enet1.mac_addr))
804                 bcm63xx_enet_register(1, &board.enet1);
805
806         if (board.has_dsp)
807                 bcm63xx_dsp_register(&board.dsp);
808
809         /* Generate MAC address for WLAN and
810          * register our SPROM */
811 #ifdef CONFIG_SSB_PCIHOST
812         if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
813                 memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
814                 memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
815                 if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0)
816                         printk(KERN_ERR "failed to register fallback SPROM\n");
817         }
818 #endif
819
820         /* read base address of boot chip select (0) */
821         if (BCMCPU_IS_6345())
822                 val = 0x1fc00000;
823         else {
824                 val = bcm_mpi_readl(MPI_CSBASE_REG(0));
825                 val &= MPI_CSBASE_BASE_MASK;
826         }
827         mtd_resources[0].start = val;
828         mtd_resources[0].end = 0x1FFFFFFF;
829
830         platform_device_register(&mtd_dev);
831
832         bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
833         bcm63xx_led_data.leds = board.leds;
834
835         platform_device_register(&bcm63xx_gpio_leds);
836
837         return 0;
838 }
839