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