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 * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> 8 */ 9 10 #include <linux/init.h> 11 #include <linux/kernel.h> 12 #include <linux/string.h> 13 #include <linux/platform_device.h> 14 #include <linux/mtd/mtd.h> 15 #include <linux/mtd/partitions.h> 16 #include <linux/mtd/physmap.h> 17 #include <linux/ssb/ssb.h> 18 #include <asm/addrspace.h> 19 #include <bcm63xx_board.h> 20 #include <bcm63xx_cpu.h> 21 #include <bcm63xx_regs.h> 22 #include <bcm63xx_io.h> 23 #include <bcm63xx_dev_pci.h> 24 #include <bcm63xx_dev_enet.h> 25 #include <bcm63xx_dev_dsp.h> 26 #include <bcm63xx_dev_pcmcia.h> 27 #include <bcm63xx_dev_uart.h> 28 #include <board_bcm963xx.h> 29 30 #define PFX "board_bcm963xx: " 31 32 static struct bcm963xx_nvram nvram; 33 static unsigned int mac_addr_used; 34 static struct board_info board; 35 36 /* 37 * known 6338 boards 38 */ 39 #ifdef CONFIG_BCM63XX_CPU_6338 40 static struct board_info __initdata board_96338gw = { 41 .name = "96338GW", 42 .expected_cpu_id = 0x6338, 43 44 .has_enet0 = 1, 45 .enet0 = { 46 .force_speed_100 = 1, 47 .force_duplex_full = 1, 48 }, 49 50 .has_ohci0 = 1, 51 52 .leds = { 53 { 54 .name = "adsl", 55 .gpio = 3, 56 .active_low = 1, 57 }, 58 { 59 .name = "ses", 60 .gpio = 5, 61 .active_low = 1, 62 }, 63 { 64 .name = "ppp-fail", 65 .gpio = 4, 66 .active_low = 1, 67 }, 68 { 69 .name = "power", 70 .gpio = 0, 71 .active_low = 1, 72 .default_trigger = "default-on", 73 }, 74 { 75 .name = "stop", 76 .gpio = 1, 77 .active_low = 1, 78 } 79 }, 80 }; 81 82 static struct board_info __initdata board_96338w = { 83 .name = "96338W", 84 .expected_cpu_id = 0x6338, 85 86 .has_enet0 = 1, 87 .enet0 = { 88 .force_speed_100 = 1, 89 .force_duplex_full = 1, 90 }, 91 92 .leds = { 93 { 94 .name = "adsl", 95 .gpio = 3, 96 .active_low = 1, 97 }, 98 { 99 .name = "ses", 100 .gpio = 5, 101 .active_low = 1, 102 }, 103 { 104 .name = "ppp-fail", 105 .gpio = 4, 106 .active_low = 1, 107 }, 108 { 109 .name = "power", 110 .gpio = 0, 111 .active_low = 1, 112 .default_trigger = "default-on", 113 }, 114 { 115 .name = "stop", 116 .gpio = 1, 117 .active_low = 1, 118 }, 119 }, 120 }; 121 #endif 122 123 /* 124 * known 6345 boards 125 */ 126 #ifdef CONFIG_BCM63XX_CPU_6345 127 static struct board_info __initdata board_96345gw2 = { 128 .name = "96345GW2", 129 .expected_cpu_id = 0x6345, 130 }; 131 #endif 132 133 /* 134 * known 6348 boards 135 */ 136 #ifdef CONFIG_BCM63XX_CPU_6348 137 static struct board_info __initdata board_96348r = { 138 .name = "96348R", 139 .expected_cpu_id = 0x6348, 140 141 .has_enet0 = 1, 142 .has_pci = 1, 143 144 .enet0 = { 145 .has_phy = 1, 146 .use_internal_phy = 1, 147 }, 148 149 .leds = { 150 { 151 .name = "adsl-fail", 152 .gpio = 2, 153 .active_low = 1, 154 }, 155 { 156 .name = "ppp", 157 .gpio = 3, 158 .active_low = 1, 159 }, 160 { 161 .name = "ppp-fail", 162 .gpio = 4, 163 .active_low = 1, 164 }, 165 { 166 .name = "power", 167 .gpio = 0, 168 .active_low = 1, 169 .default_trigger = "default-on", 170 171 }, 172 { 173 .name = "stop", 174 .gpio = 1, 175 .active_low = 1, 176 }, 177 }, 178 }; 179 180 static struct board_info __initdata board_96348gw_10 = { 181 .name = "96348GW-10", 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 .enet1 = { 193 .force_speed_100 = 1, 194 .force_duplex_full = 1, 195 }, 196 197 .has_ohci0 = 1, 198 .has_pccard = 1, 199 .has_ehci0 = 1, 200 201 .has_dsp = 1, 202 .dsp = { 203 .gpio_rst = 6, 204 .gpio_int = 34, 205 .cs = 2, 206 .ext_irq = 2, 207 }, 208 209 .leds = { 210 { 211 .name = "adsl-fail", 212 .gpio = 2, 213 .active_low = 1, 214 }, 215 { 216 .name = "ppp", 217 .gpio = 3, 218 .active_low = 1, 219 }, 220 { 221 .name = "ppp-fail", 222 .gpio = 4, 223 .active_low = 1, 224 }, 225 { 226 .name = "power", 227 .gpio = 0, 228 .active_low = 1, 229 .default_trigger = "default-on", 230 }, 231 { 232 .name = "stop", 233 .gpio = 1, 234 .active_low = 1, 235 }, 236 }, 237 }; 238 239 static struct board_info __initdata board_96348gw_11 = { 240 .name = "96348GW-11", 241 .expected_cpu_id = 0x6348, 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 .leds = { 263 { 264 .name = "adsl-fail", 265 .gpio = 2, 266 .active_low = 1, 267 }, 268 { 269 .name = "ppp", 270 .gpio = 3, 271 .active_low = 1, 272 }, 273 { 274 .name = "ppp-fail", 275 .gpio = 4, 276 .active_low = 1, 277 }, 278 { 279 .name = "power", 280 .gpio = 0, 281 .active_low = 1, 282 .default_trigger = "default-on", 283 }, 284 { 285 .name = "stop", 286 .gpio = 1, 287 .active_low = 1, 288 }, 289 }, 290 }; 291 292 static struct board_info __initdata board_96348gw = { 293 .name = "96348GW", 294 .expected_cpu_id = 0x6348, 295 296 .has_enet0 = 1, 297 .has_enet1 = 1, 298 .has_pci = 1, 299 300 .enet0 = { 301 .has_phy = 1, 302 .use_internal_phy = 1, 303 }, 304 .enet1 = { 305 .force_speed_100 = 1, 306 .force_duplex_full = 1, 307 }, 308 309 .has_ohci0 = 1, 310 311 .has_dsp = 1, 312 .dsp = { 313 .gpio_rst = 6, 314 .gpio_int = 34, 315 .ext_irq = 2, 316 .cs = 2, 317 }, 318 319 .leds = { 320 { 321 .name = "adsl-fail", 322 .gpio = 2, 323 .active_low = 1, 324 }, 325 { 326 .name = "ppp", 327 .gpio = 3, 328 .active_low = 1, 329 }, 330 { 331 .name = "ppp-fail", 332 .gpio = 4, 333 .active_low = 1, 334 }, 335 { 336 .name = "power", 337 .gpio = 0, 338 .active_low = 1, 339 .default_trigger = "default-on", 340 }, 341 { 342 .name = "stop", 343 .gpio = 1, 344 .active_low = 1, 345 }, 346 }, 347 }; 348 349 static struct board_info __initdata board_FAST2404 = { 350 .name = "F@ST2404", 351 .expected_cpu_id = 0x6348, 352 353 .has_enet0 = 1, 354 .has_enet1 = 1, 355 .has_pci = 1, 356 357 .enet0 = { 358 .has_phy = 1, 359 .use_internal_phy = 1, 360 }, 361 362 .enet1 = { 363 .force_speed_100 = 1, 364 .force_duplex_full = 1, 365 }, 366 367 368 .has_ohci0 = 1, 369 .has_pccard = 1, 370 .has_ehci0 = 1, 371 }; 372 373 static struct board_info __initdata board_DV201AMR = { 374 .name = "DV201AMR", 375 .expected_cpu_id = 0x6348, 376 377 .has_pci = 1, 378 .has_ohci0 = 1, 379 380 .has_enet0 = 1, 381 .has_enet1 = 1, 382 .enet0 = { 383 .has_phy = 1, 384 .use_internal_phy = 1, 385 }, 386 .enet1 = { 387 .force_speed_100 = 1, 388 .force_duplex_full = 1, 389 }, 390 }; 391 392 static struct board_info __initdata board_96348gw_a = { 393 .name = "96348GW-A", 394 .expected_cpu_id = 0x6348, 395 396 .has_enet0 = 1, 397 .has_enet1 = 1, 398 .has_pci = 1, 399 400 .enet0 = { 401 .has_phy = 1, 402 .use_internal_phy = 1, 403 }, 404 .enet1 = { 405 .force_speed_100 = 1, 406 .force_duplex_full = 1, 407 }, 408 409 .has_ohci0 = 1, 410 }; 411 #endif 412 413 /* 414 * known 6358 boards 415 */ 416 #ifdef CONFIG_BCM63XX_CPU_6358 417 static struct board_info __initdata board_96358vw = { 418 .name = "96358VW", 419 .expected_cpu_id = 0x6358, 420 421 .has_enet0 = 1, 422 .has_enet1 = 1, 423 .has_pci = 1, 424 425 .enet0 = { 426 .has_phy = 1, 427 .use_internal_phy = 1, 428 }, 429 430 .enet1 = { 431 .force_speed_100 = 1, 432 .force_duplex_full = 1, 433 }, 434 435 436 .has_ohci0 = 1, 437 .has_pccard = 1, 438 .has_ehci0 = 1, 439 440 .leds = { 441 { 442 .name = "adsl-fail", 443 .gpio = 15, 444 .active_low = 1, 445 }, 446 { 447 .name = "ppp", 448 .gpio = 22, 449 .active_low = 1, 450 }, 451 { 452 .name = "ppp-fail", 453 .gpio = 23, 454 .active_low = 1, 455 }, 456 { 457 .name = "power", 458 .gpio = 4, 459 .default_trigger = "default-on", 460 }, 461 { 462 .name = "stop", 463 .gpio = 5, 464 }, 465 }, 466 }; 467 468 static struct board_info __initdata board_96358vw2 = { 469 .name = "96358VW2", 470 .expected_cpu_id = 0x6358, 471 472 .has_enet0 = 1, 473 .has_enet1 = 1, 474 .has_pci = 1, 475 476 .enet0 = { 477 .has_phy = 1, 478 .use_internal_phy = 1, 479 }, 480 481 .enet1 = { 482 .force_speed_100 = 1, 483 .force_duplex_full = 1, 484 }, 485 486 487 .has_ohci0 = 1, 488 .has_pccard = 1, 489 .has_ehci0 = 1, 490 491 .leds = { 492 { 493 .name = "adsl", 494 .gpio = 22, 495 .active_low = 1, 496 }, 497 { 498 .name = "ppp-fail", 499 .gpio = 23, 500 }, 501 { 502 .name = "power", 503 .gpio = 5, 504 .active_low = 1, 505 .default_trigger = "default-on", 506 }, 507 { 508 .name = "stop", 509 .gpio = 4, 510 .active_low = 1, 511 }, 512 }, 513 }; 514 515 static struct board_info __initdata board_AGPFS0 = { 516 .name = "AGPF-S0", 517 .expected_cpu_id = 0x6358, 518 519 .has_enet0 = 1, 520 .has_enet1 = 1, 521 .has_pci = 1, 522 523 .enet0 = { 524 .has_phy = 1, 525 .use_internal_phy = 1, 526 }, 527 528 .enet1 = { 529 .force_speed_100 = 1, 530 .force_duplex_full = 1, 531 }, 532 533 .has_ohci0 = 1, 534 .has_ehci0 = 1, 535 }; 536 #endif 537 538 /* 539 * all boards 540 */ 541 static const struct board_info __initdata *bcm963xx_boards[] = { 542 #ifdef CONFIG_BCM63XX_CPU_6338 543 &board_96338gw, 544 &board_96338w, 545 #endif 546 #ifdef CONFIG_BCM63XX_CPU_6345 547 &board_96345gw2, 548 #endif 549 #ifdef CONFIG_BCM63XX_CPU_6348 550 &board_96348r, 551 &board_96348gw, 552 &board_96348gw_10, 553 &board_96348gw_11, 554 &board_FAST2404, 555 &board_DV201AMR, 556 &board_96348gw_a, 557 #endif 558 559 #ifdef CONFIG_BCM63XX_CPU_6358 560 &board_96358vw, 561 &board_96358vw2, 562 &board_AGPFS0, 563 #endif 564 }; 565 566 /* 567 * early init callback, read nvram data from flash and checksum it 568 */ 569 void __init board_prom_init(void) 570 { 571 unsigned int check_len, i; 572 u8 *boot_addr, *cfe, *p; 573 char cfe_version[32]; 574 u32 val; 575 576 /* read base address of boot chip select (0) 577 * 6345 does not have MPI but boots from standard 578 * MIPS Flash address */ 579 if (BCMCPU_IS_6345()) 580 val = 0x1fc00000; 581 else { 582 val = bcm_mpi_readl(MPI_CSBASE_REG(0)); 583 val &= MPI_CSBASE_BASE_MASK; 584 } 585 boot_addr = (u8 *)KSEG1ADDR(val); 586 587 /* dump cfe version */ 588 cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET; 589 if (!memcmp(cfe, "cfe-v", 5)) 590 snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u", 591 cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]); 592 else 593 strcpy(cfe_version, "unknown"); 594 printk(KERN_INFO PFX "CFE version: %s\n", cfe_version); 595 596 /* extract nvram data */ 597 memcpy(&nvram, boot_addr + BCM963XX_NVRAM_OFFSET, sizeof(nvram)); 598 599 /* check checksum before using data */ 600 if (nvram.version <= 4) 601 check_len = offsetof(struct bcm963xx_nvram, checksum_old); 602 else 603 check_len = sizeof(nvram); 604 val = 0; 605 p = (u8 *)&nvram; 606 while (check_len--) 607 val += *p; 608 if (val) { 609 printk(KERN_ERR PFX "invalid nvram checksum\n"); 610 return; 611 } 612 613 /* find board by name */ 614 for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) { 615 if (strncmp(nvram.name, bcm963xx_boards[i]->name, 616 sizeof(nvram.name))) 617 continue; 618 /* copy, board desc array is marked initdata */ 619 memcpy(&board, bcm963xx_boards[i], sizeof(board)); 620 break; 621 } 622 623 /* bail out if board is not found, will complain later */ 624 if (!board.name[0]) { 625 char name[17]; 626 memcpy(name, nvram.name, 16); 627 name[16] = 0; 628 printk(KERN_ERR PFX "unknown bcm963xx board: %s\n", 629 name); 630 return; 631 } 632 633 /* setup pin multiplexing depending on board enabled device, 634 * this has to be done this early since PCI init is done 635 * inside arch_initcall */ 636 val = 0; 637 638 #ifdef CONFIG_PCI 639 if (board.has_pci) { 640 bcm63xx_pci_enabled = 1; 641 if (BCMCPU_IS_6348()) 642 val |= GPIO_MODE_6348_G2_PCI; 643 } 644 #endif 645 646 if (board.has_pccard) { 647 if (BCMCPU_IS_6348()) 648 val |= GPIO_MODE_6348_G1_MII_PCCARD; 649 } 650 651 if (board.has_enet0 && !board.enet0.use_internal_phy) { 652 if (BCMCPU_IS_6348()) 653 val |= GPIO_MODE_6348_G3_EXT_MII | 654 GPIO_MODE_6348_G0_EXT_MII; 655 } 656 657 if (board.has_enet1 && !board.enet1.use_internal_phy) { 658 if (BCMCPU_IS_6348()) 659 val |= GPIO_MODE_6348_G3_EXT_MII | 660 GPIO_MODE_6348_G0_EXT_MII; 661 } 662 663 bcm_gpio_writel(val, GPIO_MODE_REG); 664 } 665 666 /* 667 * second stage init callback, good time to panic if we couldn't 668 * identify on which board we're running since early printk is working 669 */ 670 void __init board_setup(void) 671 { 672 if (!board.name[0]) 673 panic("unable to detect bcm963xx board"); 674 printk(KERN_INFO PFX "board name: %s\n", board.name); 675 676 /* make sure we're running on expected cpu */ 677 if (bcm63xx_get_cpu_id() != board.expected_cpu_id) 678 panic("unexpected CPU for bcm963xx board"); 679 } 680 681 /* 682 * return board name for /proc/cpuinfo 683 */ 684 const char *board_get_name(void) 685 { 686 return board.name; 687 } 688 689 /* 690 * register & return a new board mac address 691 */ 692 static int board_get_mac_address(u8 *mac) 693 { 694 u8 *p; 695 int count; 696 697 if (mac_addr_used >= nvram.mac_addr_count) { 698 printk(KERN_ERR PFX "not enough mac address\n"); 699 return -ENODEV; 700 } 701 702 memcpy(mac, nvram.mac_addr_base, ETH_ALEN); 703 p = mac + ETH_ALEN - 1; 704 count = mac_addr_used; 705 706 while (count--) { 707 do { 708 (*p)++; 709 if (*p != 0) 710 break; 711 p--; 712 } while (p != mac); 713 } 714 715 if (p == mac) { 716 printk(KERN_ERR PFX "unable to fetch mac address\n"); 717 return -ENODEV; 718 } 719 720 mac_addr_used++; 721 return 0; 722 } 723 724 static struct mtd_partition mtd_partitions[] = { 725 { 726 .name = "cfe", 727 .offset = 0x0, 728 .size = 0x40000, 729 } 730 }; 731 732 static struct physmap_flash_data flash_data = { 733 .width = 2, 734 .nr_parts = ARRAY_SIZE(mtd_partitions), 735 .parts = mtd_partitions, 736 }; 737 738 static struct resource mtd_resources[] = { 739 { 740 .start = 0, /* filled at runtime */ 741 .end = 0, /* filled at runtime */ 742 .flags = IORESOURCE_MEM, 743 } 744 }; 745 746 static struct platform_device mtd_dev = { 747 .name = "physmap-flash", 748 .resource = mtd_resources, 749 .num_resources = ARRAY_SIZE(mtd_resources), 750 .dev = { 751 .platform_data = &flash_data, 752 }, 753 }; 754 755 /* 756 * Register a sane SPROMv2 to make the on-board 757 * bcm4318 WLAN work 758 */ 759 #ifdef CONFIG_SSB_PCIHOST 760 static struct ssb_sprom bcm63xx_sprom = { 761 .revision = 0x02, 762 .board_rev = 0x17, 763 .country_code = 0x0, 764 .ant_available_bg = 0x3, 765 .pa0b0 = 0x15ae, 766 .pa0b1 = 0xfa85, 767 .pa0b2 = 0xfe8d, 768 .pa1b0 = 0xffff, 769 .pa1b1 = 0xffff, 770 .pa1b2 = 0xffff, 771 .gpio0 = 0xff, 772 .gpio1 = 0xff, 773 .gpio2 = 0xff, 774 .gpio3 = 0xff, 775 .maxpwr_bg = 0x004c, 776 .itssi_bg = 0x00, 777 .boardflags_lo = 0x2848, 778 .boardflags_hi = 0x0000, 779 }; 780 #endif 781 782 static struct gpio_led_platform_data bcm63xx_led_data; 783 784 static struct platform_device bcm63xx_gpio_leds = { 785 .name = "leds-gpio", 786 .id = 0, 787 .dev.platform_data = &bcm63xx_led_data, 788 }; 789 790 /* 791 * third stage init callback, register all board devices. 792 */ 793 int __init board_register_devices(void) 794 { 795 u32 val; 796 797 bcm63xx_uart_register(); 798 799 if (board.has_pccard) 800 bcm63xx_pcmcia_register(); 801 802 if (board.has_enet0 && 803 !board_get_mac_address(board.enet0.mac_addr)) 804 bcm63xx_enet_register(0, &board.enet0); 805 806 if (board.has_enet1 && 807 !board_get_mac_address(board.enet1.mac_addr)) 808 bcm63xx_enet_register(1, &board.enet1); 809 810 if (board.has_dsp) 811 bcm63xx_dsp_register(&board.dsp); 812 813 /* Generate MAC address for WLAN and 814 * register our SPROM */ 815 #ifdef CONFIG_SSB_PCIHOST 816 if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { 817 memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); 818 memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); 819 if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0) 820 printk(KERN_ERR "failed to register fallback SPROM\n"); 821 } 822 #endif 823 824 /* read base address of boot chip select (0) */ 825 if (BCMCPU_IS_6345()) 826 val = 0x1fc00000; 827 else { 828 val = bcm_mpi_readl(MPI_CSBASE_REG(0)); 829 val &= MPI_CSBASE_BASE_MASK; 830 } 831 mtd_resources[0].start = val; 832 mtd_resources[0].end = 0x1FFFFFFF; 833 834 platform_device_register(&mtd_dev); 835 836 bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds); 837 bcm63xx_led_data.leds = board.leds; 838 839 platform_device_register(&bcm63xx_gpio_leds); 840 841 return 0; 842 } 843 844