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