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