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