e3ae72bff28faabf9fae4986e34ae15e1091d8fb
[openwrt.git] / target / linux / brcm63xx / files / 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  */
8
9 #include <linux/init.h>
10 #include <linux/kernel.h>
11 #include <linux/string.h>
12 #include <linux/platform_device.h>
13 #include <linux/mtd/mtd.h>
14 #include <linux/mtd/partitions.h>
15 #include <linux/mtd/physmap.h>
16 #include <linux/ssb/ssb.h>
17 #include <asm/addrspace.h>
18 #include <bcm63xx_board.h>
19 #include <bcm63xx_cpu.h>
20 #include <bcm63xx_regs.h>
21 #include <bcm63xx_io.h>
22 #include <bcm63xx_board.h>
23 #include <bcm63xx_dev_pci.h>
24 #include <bcm63xx_dev_uart.h>
25 #include <bcm63xx_dev_wdt.h>
26 #include <bcm63xx_dev_enet.h>
27 #include <bcm63xx_dev_dsp.h>
28 #include <bcm63xx_dev_pcmcia.h>
29 #include <bcm63xx_dev_usb_ohci.h>
30 #include <bcm63xx_dev_usb_ehci.h>
31 #include <bcm63xx_dev_usb_udc.h>
32 #include <bcm63xx_dev_spi.h>
33 #include <board_bcm963xx.h>
34
35 #define PFX     "board_bcm963xx: "
36
37 static struct bcm963xx_nvram nvram;
38 static unsigned int mac_addr_used = 0;
39 static struct board_info board;
40
41 /*
42  * known 6338 boards
43  */
44
45 #ifdef CONFIG_BCM63XX_CPU_6338
46 static struct board_info __initdata board_96338gw = {
47         .name                           = "96338GW",
48         .expected_cpu_id                = 0x6338,
49         
50         .has_enet0                      = 1,
51         .enet0 = {
52                 .force_speed_100        = 1,
53                 .force_duplex_full      = 1,
54         },
55
56         .has_ohci0                      = 1,
57 };
58
59 static struct board_info __initdata board_96338w = {
60         .name                           = "96338W",
61         .expected_cpu_id                = 0x6338,
62         
63         .has_enet0                      = 1,
64         .enet0 = {
65                 .force_speed_100        = 1,
66                 .force_duplex_full      = 1,
67         }
68 };
69 #endif
70
71 /*
72  * known 6345 boards
73  */
74 #ifdef CONFIG_BCM63XX_CPU_6345
75 static struct board_info __initdata board_96345gw2 = {
76         .name                           = "96345GW2",
77         .expected_cpu_id                = 0x6345,
78 };
79 #endif
80
81 /*
82  * known 6348 boards
83  */
84 #ifdef CONFIG_BCM63XX_CPU_6348
85 static struct board_info __initdata board_96348r = {
86         .name                           = "96348R",
87         .expected_cpu_id                = 0x6348,
88
89         .has_enet0                      = 1,
90         .has_pci                        = 1,
91
92         .enet0 = {
93                 .has_phy                = 1,
94                 .use_internal_phy       = 1,
95         },
96 };
97
98 static struct board_info __initdata board_96348gw_10 = { 
99         .name                           = "96348GW-10",
100         .expected_cpu_id                = 0x6348,
101         
102         .has_enet0                      = 1,
103         .has_enet1                      = 1,
104         .has_pci                        = 1, 
105         
106         .enet0 = {
107                 .has_phy                = 1,
108                 .use_internal_phy       = 1,
109         },
110         .enet1 = {
111                 .force_speed_100        = 1,
112                 .force_duplex_full      = 1,
113         },
114         
115         .has_ohci0                      = 1,
116         .has_pccard                     = 1,
117         .has_ehci0                      = 1,
118
119         .has_dsp                        = 1,
120         .dsp = {
121                 .gpio_rst               = 6,
122                 .gpio_int               = 34,
123                 .cs                     = 2,
124                 .ext_irq                = 2,
125         },
126 }; 
127
128 static struct board_info __initdata board_96348gw_11 = {
129         .name                           = "96348GW-11",
130         .expected_cpu_id                = 0x6348,
131
132         .has_enet0                      = 1,
133         .has_enet1                      = 1,
134         .has_pci                        = 1,
135
136         .enet0 = {
137                 .has_phy                = 1,
138                 .use_internal_phy       = 1,
139         },
140
141         .enet1 = {
142                 .force_speed_100        = 1,
143                 .force_duplex_full      = 1,
144         },
145
146
147         .has_ohci0 = 1,
148         .has_pccard = 1,
149         .has_ehci0 = 1,
150 };
151
152 static struct board_info __initdata board_96348gw = {
153         .name                           = "96348GW",
154         .expected_cpu_id                = 0x6348,
155
156         .has_enet0                      = 1,
157         .has_enet1                      = 1,
158         .has_pci                        = 1,
159
160         .enet0 = {
161                 .has_phy                = 1,
162                 .use_internal_phy       = 1,
163         },
164         .enet1 = {
165                 .force_speed_100        = 1,
166                 .force_duplex_full      = 1,
167         },
168
169         .has_ohci0                      = 1,
170         .has_dsp                        = 1,
171         
172         .dsp = {
173                 .gpio_rst               = 6,
174                 .gpio_int               = 34,
175                 .ext_irq                = 2,
176                 .cs                     = 2,
177         },
178 };
179
180 static struct board_info __initdata board_FAST2404 = {
181         .name                           = "F@ST2404",
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
193         .enet1 = {
194                 .force_speed_100        = 1,
195                 .force_duplex_full      = 1,
196         },
197
198
199         .has_ohci0 = 1,
200         .has_pccard = 1,
201         .has_ehci0 = 1,
202 };
203
204 static struct board_info __initdata board_DV201AMR = {
205         .name                           = "DV201AMR",
206         .expected_cpu_id                = 0x6348,
207
208         .has_pci                        = 1,
209         .has_ohci0                      = 1,
210         .has_udc0                       = 1,
211
212         .has_enet0                      = 1,
213         .has_enet1                      = 1,
214         .enet0 = {
215                 .has_phy                = 1,
216                 .use_internal_phy       = 1,
217         },
218         .enet1 = {
219                 .force_speed_100        = 1,
220                 .force_duplex_full      = 1,
221         },
222 };
223
224 static struct board_info __initdata board_96348gw_a = {
225         .name                           = "96348GW-A",
226         .expected_cpu_id                = 0x6348,
227
228         .has_enet0                      = 1,
229         .has_enet1                      = 1,
230         .has_pci                        = 1,
231
232         .enet0 = {
233                 .has_phy                = 1,
234                 .use_internal_phy       = 1,
235         },
236         .enet1 = {
237                 .force_speed_100        = 1,
238                 .force_duplex_full      = 1,
239         },
240
241         .has_ohci0 = 1,
242 };
243
244
245 #endif
246
247 /*
248  * known 6358 boards
249  */
250 #ifdef CONFIG_BCM63XX_CPU_6358
251 static struct board_info __initdata board_96358vw = {
252         .name                           = "96358VW",
253         .expected_cpu_id                = 0x6358,
254
255         .has_enet0                      = 1,
256         .has_enet1                      = 1,
257         .has_pci                        = 1,
258
259         .enet0 = {
260                 .has_phy                = 1,
261                 .use_internal_phy       = 1,
262         },
263
264         .enet1 = {
265                 .force_speed_100        = 1,
266                 .force_duplex_full      = 1,
267         },
268
269
270         .has_ohci0 = 1,
271         .has_pccard = 1,
272         .has_ehci0 = 1,
273 };
274
275 static struct board_info __initdata board_96358vw2 = {
276         .name                           = "96358VW2",
277         .expected_cpu_id                = 0x6358,
278
279         .has_enet0                      = 1,
280         .has_enet1                      = 1,
281         .has_pci                        = 1,
282
283         .enet0 = {
284                 .has_phy                = 1,
285                 .use_internal_phy       = 1,
286         },
287
288         .enet1 = {
289                 .force_speed_100        = 1,
290                 .force_duplex_full      = 1,
291         },
292
293
294         .has_ohci0 = 1,
295         .has_pccard = 1,
296         .has_ehci0 = 1,
297 };
298
299 static struct board_info __initdata board_AGPFS0 = {
300         .name                           = "AGPF-S0",
301         .expected_cpu_id                = 0x6358,
302
303         .has_enet0                      = 1,
304         .has_enet1                      = 1,
305         .has_pci                        = 1,
306
307         .enet0 = {
308                 .has_phy                = 1,
309                 .use_internal_phy       = 1,
310         },
311
312         .enet1 = {
313                 .force_speed_100        = 1,
314                 .force_duplex_full      = 1,
315         },
316
317         .has_ohci0 = 1,
318         .has_ehci0 = 1,
319 };
320 #endif
321
322 /*
323  * all boards
324  */
325 static const struct board_info __initdata *bcm963xx_boards[] = {
326 #ifdef CONFIG_BCM63XX_CPU_6338
327         &board_96338gw,
328         &board_96338w,
329 #endif
330 #ifdef CONFIG_BCM63XX_CPU_6345
331         &board_96345gw2,
332 #endif
333 #ifdef CONFIG_BCM63XX_CPU_6348
334         &board_96348r,
335         &board_96348gw,
336         &board_96348gw_10,
337         &board_96348gw_11,
338         &board_FAST2404,
339         &board_DV201AMR,
340         &board_96348gw_a,
341 #endif
342
343 #ifdef CONFIG_BCM63XX_CPU_6358
344         &board_96358vw,
345         &board_96358vw2,
346         &board_AGPFS0,
347 #endif
348 };
349
350 /*
351  * early init callback, read nvram data from flash and checksum it
352  */
353 void __init board_prom_init(void)
354 {
355         unsigned int check_len, i;
356         u8 *boot_addr, *cfe, *p;
357         char cfe_version[32];
358         u32 val;
359
360         /* read base address of boot chip select (0) 
361          * 6345 does not have MPI but boots from standard
362          * MIPS Flash address */
363         if (BCMCPU_IS_6345())
364                 val = 0x1fc00000;
365         else {
366                 val = bcm_mpi_readl(MPI_CSBASE_REG(0));
367                 val &= MPI_CSBASE_BASE_MASK;
368         }
369         boot_addr = (u8 *)KSEG1ADDR(val);
370
371         /* dump cfe version */
372         cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET;
373         if (!memcmp(cfe, "cfe-v", 5))
374                 snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u",
375                          cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]);
376         else
377                 strcpy(cfe_version, "unknown");
378         printk(KERN_INFO PFX "CFE version: %s\n", cfe_version);
379
380         /* extract nvram data */
381         memcpy(&nvram, boot_addr + BCM963XX_NVRAM_OFFSET, sizeof(nvram));
382
383         /* check checksum before using data */
384         if (nvram.version <= 4)
385                 check_len = offsetof(struct bcm963xx_nvram, checksum_old);
386         else
387                 check_len = sizeof(nvram);
388         val = 0;
389         p = (u8 *)&nvram;
390         while (check_len--)
391                 val += *p;
392         if (val) {
393                 printk(KERN_ERR PFX "invalid nvram checksum\n");
394                 return;
395         }
396
397         /* find board by name */
398         for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) {
399                 if (strncmp(nvram.name, bcm963xx_boards[i]->name,
400                             sizeof(nvram.name)))
401                         continue;
402                 /* copy, board desc array is marked initdata */
403                 memcpy(&board, bcm963xx_boards[i], sizeof(board));
404                 break;
405         }
406
407         /* bail out if board is not found, will complain later */
408         if (!board.name[0]) {
409                 char name[17];
410                 memcpy(name, nvram.name, 16);
411                 name[16] = 0;
412                 printk(KERN_ERR PFX "unknown bcm963xx board: %s\n",
413                        name);
414                 return;
415         }
416
417         /* setup pin multiplexing depending on board enabled device,
418          * this has to be done this early since PCI init is done
419          * inside arch_initcall */
420         val = 0;
421 #ifdef CONFIG_PCI
422         if (board.has_pci) {
423                 bcm63xx_pci_enabled = 1;
424                 if (BCMCPU_IS_6348())
425                         val |= GPIO_MODE_6348_G2_PCI;
426         }
427 #endif
428         if (board.has_pccard) {
429                 if (BCMCPU_IS_6348())
430                         val |= GPIO_MODE_6348_G1_MII_PCCARD;
431         }
432
433         if (board.has_enet0 && !board.enet0.use_internal_phy) {
434                 if (BCMCPU_IS_6348())
435                         val |= GPIO_MODE_6348_G3_EXT_MII |
436                                 GPIO_MODE_6348_G0_EXT_MII;
437         }
438
439         if (board.has_enet1 && !board.enet1.use_internal_phy) {
440                 if (BCMCPU_IS_6348())
441                         val |= GPIO_MODE_6348_G3_EXT_MII |
442                                 GPIO_MODE_6348_G0_EXT_MII;
443         }
444
445         bcm_gpio_writel(val, GPIO_MODE_REG);
446 }
447
448 /*
449  * second stage init callback, good time to panic if we couldn't
450  * identify on which board we're running since early printk is working
451  */
452 void __init board_setup(void)
453 {
454         if (!board.name[0])
455                 panic("unable to detect bcm963xx board");
456         printk(KERN_INFO PFX "board name: %s\n", board.name);
457
458         /* make sure we're running on expected cpu */
459         if (bcm63xx_get_cpu_id() != board.expected_cpu_id)
460                 panic("unexpected CPU for bcm963xx board");
461 }
462
463 /*
464  * return board name for /proc/cpuinfo
465  */
466 const char *board_get_name(void)
467 {
468         return board.name;
469 }
470
471 /*
472  * register & return a new board mac address
473  */
474 static int board_get_mac_address(u8 *mac)
475 {
476         u8 *p;
477         int count;
478
479         if (mac_addr_used >= nvram.mac_addr_count) {
480                 printk(KERN_ERR PFX "not enough mac address\n");
481                 return -ENODEV;
482         }
483
484         memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
485         p = mac + ETH_ALEN - 1;
486         count = mac_addr_used;
487
488         while (count--) {
489                 do {
490                         (*p)++;
491                         if (*p != 0)
492                                 break;
493                         p--;
494                 } while (p != mac);
495         }
496
497         if (p == mac) {
498                 printk(KERN_ERR PFX "unable to fetch mac address\n");
499                 return -ENODEV;
500         }
501
502         mac_addr_used++;
503         return 0;
504 }
505
506 static struct resource mtd_resources[] = {
507         {
508                 .start          = 0,    /* filled at runtime */
509                 .end            = 0,    /* filled at runtime */
510                 .flags          = IORESOURCE_MEM,
511         }
512 };
513
514 static struct platform_device mtd_dev = {
515         .name                   = "bcm963xx-flash",
516         .resource               = mtd_resources,
517         .num_resources          = ARRAY_SIZE(mtd_resources),
518 };
519
520 /*
521  * Register a sane SPROMv2 to make the on-board
522  * bcm4318 WLAN work
523  */
524 static struct ssb_sprom bcm63xx_sprom = {
525         .revision               = 0x02,
526         .board_rev              = 0x17,
527         .country_code           = 0x0,
528         .ant_available_bg       = 0x3,
529         .pa0b0                  = 0x15ae,
530         .pa0b1                  = 0xfa85,
531         .pa0b2                  = 0xfe8d,
532         .pa1b0                  = 0xffff,
533         .pa1b1                  = 0xffff,
534         .pa1b2                  = 0xffff,
535         .gpio0                  = 0xff,
536         .gpio1                  = 0xff,
537         .gpio2                  = 0xff,
538         .gpio3                  = 0xff,
539         .maxpwr_bg              = 0x004c,
540         .itssi_bg               = 0x00,
541         .boardflags_lo          = 0x2848,
542         .boardflags_hi          = 0x0000,
543 };
544
545 static struct resource gpiodev_resource = {
546         .start                  = 0xFFFFFFFF,
547 };
548
549 /*
550  * third stage init callback, register all board devices.
551  */
552 int __init board_register_devices(void)
553 {
554         u32 val;
555
556         bcm63xx_uart_register();
557         bcm63xx_wdt_register();
558         bcm63xx_spi_register();
559
560         if (board.has_pccard)
561                 bcm63xx_pcmcia_register();
562
563         if (board.has_enet0 &&
564             !board_get_mac_address(board.enet0.mac_addr))
565                 bcm63xx_enet_register(0, &board.enet0);
566
567         if (board.has_enet1 &&
568             !board_get_mac_address(board.enet1.mac_addr))
569                 bcm63xx_enet_register(1, &board.enet1);
570
571         if (board.has_ohci0)
572                 bcm63xx_ohci_register();
573
574         if (board.has_ehci0)
575                 bcm63xx_ehci_register();
576
577         if (board.has_udc0)
578                 bcm63xx_udc_register();
579
580         if (board.has_dsp)
581                 bcm63xx_dsp_register(&board.dsp);
582         
583         /* Generate MAC address for WLAN and
584          * register our SPROM */
585 #ifdef CONFIG_PCI
586         if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
587                 memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
588                 memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
589                 if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0)
590                         printk(KERN_ERR "failed to register fallback SPROM\n");
591         }
592 #endif
593
594         /* read base address of boot chip select (0) */
595         if (BCMCPU_IS_6345())
596                 val = 0x1fc0000;
597         else {
598                 val = bcm_mpi_readl(MPI_CSBASE_REG(0));
599                 val &= MPI_CSBASE_BASE_MASK;
600         }
601         mtd_resources[0].start = val;
602         mtd_resources[0].end = 0x1FFFFFFF;
603
604         platform_device_register(&mtd_dev);
605
606         /* Register GPIODEV */
607         platform_device_register_simple("GPIODEV", 0, &gpiodev_resource, 1);
608
609         return 0;
610 }
611