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