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