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