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