diff options
author | David Daney <david.daney@cavium.com> | 2012-07-05 12:12:38 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-07-23 08:54:52 -0400 |
commit | 7ed1815296498e9d1bfa1f13e94b743364b14caf (patch) | |
tree | f8988180f1827f9a0f9e251ae79afc80745ec7f6 /arch/mips/cavium-octeon/octeon-platform.c | |
parent | b01da9f130adbf69cfbad2a65f1327f1382bf4ae (diff) |
MIPS: Octeon: Initialize and fixup device tree.
If a compiled in device tree template is used, trim out unwanted parts
based on legacy platform probing.
Signed-off-by: David Daney <david.daney@cavium.com>
Cc: linux-mips@linux-mips.org
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: linux-kernel@vger.kernel.org
Cc: David Daney <david.daney@cavium.com>
Patchwork: https://patchwork.linux-mips.org/patch/3935/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/cavium-octeon/octeon-platform.c')
-rw-r--r-- | arch/mips/cavium-octeon/octeon-platform.c | 523 |
1 files changed, 522 insertions, 1 deletions
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index cd61d7281d91..2754bc225903 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2004-2010 Cavium Networks | 6 | * Copyright (C) 2004-2011 Cavium Networks |
7 | * Copyright (C) 2008 Wind River Systems | 7 | * Copyright (C) 2008 Wind River Systems |
8 | */ | 8 | */ |
9 | 9 | ||
@@ -13,10 +13,16 @@ | |||
13 | #include <linux/usb.h> | 13 | #include <linux/usb.h> |
14 | #include <linux/dma-mapping.h> | 14 | #include <linux/dma-mapping.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | ||
16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/of_fdt.h> | ||
20 | #include <linux/libfdt.h> | ||
17 | 21 | ||
18 | #include <asm/octeon/octeon.h> | 22 | #include <asm/octeon/octeon.h> |
19 | #include <asm/octeon/cvmx-rnm-defs.h> | 23 | #include <asm/octeon/cvmx-rnm-defs.h> |
24 | #include <asm/octeon/cvmx-helper.h> | ||
25 | #include <asm/octeon/cvmx-helper-board.h> | ||
20 | 26 | ||
21 | static struct octeon_cf_data octeon_cf_data; | 27 | static struct octeon_cf_data octeon_cf_data; |
22 | 28 | ||
@@ -440,6 +446,521 @@ device_initcall(octeon_ohci_device_init); | |||
440 | 446 | ||
441 | #endif /* CONFIG_USB */ | 447 | #endif /* CONFIG_USB */ |
442 | 448 | ||
449 | static struct of_device_id __initdata octeon_ids[] = { | ||
450 | { .compatible = "simple-bus", }, | ||
451 | { .compatible = "cavium,octeon-6335-uctl", }, | ||
452 | { .compatible = "cavium,octeon-3860-bootbus", }, | ||
453 | { .compatible = "cavium,mdio-mux", }, | ||
454 | { .compatible = "gpio-leds", }, | ||
455 | {}, | ||
456 | }; | ||
457 | |||
458 | static bool __init octeon_has_88e1145(void) | ||
459 | { | ||
460 | return !OCTEON_IS_MODEL(OCTEON_CN52XX) && | ||
461 | !OCTEON_IS_MODEL(OCTEON_CN6XXX) && | ||
462 | !OCTEON_IS_MODEL(OCTEON_CN56XX); | ||
463 | } | ||
464 | |||
465 | static void __init octeon_fdt_set_phy(int eth, int phy_addr) | ||
466 | { | ||
467 | const __be32 *phy_handle; | ||
468 | const __be32 *alt_phy_handle; | ||
469 | const __be32 *reg; | ||
470 | u32 phandle; | ||
471 | int phy; | ||
472 | int alt_phy; | ||
473 | const char *p; | ||
474 | int current_len; | ||
475 | char new_name[20]; | ||
476 | |||
477 | phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL); | ||
478 | if (!phy_handle) | ||
479 | return; | ||
480 | |||
481 | phandle = be32_to_cpup(phy_handle); | ||
482 | phy = fdt_node_offset_by_phandle(initial_boot_params, phandle); | ||
483 | |||
484 | alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); | ||
485 | if (alt_phy_handle) { | ||
486 | u32 alt_phandle = be32_to_cpup(alt_phy_handle); | ||
487 | alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle); | ||
488 | } else { | ||
489 | alt_phy = -1; | ||
490 | } | ||
491 | |||
492 | if (phy_addr < 0 || phy < 0) { | ||
493 | /* Delete the PHY things */ | ||
494 | fdt_nop_property(initial_boot_params, eth, "phy-handle"); | ||
495 | /* This one may fail */ | ||
496 | fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle"); | ||
497 | if (phy >= 0) | ||
498 | fdt_nop_node(initial_boot_params, phy); | ||
499 | if (alt_phy >= 0) | ||
500 | fdt_nop_node(initial_boot_params, alt_phy); | ||
501 | return; | ||
502 | } | ||
503 | |||
504 | if (phy_addr >= 256 && alt_phy > 0) { | ||
505 | const struct fdt_property *phy_prop; | ||
506 | struct fdt_property *alt_prop; | ||
507 | u32 phy_handle_name; | ||
508 | |||
509 | /* Use the alt phy node instead.*/ | ||
510 | phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL); | ||
511 | phy_handle_name = phy_prop->nameoff; | ||
512 | fdt_nop_node(initial_boot_params, phy); | ||
513 | fdt_nop_property(initial_boot_params, eth, "phy-handle"); | ||
514 | alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); | ||
515 | alt_prop->nameoff = phy_handle_name; | ||
516 | phy = alt_phy; | ||
517 | } | ||
518 | |||
519 | phy_addr &= 0xff; | ||
520 | |||
521 | if (octeon_has_88e1145()) { | ||
522 | fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); | ||
523 | memset(new_name, 0, sizeof(new_name)); | ||
524 | strcpy(new_name, "marvell,88e1145"); | ||
525 | p = fdt_getprop(initial_boot_params, phy, "compatible", | ||
526 | ¤t_len); | ||
527 | if (p && current_len >= strlen(new_name)) | ||
528 | fdt_setprop_inplace(initial_boot_params, phy, | ||
529 | "compatible", new_name, current_len); | ||
530 | } | ||
531 | |||
532 | reg = fdt_getprop(initial_boot_params, phy, "reg", NULL); | ||
533 | if (phy_addr == be32_to_cpup(reg)) | ||
534 | return; | ||
535 | |||
536 | fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr); | ||
537 | |||
538 | snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr); | ||
539 | |||
540 | p = fdt_get_name(initial_boot_params, phy, ¤t_len); | ||
541 | if (p && current_len == strlen(new_name)) | ||
542 | fdt_set_name(initial_boot_params, phy, new_name); | ||
543 | else | ||
544 | pr_err("Error: could not rename ethernet phy: <%s>", p); | ||
545 | } | ||
546 | |||
547 | static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) | ||
548 | { | ||
549 | u8 new_mac[6]; | ||
550 | u64 mac = *pmac; | ||
551 | int r; | ||
552 | |||
553 | new_mac[0] = (mac >> 40) & 0xff; | ||
554 | new_mac[1] = (mac >> 32) & 0xff; | ||
555 | new_mac[2] = (mac >> 24) & 0xff; | ||
556 | new_mac[3] = (mac >> 16) & 0xff; | ||
557 | new_mac[4] = (mac >> 8) & 0xff; | ||
558 | new_mac[5] = mac & 0xff; | ||
559 | |||
560 | r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address", | ||
561 | new_mac, sizeof(new_mac)); | ||
562 | |||
563 | if (r) { | ||
564 | pr_err("Setting \"local-mac-address\" failed %d", r); | ||
565 | return; | ||
566 | } | ||
567 | *pmac = mac + 1; | ||
568 | } | ||
569 | |||
570 | static void __init octeon_fdt_rm_ethernet(int node) | ||
571 | { | ||
572 | const __be32 *phy_handle; | ||
573 | |||
574 | phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL); | ||
575 | if (phy_handle) { | ||
576 | u32 ph = be32_to_cpup(phy_handle); | ||
577 | int p = fdt_node_offset_by_phandle(initial_boot_params, ph); | ||
578 | if (p >= 0) | ||
579 | fdt_nop_node(initial_boot_params, p); | ||
580 | } | ||
581 | fdt_nop_node(initial_boot_params, node); | ||
582 | } | ||
583 | |||
584 | static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac) | ||
585 | { | ||
586 | char name_buffer[20]; | ||
587 | int eth; | ||
588 | int phy_addr; | ||
589 | int ipd_port; | ||
590 | |||
591 | snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p); | ||
592 | eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer); | ||
593 | if (eth < 0) | ||
594 | return; | ||
595 | if (p > max) { | ||
596 | pr_debug("Deleting port %x:%x\n", i, p); | ||
597 | octeon_fdt_rm_ethernet(eth); | ||
598 | return; | ||
599 | } | ||
600 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
601 | ipd_port = (0x100 * i) + (0x10 * p) + 0x800; | ||
602 | else | ||
603 | ipd_port = 16 * i + p; | ||
604 | |||
605 | phy_addr = cvmx_helper_board_get_mii_address(ipd_port); | ||
606 | octeon_fdt_set_phy(eth, phy_addr); | ||
607 | octeon_fdt_set_mac_addr(eth, pmac); | ||
608 | } | ||
609 | |||
610 | static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) | ||
611 | { | ||
612 | char name_buffer[20]; | ||
613 | int iface; | ||
614 | int p; | ||
615 | int count; | ||
616 | |||
617 | count = cvmx_helper_interface_enumerate(idx); | ||
618 | |||
619 | snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); | ||
620 | iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); | ||
621 | if (iface < 0) | ||
622 | return; | ||
623 | |||
624 | for (p = 0; p < 16; p++) | ||
625 | octeon_fdt_pip_port(iface, idx, p, count - 1, pmac); | ||
626 | } | ||
627 | |||
628 | int __init octeon_prune_device_tree(void) | ||
629 | { | ||
630 | int i, max_port, uart_mask; | ||
631 | const char *pip_path; | ||
632 | const char *alias_prop; | ||
633 | char name_buffer[20]; | ||
634 | int aliases; | ||
635 | u64 mac_addr_base; | ||
636 | |||
637 | if (fdt_check_header(initial_boot_params)) | ||
638 | panic("Corrupt Device Tree."); | ||
639 | |||
640 | aliases = fdt_path_offset(initial_boot_params, "/aliases"); | ||
641 | if (aliases < 0) { | ||
642 | pr_err("Error: No /aliases node in device tree."); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | |||
646 | |||
647 | mac_addr_base = | ||
648 | ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | | ||
649 | ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | | ||
650 | ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | | ||
651 | ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | | ||
652 | ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | | ||
653 | (octeon_bootinfo->mac_addr_base[5] & 0xffull); | ||
654 | |||
655 | if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) | ||
656 | max_port = 2; | ||
657 | else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
658 | max_port = 1; | ||
659 | else | ||
660 | max_port = 0; | ||
661 | |||
662 | if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E) | ||
663 | max_port = 0; | ||
664 | |||
665 | for (i = 0; i < 2; i++) { | ||
666 | int mgmt; | ||
667 | snprintf(name_buffer, sizeof(name_buffer), | ||
668 | "mix%d", i); | ||
669 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
670 | name_buffer, NULL); | ||
671 | if (alias_prop) { | ||
672 | mgmt = fdt_path_offset(initial_boot_params, alias_prop); | ||
673 | if (mgmt < 0) | ||
674 | continue; | ||
675 | if (i >= max_port) { | ||
676 | pr_debug("Deleting mix%d\n", i); | ||
677 | octeon_fdt_rm_ethernet(mgmt); | ||
678 | fdt_nop_property(initial_boot_params, aliases, | ||
679 | name_buffer); | ||
680 | } else { | ||
681 | int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); | ||
682 | octeon_fdt_set_phy(mgmt, phy_addr); | ||
683 | octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | |||
688 | pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL); | ||
689 | if (pip_path) { | ||
690 | int pip = fdt_path_offset(initial_boot_params, pip_path); | ||
691 | if (pip >= 0) | ||
692 | for (i = 0; i <= 4; i++) | ||
693 | octeon_fdt_pip_iface(pip, i, &mac_addr_base); | ||
694 | } | ||
695 | |||
696 | /* I2C */ | ||
697 | if (OCTEON_IS_MODEL(OCTEON_CN52XX) || | ||
698 | OCTEON_IS_MODEL(OCTEON_CN63XX) || | ||
699 | OCTEON_IS_MODEL(OCTEON_CN68XX) || | ||
700 | OCTEON_IS_MODEL(OCTEON_CN56XX)) | ||
701 | max_port = 2; | ||
702 | else | ||
703 | max_port = 1; | ||
704 | |||
705 | for (i = 0; i < 2; i++) { | ||
706 | int i2c; | ||
707 | snprintf(name_buffer, sizeof(name_buffer), | ||
708 | "twsi%d", i); | ||
709 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
710 | name_buffer, NULL); | ||
711 | |||
712 | if (alias_prop) { | ||
713 | i2c = fdt_path_offset(initial_boot_params, alias_prop); | ||
714 | if (i2c < 0) | ||
715 | continue; | ||
716 | if (i >= max_port) { | ||
717 | pr_debug("Deleting twsi%d\n", i); | ||
718 | fdt_nop_node(initial_boot_params, i2c); | ||
719 | fdt_nop_property(initial_boot_params, aliases, | ||
720 | name_buffer); | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | |||
725 | /* SMI/MDIO */ | ||
726 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
727 | max_port = 4; | ||
728 | else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || | ||
729 | OCTEON_IS_MODEL(OCTEON_CN63XX) || | ||
730 | OCTEON_IS_MODEL(OCTEON_CN56XX)) | ||
731 | max_port = 2; | ||
732 | else | ||
733 | max_port = 1; | ||
734 | |||
735 | for (i = 0; i < 2; i++) { | ||
736 | int i2c; | ||
737 | snprintf(name_buffer, sizeof(name_buffer), | ||
738 | "smi%d", i); | ||
739 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
740 | name_buffer, NULL); | ||
741 | |||
742 | if (alias_prop) { | ||
743 | i2c = fdt_path_offset(initial_boot_params, alias_prop); | ||
744 | if (i2c < 0) | ||
745 | continue; | ||
746 | if (i >= max_port) { | ||
747 | pr_debug("Deleting smi%d\n", i); | ||
748 | fdt_nop_node(initial_boot_params, i2c); | ||
749 | fdt_nop_property(initial_boot_params, aliases, | ||
750 | name_buffer); | ||
751 | } | ||
752 | } | ||
753 | } | ||
754 | |||
755 | /* Serial */ | ||
756 | uart_mask = 3; | ||
757 | |||
758 | /* Right now CN52XX is the only chip with a third uart */ | ||
759 | if (OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
760 | uart_mask |= 4; /* uart2 */ | ||
761 | |||
762 | for (i = 0; i < 3; i++) { | ||
763 | int uart; | ||
764 | snprintf(name_buffer, sizeof(name_buffer), | ||
765 | "uart%d", i); | ||
766 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
767 | name_buffer, NULL); | ||
768 | |||
769 | if (alias_prop) { | ||
770 | uart = fdt_path_offset(initial_boot_params, alias_prop); | ||
771 | if (uart_mask & (1 << i)) | ||
772 | continue; | ||
773 | pr_debug("Deleting uart%d\n", i); | ||
774 | fdt_nop_node(initial_boot_params, uart); | ||
775 | fdt_nop_property(initial_boot_params, aliases, | ||
776 | name_buffer); | ||
777 | } | ||
778 | } | ||
779 | |||
780 | /* Compact Flash */ | ||
781 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
782 | "cf0", NULL); | ||
783 | if (alias_prop) { | ||
784 | union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; | ||
785 | unsigned long base_ptr, region_base, region_size; | ||
786 | unsigned long region1_base = 0; | ||
787 | unsigned long region1_size = 0; | ||
788 | int cs, bootbus; | ||
789 | bool is_16bit = false; | ||
790 | bool is_true_ide = false; | ||
791 | __be32 new_reg[6]; | ||
792 | __be32 *ranges; | ||
793 | int len; | ||
794 | |||
795 | int cf = fdt_path_offset(initial_boot_params, alias_prop); | ||
796 | base_ptr = 0; | ||
797 | if (octeon_bootinfo->major_version == 1 | ||
798 | && octeon_bootinfo->minor_version >= 1) { | ||
799 | if (octeon_bootinfo->compact_flash_common_base_addr) | ||
800 | base_ptr = octeon_bootinfo->compact_flash_common_base_addr; | ||
801 | } else { | ||
802 | base_ptr = 0x1d000800; | ||
803 | } | ||
804 | |||
805 | if (!base_ptr) | ||
806 | goto no_cf; | ||
807 | |||
808 | /* Find CS0 region. */ | ||
809 | for (cs = 0; cs < 8; cs++) { | ||
810 | mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); | ||
811 | region_base = mio_boot_reg_cfg.s.base << 16; | ||
812 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | ||
813 | if (mio_boot_reg_cfg.s.en && base_ptr >= region_base | ||
814 | && base_ptr < region_base + region_size) { | ||
815 | is_16bit = mio_boot_reg_cfg.s.width; | ||
816 | break; | ||
817 | } | ||
818 | } | ||
819 | if (cs >= 7) { | ||
820 | /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */ | ||
821 | goto no_cf; | ||
822 | } | ||
823 | |||
824 | if (!(base_ptr & 0xfffful)) { | ||
825 | /* | ||
826 | * Boot loader signals availability of DMA (true_ide | ||
827 | * mode) by setting low order bits of base_ptr to | ||
828 | * zero. | ||
829 | */ | ||
830 | |||
831 | /* Asume that CS1 immediately follows. */ | ||
832 | mio_boot_reg_cfg.u64 = | ||
833 | cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); | ||
834 | region1_base = mio_boot_reg_cfg.s.base << 16; | ||
835 | region1_size = (mio_boot_reg_cfg.s.size + 1) << 16; | ||
836 | if (!mio_boot_reg_cfg.s.en) | ||
837 | goto no_cf; | ||
838 | is_true_ide = true; | ||
839 | |||
840 | } else { | ||
841 | fdt_nop_property(initial_boot_params, cf, "cavium,true-ide"); | ||
842 | fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle"); | ||
843 | if (!is_16bit) { | ||
844 | __be32 width = cpu_to_be32(8); | ||
845 | fdt_setprop_inplace(initial_boot_params, cf, | ||
846 | "cavium,bus-width", &width, sizeof(width)); | ||
847 | } | ||
848 | } | ||
849 | new_reg[0] = cpu_to_be32(cs); | ||
850 | new_reg[1] = cpu_to_be32(0); | ||
851 | new_reg[2] = cpu_to_be32(0x10000); | ||
852 | new_reg[3] = cpu_to_be32(cs + 1); | ||
853 | new_reg[4] = cpu_to_be32(0); | ||
854 | new_reg[5] = cpu_to_be32(0x10000); | ||
855 | fdt_setprop_inplace(initial_boot_params, cf, | ||
856 | "reg", new_reg, sizeof(new_reg)); | ||
857 | |||
858 | bootbus = fdt_parent_offset(initial_boot_params, cf); | ||
859 | if (bootbus < 0) | ||
860 | goto no_cf; | ||
861 | ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); | ||
862 | if (!ranges || len < (5 * 8 * sizeof(__be32))) | ||
863 | goto no_cf; | ||
864 | |||
865 | ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); | ||
866 | ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); | ||
867 | ranges[(cs * 5) + 4] = cpu_to_be32(region_size); | ||
868 | if (is_true_ide) { | ||
869 | cs++; | ||
870 | ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32); | ||
871 | ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff); | ||
872 | ranges[(cs * 5) + 4] = cpu_to_be32(region1_size); | ||
873 | } | ||
874 | goto end_cf; | ||
875 | no_cf: | ||
876 | fdt_nop_node(initial_boot_params, cf); | ||
877 | |||
878 | end_cf: | ||
879 | ; | ||
880 | } | ||
881 | |||
882 | /* 8 char LED */ | ||
883 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
884 | "led0", NULL); | ||
885 | if (alias_prop) { | ||
886 | union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; | ||
887 | unsigned long base_ptr, region_base, region_size; | ||
888 | int cs, bootbus; | ||
889 | __be32 new_reg[6]; | ||
890 | __be32 *ranges; | ||
891 | int len; | ||
892 | int led = fdt_path_offset(initial_boot_params, alias_prop); | ||
893 | |||
894 | base_ptr = octeon_bootinfo->led_display_base_addr; | ||
895 | if (base_ptr == 0) | ||
896 | goto no_led; | ||
897 | /* Find CS0 region. */ | ||
898 | for (cs = 0; cs < 8; cs++) { | ||
899 | mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); | ||
900 | region_base = mio_boot_reg_cfg.s.base << 16; | ||
901 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | ||
902 | if (mio_boot_reg_cfg.s.en && base_ptr >= region_base | ||
903 | && base_ptr < region_base + region_size) | ||
904 | break; | ||
905 | } | ||
906 | |||
907 | if (cs > 7) | ||
908 | goto no_led; | ||
909 | |||
910 | new_reg[0] = cpu_to_be32(cs); | ||
911 | new_reg[1] = cpu_to_be32(0x20); | ||
912 | new_reg[2] = cpu_to_be32(0x20); | ||
913 | new_reg[3] = cpu_to_be32(cs); | ||
914 | new_reg[4] = cpu_to_be32(0); | ||
915 | new_reg[5] = cpu_to_be32(0x20); | ||
916 | fdt_setprop_inplace(initial_boot_params, led, | ||
917 | "reg", new_reg, sizeof(new_reg)); | ||
918 | |||
919 | bootbus = fdt_parent_offset(initial_boot_params, led); | ||
920 | if (bootbus < 0) | ||
921 | goto no_led; | ||
922 | ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); | ||
923 | if (!ranges || len < (5 * 8 * sizeof(__be32))) | ||
924 | goto no_led; | ||
925 | |||
926 | ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); | ||
927 | ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); | ||
928 | ranges[(cs * 5) + 4] = cpu_to_be32(region_size); | ||
929 | goto end_led; | ||
930 | |||
931 | no_led: | ||
932 | fdt_nop_node(initial_boot_params, led); | ||
933 | end_led: | ||
934 | ; | ||
935 | } | ||
936 | |||
937 | /* OHCI/UHCI USB */ | ||
938 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
939 | "uctl", NULL); | ||
940 | if (alias_prop) { | ||
941 | int uctl = fdt_path_offset(initial_boot_params, alias_prop); | ||
942 | |||
943 | if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) || | ||
944 | octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) { | ||
945 | pr_debug("Deleting uctl\n"); | ||
946 | fdt_nop_node(initial_boot_params, uctl); | ||
947 | fdt_nop_property(initial_boot_params, aliases, "uctl"); | ||
948 | } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E || | ||
949 | octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) { | ||
950 | /* Missing "refclk-type" defaults to crystal. */ | ||
951 | fdt_nop_property(initial_boot_params, uctl, "refclk-type"); | ||
952 | } | ||
953 | } | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int __init octeon_publish_devices(void) | ||
959 | { | ||
960 | return of_platform_bus_probe(NULL, octeon_ids, NULL); | ||
961 | } | ||
962 | device_initcall(octeon_publish_devices); | ||
963 | |||
443 | MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); | 964 | MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); |
444 | MODULE_LICENSE("GPL"); | 965 | MODULE_LICENSE("GPL"); |
445 | MODULE_DESCRIPTION("Platform driver for Octeon SOC"); | 966 | MODULE_DESCRIPTION("Platform driver for Octeon SOC"); |