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