octeon: testing kernel 6.1 snic10e-6.1
authorStijn Tintel <stijn@linux-ipv6.be>
Thu, 9 Nov 2023 13:34:21 +0000 (15:34 +0200)
committerStijn Tintel <stijn@linux-ipv6.be>
Thu, 9 Nov 2023 13:34:51 +0000 (15:34 +0200)
target/linux/octeon/Makefile
target/linux/octeon/config-6.1 [new file with mode: 0644]
target/linux/octeon/patches-6.1/100-mips_image_cmdline_hack.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/100-ubnt_edgerouter2_support.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/120-cmdline-hack.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/130-add_itus_support.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/150-ubnt_usg_support.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/700-allocate_interface_by_label.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/701-honor_sgmii_node_device_tree_status.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/710-netdev-phy-of-Handle-nexus-Ethernet-PHY-devices.patch [new file with mode: 0644]
target/linux/octeon/patches-6.1/711-netdev-phy-Add-driver-for-Vitesse-vsc848x-single-dua.patch [new file with mode: 0644]

index 4b5c4c07c103a3117db61872bd20aaab9ef6a5f6..0c9d715c33dfbd4d42abdf31817a57b126c0e467 100644 (file)
@@ -11,6 +11,7 @@ FEATURES:=squashfs ramdisk pci usb
 CPU_TYPE:=octeonplus
 
 KERNEL_PATCHVER:=5.15
+KERNEL_TESTING_PATCHVER:=6.1
 
 define Target/Description
        Build firmware images for Cavium Networks Octeon-based boards.
diff --git a/target/linux/octeon/config-6.1 b/target/linux/octeon/config-6.1
new file mode 100644 (file)
index 0000000..3748863
--- /dev/null
@@ -0,0 +1,303 @@
+CONFIG_64BIT=y
+CONFIG_AHCI_OCTEON=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_ARCH_MMAP_RND_BITS=12
+CONFIG_ARCH_MMAP_RND_BITS_MAX=18
+CONFIG_ARCH_MMAP_RND_BITS_MIN=12
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ATA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BUILTIN_DTB=y
+CONFIG_CAVIUM_CN63XXP1=y
+CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE=0
+CONFIG_CAVIUM_OCTEON_LOCK_L2=y
+CONFIG_CAVIUM_OCTEON_LOCK_L2_EXCEPTION=y
+CONFIG_CAVIUM_OCTEON_LOCK_L2_INTERRUPT=y
+CONFIG_CAVIUM_OCTEON_LOCK_L2_LOW_LEVEL_INTERRUPT=y
+CONFIG_CAVIUM_OCTEON_LOCK_L2_MEMCPY=y
+CONFIG_CAVIUM_OCTEON_LOCK_L2_TLB=y
+CONFIG_CAVIUM_OCTEON_SOC=y
+CONFIG_CAVIUM_RESERVE32=0
+CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
+CONFIG_CC_NO_ARRAY_BOUNDS=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLONE_BACKWARDS=y
+# CONFIG_COMMON_CLK is not set
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_CONTEXT_TRACKING=y
+CONFIG_CONTEXT_TRACKING_IDLE=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_CAVIUM_OCTEON=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS64=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_HUGEPAGES=y
+CONFIG_CRAMFS=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_LIB_SHA1=y
+CONFIG_CRYPTO_LIB_UTILS=y
+# CONFIG_CRYPTO_MD5_OCTEON is not set
+CONFIG_CRYPTO_RNG2=y
+# CONFIG_CRYPTO_SHA1_OCTEON is not set
+# CONFIG_CRYPTO_SHA256_OCTEON is not set
+# CONFIG_CRYPTO_SHA512_OCTEON is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
+CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_EDAC=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_LEGACY_SYSFS=y
+CONFIG_EDAC_OCTEON_L2C=y
+CONFIG_EDAC_OCTEON_LMC=y
+CONFIG_EDAC_OCTEON_PC=y
+CONFIG_EDAC_OCTEON_PCI=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EEPROM_AT24=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_EXT4_FS=y
+CONFIG_F2FS_FS=y
+CONFIG_FAT_FS=y
+CONFIG_FIXED_PHY=y
+CONFIG_FS_IOMAP=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_GCC11_NO_ARRAY_BOUNDS=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GLOB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_CDEV_V1=y
+CONFIG_GPIO_OCTEON=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GRO_CELLS=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OCTEON=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_OCTEON=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_LIBFDT=y
+CONFIG_LOCKDEP=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_CAVIUM=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+CONFIG_MDIO_I2C=y
+CONFIG_MDIO_OCTEON=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_MIPS_ELF_APPENDED_DTB=y
+CONFIG_MIPS_FP_SUPPORT=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+CONFIG_MIPS_L1_CACHE_SHIFT_7=y
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_NR_CPU_NR_MAP=1024
+CONFIG_MIPS_NR_CPU_NR_MAP_1024=y
+CONFIG_MIPS_PGD_C0_CONTEXT=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_CAVIUM_OCTEON=y
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MODULES_USE_ELF_RELA=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_DEVLINK=y
+CONFIG_NET_DSA=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NOP_TRACER=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+CONFIG_NR_CPUS=16
+CONFIG_NR_CPUS_DEFAULT_64=y
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OCTEON_ETHERNET=y
+CONFIG_OCTEON_ILM=y
+CONFIG_OCTEON_MGMT_ETHERNET=y
+CONFIG_OCTEON_WDT=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_PADATA=y
+CONFIG_PAGE_POOL=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PATA_OCTEON_CF=y
+CONFIG_PATA_TIMINGS=y
+CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=y
+CONFIG_PHYLINK=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_PREEMPTIRQ_TRACEPOINTS=y
+CONFIG_PREEMPT_COUNT=y
+CONFIG_PREEMPT_NONE_BUILD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RAS=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_RELAY=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RING_BUFFER=y
+CONFIG_RPS=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_SATA_HOST=y
+CONFIG_SCSI=y
+CONFIG_SCSI_COMMON=y
+CONFIG_SECCOMP=y
+CONFIG_SECCOMP_FILTER=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_DWLIB=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SFP=y
+CONFIG_SG_POOL=y
+CONFIG_SMP=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_OCTEON=y
+CONFIG_SRCU=y
+CONFIG_STACKTRACE=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_CAVIUM_OCTEON=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_RELOCATABLE=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_TRACE_IRQFLAGS=y
+CONFIG_TRACING=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+# CONFIG_USB_OCTEON_EHCI is not set
+CONFIG_USB_OCTEON_HCD=y
+# CONFIG_USB_OCTEON_OHCI is not set
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USE_OF=y
+CONFIG_VFAT_FS=y
+CONFIG_VITESSE_PHY=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VSC848X_PHY=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_XPS=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA32=y
diff --git a/target/linux/octeon/patches-6.1/100-mips_image_cmdline_hack.patch b/target/linux/octeon/patches-6.1/100-mips_image_cmdline_hack.patch
new file mode 100644 (file)
index 0000000..08f30c5
--- /dev/null
@@ -0,0 +1,38 @@
+From: John Crispin <john@phrozen.org>
+Subject: hack: kernel: add generic image_cmdline hack to MIPS targets
+
+lede-commit: d59f5b3a987a48508257a0ddbaeadc7909f9f976
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ arch/mips/Kconfig       | 4 ++++
+ arch/mips/kernel/head.S | 6 ++++++
+ 2 files changed, 10 insertions(+)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1114,6 +1114,10 @@ config MIPS_MSC
+ config SYNC_R4K
+       bool
++config IMAGE_CMDLINE_HACK
++      bool "OpenWrt specific image command line hack"
++      default n
++
+ config NO_IOPORT_MAP
+       def_bool n
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -79,6 +79,12 @@ FEXPORT(__kernel_entry)
+       j       kernel_entry
+ #endif /* CONFIG_BOOT_RAW */
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++      .ascii  "CMDLINE:"
++EXPORT(__image_cmdline)
++      .fill   0x400
++#endif /* CONFIG_IMAGE_CMDLINE_HACK */
++
+       __REF
+ NESTED(kernel_entry, 16, sp)                  # kernel entry point
diff --git a/target/linux/octeon/patches-6.1/100-ubnt_edgerouter2_support.patch b/target/linux/octeon/patches-6.1/100-ubnt_edgerouter2_support.patch
new file mode 100644 (file)
index 0000000..606debd
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
++++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
+@@ -174,6 +174,8 @@ int cvmx_helper_board_get_mii_address(in
+                       return 7 - ipd_port;
+               else
+                       return -1;
++      case CVMX_BOARD_TYPE_UBNT_E200:
++              return -1;
+       case CVMX_BOARD_TYPE_KONTRON_S1901:
+               if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
+                       return 1;
diff --git a/target/linux/octeon/patches-6.1/120-cmdline-hack.patch b/target/linux/octeon/patches-6.1/120-cmdline-hack.patch
new file mode 100644 (file)
index 0000000..e65cf78
--- /dev/null
@@ -0,0 +1,47 @@
+--- a/arch/mips/cavium-octeon/setup.c
++++ b/arch/mips/cavium-octeon/setup.c
+@@ -653,6 +653,35 @@ void octeon_user_io_init(void)
+       write_c0_derraddr1(0);
+ }
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++extern char __image_cmdline[];
++
++static int __init octeon_use_image_cmdline(void)
++{
++       char *p = __image_cmdline;
++       int replace = 0;
++
++       if (*p == '-') {
++               replace = 1;
++               p++;
++       }
++
++       if (*p == '\0')
++               return 0;
++
++       if (replace) {
++               strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
++       } else {
++               strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
++               strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
++       }
++
++       return 1;
++}
++#else
++static inline int octeon_use_image_cmdline(void) { return 0; }
++#endif
++
+ /**
+  * prom_init - Early entry point for arch setup
+  */
+@@ -896,6 +925,8 @@ void __init prom_init(void)
+               }
+       }
++      octeon_use_image_cmdline();
++
+       if (strstr(arcs_cmdline, "console=") == NULL) {
+               if (octeon_uart == 1)
+                       strcat(arcs_cmdline, " console=ttyS1,115200");
diff --git a/target/linux/octeon/patches-6.1/130-add_itus_support.patch b/target/linux/octeon/patches-6.1/130-add_itus_support.patch
new file mode 100644 (file)
index 0000000..d76e863
--- /dev/null
@@ -0,0 +1,42 @@
+--- a/arch/mips/cavium-octeon/octeon-platform.c
++++ b/arch/mips/cavium-octeon/octeon-platform.c
+@@ -774,7 +774,7 @@ int __init octeon_prune_device_tree(void
+       if (fdt_check_header(initial_boot_params))
+               panic("Corrupt Device Tree.");
+-      WARN(octeon_bootinfo->board_type == CVMX_BOARD_TYPE_CUST_DSR1000N,
++      WARN(octeon_bootinfo->board_type == CVMX_BOARD_TYPE_ITUS_SHIELD,
+            "Built-in DTB booting is deprecated on %s. Please switch to use appended DTB.",
+            cvmx_board_type_to_string(octeon_bootinfo->board_type));
+--- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h
++++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h
+@@ -298,7 +298,7 @@ enum cvmx_board_types_enum {
+       CVMX_BOARD_TYPE_UBNT_E100 = 20002,
+       CVMX_BOARD_TYPE_UBNT_E200 = 20003,
+       CVMX_BOARD_TYPE_UBNT_E220 = 20005,
+-      CVMX_BOARD_TYPE_CUST_DSR1000N = 20006,
++      CVMX_BOARD_TYPE_ITUS_SHIELD = 20006,
+       CVMX_BOARD_TYPE_UBNT_E300 = 20300,
+       CVMX_BOARD_TYPE_KONTRON_S1901 = 21901,
+       CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000,
+@@ -403,7 +403,7 @@ static inline const char *cvmx_board_typ
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E200)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E220)
+-              ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N)
++              ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_ITUS_SHIELD)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E300)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX)
+--- a/arch/mips/pci/pci-octeon.c
++++ b/arch/mips/pci/pci-octeon.c
+@@ -211,7 +211,7 @@ const char *octeon_get_pci_interrupts(vo
+               return "AAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+       case CVMX_BOARD_TYPE_BBGW_REF:
+               return "AABCD";
+-      case CVMX_BOARD_TYPE_CUST_DSR1000N:
++      case CVMX_BOARD_TYPE_ITUS_SHIELD:
+               return "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
+       case CVMX_BOARD_TYPE_THUNDER:
+       case CVMX_BOARD_TYPE_EBH3000:
diff --git a/target/linux/octeon/patches-6.1/150-ubnt_usg_support.patch b/target/linux/octeon/patches-6.1/150-ubnt_usg_support.patch
new file mode 100644 (file)
index 0000000..00c268e
--- /dev/null
@@ -0,0 +1,46 @@
+--- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h
++++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h
+@@ -297,6 +297,7 @@ enum cvmx_board_types_enum {
+       CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001,
+       CVMX_BOARD_TYPE_UBNT_E100 = 20002,
+       CVMX_BOARD_TYPE_UBNT_E200 = 20003,
++      CVMX_BOARD_TYPE_UBNT_USG = 20004,
+       CVMX_BOARD_TYPE_UBNT_E220 = 20005,
+       CVMX_BOARD_TYPE_ITUS_SHIELD = 20006,
+       CVMX_BOARD_TYPE_UBNT_E300 = 20300,
+@@ -401,6 +402,7 @@ static inline const char *cvmx_board_typ
+                   /* Customer private range */
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100)
++              ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_USG)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E200)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E220)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_ITUS_SHIELD)
+--- a/arch/mips/cavium-octeon/octeon-platform.c
++++ b/arch/mips/cavium-octeon/octeon-platform.c
+@@ -635,6 +635,7 @@ static void __init octeon_rx_tx_delay(in
+               }
+               break;
+       case CVMX_BOARD_TYPE_UBNT_E100:
++      case CVMX_BOARD_TYPE_UBNT_USG:
+               if (iface == 0 && port <= 2) {
+                       _octeon_rx_tx_delay(eth, 0x0, 0x10);
+                       return;
+--- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
++++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
+@@ -170,6 +170,7 @@ int cvmx_helper_board_get_mii_address(in
+               else
+                       return -1;
+       case CVMX_BOARD_TYPE_UBNT_E100:
++      case CVMX_BOARD_TYPE_UBNT_USG:
+               if (ipd_port >= 0 && ipd_port <= 2)
+                       return 7 - ipd_port;
+               else
+@@ -337,6 +338,7 @@ enum cvmx_helper_board_usb_clock_types _
+       case CVMX_BOARD_TYPE_LANAI2_G:
+       case CVMX_BOARD_TYPE_NIC10E_66:
+       case CVMX_BOARD_TYPE_UBNT_E100:
++      case CVMX_BOARD_TYPE_UBNT_USG:
+               return USB_CLOCK_TYPE_CRYSTAL_12;
+       case CVMX_BOARD_TYPE_NIC10E:
+               return USB_CLOCK_TYPE_REF_12;
diff --git a/target/linux/octeon/patches-6.1/700-allocate_interface_by_label.patch b/target/linux/octeon/patches-6.1/700-allocate_interface_by_label.patch
new file mode 100644 (file)
index 0000000..22f284b
--- /dev/null
@@ -0,0 +1,37 @@
+From: Roman Kuzmitskii <damex.pp@icloud.com>
+Date: Wed, 28 Oct 2020 19:00:00 +0000
+Subject: [PATCH] staging: octeon: add net-labels support
+
+With this patch, device name can be set within dts file
+in the same way as dsa port can.
+
+Add label to pip interface node to use this feature:
+label = "lan0";
+
+Tested-by: Johannes Kimmel <fff@bareminimum.eu>
+Signed-off-by: Roman Kuzmitskii <damex.pp@icloud.com>
+--- a/drivers/staging/octeon/ethernet.c
++++ b/drivers/staging/octeon/ethernet.c
+@@ -407,8 +407,12 @@ static int cvm_oct_common_set_mac_addres
+ int cvm_oct_common_init(struct net_device *dev)
+ {
+       struct octeon_ethernet *priv = netdev_priv(dev);
++      const u8 *label = NULL;
+       int ret;
++      if (priv->of_node)
++              label = of_get_property(priv->of_node, "label", NULL);
++
+       ret = of_get_ethdev_address(priv->of_node, dev);
+       if (ret)
+               eth_hw_addr_random(dev);
+@@ -441,6 +445,9 @@ int cvm_oct_common_init(struct net_devic
+       if (dev->netdev_ops->ndo_stop)
+               dev->netdev_ops->ndo_stop(dev);
++      if (!IS_ERR_OR_NULL(label))
++              dev_alloc_name(dev, label);
++
+       return 0;
+ }
diff --git a/target/linux/octeon/patches-6.1/701-honor_sgmii_node_device_tree_status.patch b/target/linux/octeon/patches-6.1/701-honor_sgmii_node_device_tree_status.patch
new file mode 100644 (file)
index 0000000..771f686
--- /dev/null
@@ -0,0 +1,27 @@
+From: Roman Kuzmitskii <damex.pp@icloud.com>
+Date: Sun, 01 Nov 2020 19:00:00 +0000
+Subject: [PATCH] staging: octeon: sgmii to honor disabled dt node status
+
+With this patch, sgmii interface device tree node could be disabled and
+that disabled interface will not be unnecessarily initialized.
+
+It solves the problem with Octeon boards that have 8 sgmii or more ports
+initialized but have nothing connected to them.
+
+Tested-by: Johannes Kimmel <fff@bareminimum.eu>
+Signed-off-by: Roman Kuzmitskii <damex.pp@icloud.com>
+--- a/drivers/staging/octeon/ethernet.c
++++ b/drivers/staging/octeon/ethernet.c
+@@ -870,8 +870,10 @@ static int cvm_oct_probe(struct platform
+                       case CVMX_HELPER_INTERFACE_MODE_SGMII:
+                               priv->phy_mode = PHY_INTERFACE_MODE_SGMII;
+-                              dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
+-                              strscpy(dev->name, "eth%d", sizeof(dev->name));
++                              if (of_device_is_available(priv->of_node)) {
++                                      dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
++                                      strscpy(dev->name, "eth%d", sizeof(dev->name));
++                              }
+                               break;
+                       case CVMX_HELPER_INTERFACE_MODE_SPI:
diff --git a/target/linux/octeon/patches-6.1/710-netdev-phy-of-Handle-nexus-Ethernet-PHY-devices.patch b/target/linux/octeon/patches-6.1/710-netdev-phy-of-Handle-nexus-Ethernet-PHY-devices.patch
new file mode 100644 (file)
index 0000000..47b8452
--- /dev/null
@@ -0,0 +1,40 @@
+From c59d03f70e739eb7fec976f86fff7dd12968b3fc Mon Sep 17 00:00:00 2001
+From: Leonid Rosenboim <lrosenboim@caviumnetworks.com>
+Date: Fri, 13 Feb 2015 15:04:26 +0530
+Subject: [PATCH 2/5] netdev/phy/of: Handle nexus Ethernet PHY devices
+
+Some multi-phy devices have resources that are global between all of the
+PHYs on the same device such as the Vitesse vsc8488.  In this case each
+individual PHY is contained within a phy nexus device.
+
+Signed-off-by: Leonid Rosenboim <lrosenboim@caviumnetworks.com>
+Signed-off-by: Aaron Williams <aaron.williams@cavium.com>
+Signed-off-by: Abhishek Paliwal <abhishek.paliwal@aricent.com>
+[rebase on 5.10]
+Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
+---
+ drivers/net/mdio/of_mdio.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/mdio/of_mdio.c
++++ b/drivers/net/mdio/of_mdio.c
+@@ -18,6 +18,7 @@
+ #include <linux/of_irq.h>
+ #include <linux/of_mdio.h>
+ #include <linux/of_net.h>
++#include <linux/of_platform.h>
+ #include <linux/phy.h>
+ #include <linux/phy_fixed.h>
+@@ -180,6 +181,11 @@ int __of_mdiobus_register(struct mii_bus
+       /* Loop over the child nodes and register a phy_device for each phy */
+       for_each_available_child_of_node(np, child) {
++              if (of_device_is_compatible(child, "ethernet-phy-nexus")) {
++                      of_platform_device_create(child, NULL, &mdio->dev);
++                      continue;
++              }
++
+               addr = of_mdio_parse_addr(&mdio->dev, child);
+               if (addr < 0) {
+                       scanphys = true;
diff --git a/target/linux/octeon/patches-6.1/711-netdev-phy-Add-driver-for-Vitesse-vsc848x-single-dua.patch b/target/linux/octeon/patches-6.1/711-netdev-phy-Add-driver-for-Vitesse-vsc848x-single-dua.patch
new file mode 100644 (file)
index 0000000..2b38c7a
--- /dev/null
@@ -0,0 +1,825 @@
+From f9687bdf31bfb633a2ac615f66fd9cb5ea042a4e Mon Sep 17 00:00:00 2001
+From: David Daney <david.daney@cavium.com>
+Date: Fri, 13 Feb 2015 15:04:55 +0530
+Subject: [PATCH] netdev/phy: Add driver for Vitesse vsc848x single, dual and
+ quad 10G phys
+
+These phys implement the standard IEEE 802.3 clause 45 registers but
+require additional configuration.  Some of these registers in the multi-phy
+devices are shared among all phys such as the GPIO registers.
+
+Additionally, this PHY does not automatically access the SFP+ serial EEPROM so
+it is up to the PHY driver to parse it and change certain parameters in the
+PHY according to the type of module installed and the length of the cable, if
+copper.
+
+This module has support for the vsc8488, vsc8486 and vsc8484 Vitesse devices
+but thus far has only been tested with the vsc8488 dual PHY.
+
+netdev/phy: Clean up structure names in vsc848x.c
+Cut-and-paste snafu left some bad names, no functional change.
+
+Signed-off-by: David Daney <david.daney@cavium.com>
+Signed-off-by: Aaron Williams <aaron.williams@cavium.com>
+Signed-off-by: Leonid Rosenboim <lrosenboim@caviumnetworks.com>
+Signed-off-by: Abhishek Paliwal <abhishek.paliwal@aricent.com>
+[Rebased on kernel 5.4 by Martin Kennedy <hurricos@gmail.com>]
+Signed-off-by: Martin Kennedy <hurricos@gmail.com>
+[rebase on 5.15, use nvmem instead of of_memory_accessor]
+Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
+---
+ drivers/net/phy/Kconfig   |   7 +
+ drivers/net/phy/Makefile  |   1 +
+ drivers/net/phy/vsc848x.c | 762 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 770 insertions(+)
+ create mode 100644 drivers/net/phy/vsc848x.c
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -442,6 +442,13 @@ config VITESSE_PHY
+       help
+         Currently supports the vsc8244
++config VSC848X_PHY
++      tristate "Drivers for the Vitesse 10G PHYs"
++      depends on NVMEM
++      help
++        Driver for Vitesse vsc848x single, dual and quad 10G PHY devices.
++        Currently supports the vsc8488, vsc8486 and vsc8484 chips
++
+ config XILINX_GMII2RGMII
+       tristate "Xilinx GMII2RGMII converter driver"
+       help
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -102,4 +102,5 @@ obj-$(CONFIG_SMSC_PHY)             += smsc.o
+ obj-$(CONFIG_STE10XP)         += ste10Xp.o
+ obj-$(CONFIG_TERANETICS_PHY)  += teranetics.o
+ obj-$(CONFIG_VITESSE_PHY)     += vitesse.o
++obj-$(CONFIG_VSC848X_PHY)     += vsc848x.o
+ obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
+--- /dev/null
++++ b/drivers/net/phy/vsc848x.c
+@@ -0,0 +1,762 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2012 Cavium, Inc.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/of_mdio.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/phy.h>
++#include <linux/memory.h>
++#include <linux/mutex.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/delay.h>
++#include <linux/ctype.h>
++
++#define PMD_RX_SIGNAL_DETECT          (MII_ADDR_C45 | 0x01000a)
++#define PMA_TXOUTCTRL2                        (MII_ADDR_C45 | 0x018014)
++#define EDC_EYE_QUALITY                       (MII_ADDR_C45 | 0x018034)
++/* EDC Firmware State Machine Status and Lib Force
++ * 15: library force enable
++ * 14:8 - Library number
++ * 7:5  - N/A
++ * 4    - State force
++ * 3:0  - FW state (1=reset, 2=wait for alarm to clear, 3 = convergence,
++ *      4 = tracking, 5 = freeze)
++ */
++#define EDC_FW_SM_STATUS              (MII_ADDR_C45 | 0x018036)
++
++#define BASER_PCS_STATUS              (MII_ADDR_C45 | 0x030020)
++#define XGXS_LANE_STATUS              (MII_ADDR_C45 | 0x040018)
++#define EWIS_INTR_PEND1                       (MII_ADDR_C45 | 0x02EE00)
++#define EWIS_INTR_MASKA_1             (MII_ADDR_C45 | 0x02EE01)
++#define EWIS_INTR_MASKB_1             (MII_ADDR_C45 | 0x02EE02)
++#define EWIS_INTR_STAT2                       (MII_ADDR_C45 | 0x02EE03)
++#define EWIS_INTR_PEND2                       (MII_ADDR_C45 | 0x02EE04)
++#define EWIS_INTR_MASKA_2             (MII_ADDR_C45 | 0x02EE05)
++#define EWIS_INTR_MASKB_2             (MII_ADDR_C45 | 0x02EE06)
++#define EWIS_FAULT_MASK                       (MII_ADDR_C45 | 0x02EE07)
++#define EWIS_INTR_PEND3                       (MII_ADDR_C45 | 0x02EE08)
++#define EWIS_INTR_MASKA_3             (MII_ADDR_C45 | 0x02EE09)
++#define EWIS_INTR_MASKB_3             (MII_ADDR_C45 | 0x02EE0A)
++
++/* Device ID
++ * 15:0 - device ID
++ */
++#define GBL_DEVICE_ID                 (MII_ADDR_C45 | 0x1e0000)
++/* Device revision
++ * 15:04 - reserved
++ * 03:00 - revision ID
++ */
++#define GBL_DEVICE_REVISION           (MII_ADDR_C45 | 0x1e0001)
++/* Block Level Software Reset
++ * 15:14 - reserved
++ * 13:   - software reset EDC 1 (1 = reset, autoclears)
++ * 12:   - software reset EDC 0 (1 = reset, autoclears)
++ * 11:10 - reserved
++ * 09:   - Software reset channel 1 (1 = reset, autoclears)
++ * 08:   - Software reset channel 0 (1 = reset, autoclears)
++ * 07:   - Microprocessor reset (0 = normal operation, 1 = reset)
++ * 06:   - Software reset BIU (1 = reset, autoclears)
++ * 05:   - Software reset TWS slave (1 = reset, autoclears)
++ * 04:   - Software reset TWS master (1 = reset, autoclears)
++ * 03:   - Software reset MDIO (1 = reset, autoclears)
++ * 02:   - Software reset UART (1 = reset, autoclears)
++ * 01:   - Global register reset (1 = reset, autoclears)
++ * 00:   - Software reset chip (1 = reset, autoclears)
++ */
++#define GBL_BLOCK_LVL_SW_RESET                (MII_ADDR_C45 | 0x1e0002)
++#define GBL_GPIO_0_CONFIG1_STATUS     (MII_ADDR_C45 | 0x1e0100)
++#define GBL_GPIO_0_CONFIG2            (MII_ADDR_C45 | 0x1e0101)
++#define GBL_DEVICE_ID                 (MII_ADDR_C45 | 0x1e0000)
++#define GBL_FW_CHECKSUM                       (MII_ADDR_C45 | 0x1e7fe0)
++#define GBL_FW_WATCHDOG                       (MII_ADDR_C45 | 0x1e7fe1)
++#define GBL_FW_VERSION                        (MII_ADDR_C45 | 0x1e7fe2)
++#define GBL_FW_VAR_ACC_CTRL           (MII_ADDR_C45 | 0x1e7fe3)
++#define GBL_FW_VAR_ACC_DATA           (MII_ADDR_C45 | 0x1e7fe4)
++
++/* The Vitesse VSC848X series are 10G PHYs.
++ *
++ * Some of these devices contain multiple PHYs in a single package and
++ * some features are controlled by a global set of registers shared between
++ * all of the PHY devices.  Because of this a nexus is used to handle all
++ * of the PHYs on the same device.
++ *
++ * Unlike some PHY devices, it is up to the driver to read the SFP module
++ * serial EEPROM in order to put the PHY into the right mode.  The VSC848X
++ * does not provide an I2C interface so the PHY driver relies on the
++ * external AT24 I2C EEPROM driver to read the module whenever it is inserted.
++ *
++ */
++
++/* Enable LOPC detection (see 0x5B for target state)
++ * 15:12 - channel 3
++ * 11:08 - channel 2
++ * 07:04 - channel 1
++ * 03:00 - channel 0
++ * 1 = enable (default), 0 = disable
++ */
++#define FW_VAR_ENABLE_LOPC            0x58
++/* While in tracking mode, go to this state in response to LOPC assertion
++ * 1 = reset, 2 = wait (default), 3 = converging, 4 = tracking, 5 = freeze
++ */
++#define FW_VAR_LOPC_ASSERT_MODE               0x5B
++/* While in freeze mode, enable state transition upon deassertion of LOPC (see
++ * 0x61 for target state)
++ * 1 - reset, 2 = wait, 3 = converging, 4 = tracking (default), 5 = freeze
++ */
++#define FW_VAR_FREEZE_DEASSERT_MODE   0x61
++/* Current functional mode
++ * See VITESSE_FUNC_MODE_XXX below for values
++ * NOTE: When the firmware is done servicing the mode change request, bit 4
++ * will be set to 1.
++ */
++#define FW_VAR_FUNCTIONAL_MODE                0x94
++/* Current state of graded SPSA process
++ * 3: channel 3
++ * 2: channel 2
++ * 1: channel 1
++ * 0: channel 0
++ * 1 = busy, 2 = done
++ */
++#define FW_VAR_GRADED_SPSA_STATE      0x95
++/* BerScore at start of SPSA cycle */
++#define FW_VAR_BERSCORE_START         0x96
++/* BerScore at end of SPSA cycle */
++#define FW_VAR_BERSCORE_END           0x97
++/* Enable/Disable aggressive track phase on entering tracking state
++ * 15:12 - channel 3
++ * 11:08 - channel 2
++ * 07:04 - channel 1
++ * 03:00 - channel 0
++ * 0 = disable, 1 = enable (default)
++ */
++#define FW_VAR_AGG_TRACKING           0xAF
++
++/* Modes for the PHY firmware */
++#define VITESSE_FUNC_MODE_LIMITING    2       /* Optical */
++#define VITESSE_FUNC_MODE_COPPER      3       /* Copper */
++#define VITESSE_FUNC_MODE_LINEAR      4
++#define VITESSE_FUNC_MODE_KR          5
++#define VITESSE_FUNC_MODE_ZR          7
++#define VITESSE_FUNC_MODE_1G          8
++
++
++struct vsc848x_nexus_mdiobus {
++      struct mii_bus *mii_bus;
++      struct mii_bus *parent_mii_bus;
++      int reg_offset;
++      struct mutex lock;      /* Lock used for global register sequences */
++      int phy_irq[PHY_MAX_ADDR];
++};
++
++struct vsc848x_phy_info {
++      int sfp_conn;           /* Module connected? */
++      int tx_en_gpio;         /* GPIO that enables transmit */
++      int mod_abs_gpio;       /* Module Absent GPIO line */
++      int tx_fault_gpio;      /* TX Fault GPIO line */
++      int inta_gpio, intb_gpio;       /* Interrupt GPIO line (output) */
++      uint8_t mode;           /* Mode for module */
++      uint8_t channel;        /* channel in multi-phy devices */
++      struct vsc848x_nexus_mdiobus *nexus;    /* Nexus for lock */
++};
++
++/**
++ * Maps GPIO lines to the global GPIO config registers.
++ *
++ * Please see the data sheet since the configuration for each GPIO line is
++ * different.
++ */
++static const struct {
++      uint32_t config1_status_reg;
++      uint32_t config2_reg;
++} vcs848x_gpio_to_reg[12] = {
++      { (MII_ADDR_C45 | 0x1e0100), (MII_ADDR_C45 | 0x1e0101) },       /* 0 */
++      { (MII_ADDR_C45 | 0x1e0102), (MII_ADDR_C45 | 0x1e0103) },       /* 1 */
++      { (MII_ADDR_C45 | 0x1e0104), (MII_ADDR_C45 | 0x1e0105) },       /* 2 */
++      { (MII_ADDR_C45 | 0x1e0106), (MII_ADDR_C45 | 0x1e0107) },       /* 3 */
++      { (MII_ADDR_C45 | 0x1e0108), (MII_ADDR_C45 | 0x1e0109) },       /* 4 */
++      { (MII_ADDR_C45 | 0x1e010A), (MII_ADDR_C45 | 0x1e010B) },       /* 5 */
++      { (MII_ADDR_C45 | 0x1e0124), (MII_ADDR_C45 | 0x1e0125) },       /* 6 */
++      { (MII_ADDR_C45 | 0x1e0126), (MII_ADDR_C45 | 0x1e0127) },       /* 7 */
++      { (MII_ADDR_C45 | 0x1e0128), (MII_ADDR_C45 | 0x1e0129) },       /* 8 */
++      { (MII_ADDR_C45 | 0x1e012a), (MII_ADDR_C45 | 0x1e012b) },       /* 9 */
++      { (MII_ADDR_C45 | 0x1e012c), (MII_ADDR_C45 | 0x1e012d) },       /* 10 */
++      { (MII_ADDR_C45 | 0x1e012e), (MII_ADDR_C45 | 0x1e012f) },       /* 11 */
++};
++
++static int vsc848x_probe(struct phy_device *phydev)
++{
++      struct vsc848x_phy_info *dev_info;
++      int ret;
++
++      dev_info = devm_kzalloc(&phydev->mdio.dev, sizeof(*dev_info), GFP_KERNEL);
++      if (dev_info == NULL)
++              return -ENOMEM;
++
++      phydev->priv = dev_info;
++      dev_info->mode = VITESSE_FUNC_MODE_LIMITING;    /* Default to optical */
++      phydev->priv = dev_info;
++      dev_info->nexus = phydev->mdio.bus->priv;
++
++      ret = of_property_read_u32(phydev->mdio.dev.of_node, "mod_abs",
++                                 &dev_info->mod_abs_gpio);
++      if (ret) {
++              dev_err(&phydev->mdio.dev, "%s has invalid mod_abs address\n",
++                      phydev->mdio.dev.of_node->full_name);
++              return ret;
++      }
++
++      ret = of_property_read_u32(phydev->mdio.dev.of_node, "tx_fault",
++                                 &dev_info->tx_fault_gpio);
++      if (ret) {
++              dev_err(&phydev->mdio.dev, "%s has invalid tx_fault address\n",
++                      phydev->mdio.dev.of_node->full_name);
++              return ret;
++      }
++
++      ret = of_property_read_u32(phydev->mdio.dev.of_node, "inta",
++                                 &dev_info->inta_gpio);
++      if (ret)
++              dev_info->inta_gpio = -1;
++
++      ret = of_property_read_u32(phydev->mdio.dev.of_node, "intb",
++                                 &dev_info->intb_gpio);
++      if (ret)
++              dev_info->intb_gpio = -1;
++
++      ret = of_property_read_u32(phydev->mdio.dev.of_node, "txon",
++                                 &dev_info->tx_en_gpio);
++      if (ret) {
++              dev_err(&phydev->mdio.dev, "%s has invalid txon gpio address\n",
++                      phydev->mdio.dev.of_node->full_name);
++              return -ENXIO;
++      }
++
++      ret = phy_read(phydev, GBL_DEVICE_ID);
++      if (ret < 0) {
++              dev_err(&phydev->mdio.dev, "%s error reading PHY\n",
++                      phydev->mdio.dev.of_node->full_name);
++              return ret;
++      }
++
++      /* Check how many devices are in the package to figure out the channel
++       * number.
++       */
++      switch (ret) {
++      case 0x8487:    /* Single */
++      case 0x8486:
++              dev_info->channel = 0;
++              break;
++      case 0x8488:    /* Dual */
++              dev_info->channel = phydev->mdio.addr & 1;
++              break;
++      case 0x8484:    /* Quad */
++              dev_info->channel = phydev->mdio.addr & 3;
++              break;
++      default:
++              dev_err(&phydev->mdio.dev, "%s Unknown Vitesse PHY model %04x\n",
++                      phydev->mdio.dev.of_node->full_name, ret);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static void vsc848x_remove(struct phy_device *phydev)
++{
++      struct vsc848x_phy_info *dev_info = phydev->priv;
++
++      dev_info(&phydev->mdio.dev, "%s Exiting\n", phydev->mdio.dev.of_node->full_name);
++
++      kfree(dev_info);
++}
++
++static int vsc848x_config_init(struct phy_device *phydev)
++{
++      linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
++                       phydev->advertising);
++
++      linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
++                       phydev->supported);
++
++      phydev->autoneg = 0;
++      phydev->is_c45 = 1;
++      phydev->state = PHY_READY;
++
++      return 0;
++}
++
++static int vsc848x_config_aneg(struct phy_device *phydev)
++{
++      return 0;
++}
++
++static int vsc848x_write_global_var(struct phy_device *phydev, uint8_t channel,
++                                  uint8_t addr, uint16_t value)
++{
++      struct vsc848x_phy_info *dev_info = phydev->priv;
++      int timeout = 1000;
++      int ret = 0;
++
++      mutex_lock(&(dev_info->nexus->lock));
++
++      /* Wait for firmware download to complete */
++      timeout = 100000;
++      do {
++              ret = phy_read(phydev, MII_ADDR_C45 | 0x1e7fe0);
++              if (ret < 0)
++                      goto error;
++              if (ret == 3)
++                      break;
++              udelay(100);
++      } while (timeout-- > 0);
++      if (timeout <= 0) {
++              dev_err(&phydev->mdio.dev, "%s Timeout waiting for PHY firmware to load\n",
++                      phydev->mdio.dev.of_node->full_name);
++              ret = -EIO;
++              goto error;
++      }
++
++      do {
++              ret = phy_read(phydev, (MII_ADDR_C45 | 0x1e7fe3));
++              if (ret < 0)
++                      return ret;
++              if (ret == 0)
++                      break;
++              mdelay(1);
++      } while (timeout-- > 0);
++      if (timeout <= 0) {
++              dev_err(&phydev->mdio.dev, "%s timed out waiting to write global\n",
++                      phydev->mdio.dev.of_node->full_name);
++              ret = -EIO;
++              goto error;
++      }
++      ret = phy_write(phydev, (MII_ADDR_C45 | 0x1e7fe4), value);
++      if (ret < 0)
++              goto error;
++
++      ret = phy_write(phydev, (MII_ADDR_C45 | 0x1e7fe3),
++                      0x8000 | ((channel & 3) << 8) | addr);
++      if (ret < 0)
++              goto error;
++
++      /* Wait for value to be written */
++      do {
++              ret = phy_read(phydev, (MII_ADDR_C45 | 0x1e7fe3));
++              if (ret < 0)
++                      return ret;
++              if (ret == 0)
++                      break;
++              mdelay(1);
++      } while (timeout-- > 0);
++      if (timeout <= 0) {
++              dev_err(&phydev->mdio.dev, "%s timed out waiting to write global\n",
++                      phydev->mdio.dev.of_node->full_name);
++              ret = -EIO;
++              goto error;
++      }
++      ret = 0;
++
++error:
++      mutex_unlock(&(dev_info->nexus->lock));
++
++      return ret;
++}
++
++/**
++ * Dumps out the contents of the SFP EEPROM when errors are detected
++ *
++ * @param eeprom - contents of SFP+ EEPROM
++ */
++static void dump_sfp_eeprom(const uint8_t eeprom[64])
++{
++      int addr = 0;
++      int i;
++      char line[17];
++      line[16] = '\0';
++
++      pr_info("SFP+ EEPROM contents:\n");
++      while (addr < 64) {
++              pr_info("  %02x:  ", addr);
++              for (i = 0; i < 16; i++)
++                      pr_cont("%02x ", eeprom[addr + i]);
++              for (i = 0; i < 16; i++) {
++                      if (!isprint(eeprom[addr + i]) ||
++                          eeprom[addr + i] >= 0x80)
++                              line[i] = '.';
++                      else
++                              line[i] = eeprom[addr + i];
++              }
++              pr_cont("    %s\n", line);
++              addr += 16;
++      }
++      pr_info("\n");
++}
++
++/**
++ * Read the SFP+ module EEPROM and program the Vitesse PHY accordingly.
++ *
++ * @param phydev - Phy device
++ *
++ * @returns 0 for success, error otherwise.
++ */
++static int vsc848x_read_sfp(struct phy_device *phydev)
++{
++      struct vsc848x_phy_info *dev_info = phydev->priv;
++      struct nvmem_device *nvmem;
++      uint8_t sfp_buffer[64];
++      uint8_t csum;
++      uint8_t mode = VITESSE_FUNC_MODE_LIMITING;
++      const char *mode_str = "Unknown";
++      int i;
++      int ret = 0;
++
++      nvmem = of_nvmem_device_get(phydev->mdio.dev.of_node, NULL);
++      if (IS_ERR(nvmem))
++              return PTR_ERR(nvmem);
++
++      /* For details on the SFP+ EEPROM contents see the SFF-8472
++       * Diagnostic Monitoring Interface for Optical Transceivers.
++       *
++       * This is based on revision 11.1, October 26, 2012.
++       */
++
++      ret = nvmem_device_read(nvmem, 0, 64, sfp_buffer);
++      nvmem_device_put(nvmem);
++      if (ret < 0)
++              return ret;
++
++      /* Validate SFP checksum */
++      csum = 0;
++      for (i = 0; i < 63; i++)
++              csum += sfp_buffer[i];
++      if (csum != sfp_buffer[63]) {
++              dev_err(&phydev->mdio.dev, "%s SFP EEPROM checksum bad, calculated 0x%02x, should be 0x%02x\n",
++                      phydev->mdio.dev.of_node->full_name, csum, sfp_buffer[63]);
++              dump_sfp_eeprom(sfp_buffer);
++              return -ENXIO;
++      }
++
++      /* Make sure it's a SFP or SFP+ module */
++      if (sfp_buffer[0] != 3) {
++              dev_err(&phydev->mdio.dev, "%s module is not SFP or SFP+\n",
++                      phydev->mdio.dev.of_node->full_name);
++              dump_sfp_eeprom(sfp_buffer);
++              return -ENXIO;
++      }
++
++      /* Check connector type */
++      switch (sfp_buffer[2]) {
++      case 0x01:      /* SC */
++              mode = VITESSE_FUNC_MODE_LIMITING;
++              break;
++      case 0x07:      /* LC */
++              mode = VITESSE_FUNC_MODE_LIMITING;
++              break;
++      case 0x0B:      /* Optical pigtail */
++              mode = VITESSE_FUNC_MODE_LIMITING;
++              break;
++      case 0x21:      /* Copper pigtail */
++      case 0x22:      /* RJ45 */
++              mode = VITESSE_FUNC_MODE_COPPER;
++              break;
++      default:
++              dev_err(&phydev->mdio.dev, "%s Unknown Connector Type 0x%x\n",
++                      phydev->mdio.dev.of_node->full_name, sfp_buffer[2]);
++              dump_sfp_eeprom(sfp_buffer);
++              return -EINVAL;
++      }
++
++      if (mode == VITESSE_FUNC_MODE_LIMITING) {
++              if (mode_str[3] & 0x10)
++                      mode_str = "10GBase-SR";
++              else if (mode_str[3] & 0x20)
++                      mode_str = "10GBase-LR";
++              else if (mode_str[3] & 0x40)
++                      mode_str = "10GBase-LRM";
++              else if (mode_str[3] & 0x80)
++                      mode_str = "10GBase-ER";
++              else
++                      dev_err(&phydev->mdio.dev, "%s unknown SFP compatibility\n"
++                              "type ID: 0x%02x, extended ID: 0x%02x, Connector type code: 0x%02x\n"
++                              "Transceiver compatibility code: (%02x) %02x %02x %02x %02x %02x %02x %02x %02x\n",
++                              phydev->mdio.dev.of_node->full_name, sfp_buffer[0],
++                              sfp_buffer[1], sfp_buffer[2], sfp_buffer[36],
++                              sfp_buffer[3], sfp_buffer[4], sfp_buffer[5],
++                              sfp_buffer[6], sfp_buffer[7], sfp_buffer[8],
++                              sfp_buffer[9], sfp_buffer[10]);
++      } else if (mode == VITESSE_FUNC_MODE_COPPER) {
++              if (sfp_buffer[8] & 0x4) {
++                      mode_str = "10G Passive Copper";
++              } else if (sfp_buffer[8] & 0x8) {
++                      mode_str = "10G Active Copper";
++                      mode = VITESSE_FUNC_MODE_LIMITING;
++              } else {
++                      dev_err(&phydev->mdio.dev, "%s Unknown SFP+ copper cable capability 0x%02x\n"
++                              "Transceiver compatibility code: (%02x) %02x %02x %02x %02x %02x %02x %02x %02x\n",
++                              phydev->mdio.dev.of_node->full_name, sfp_buffer[8],
++                              sfp_buffer[36], sfp_buffer[3], sfp_buffer[4],
++                              sfp_buffer[5], sfp_buffer[6], sfp_buffer[7],
++                              sfp_buffer[8], sfp_buffer[9], sfp_buffer[10]);
++                      return -EINVAL;
++              }
++      } else {
++              dev_err(&phydev->mdio.dev, "%s Unsupported phy mode %d\n",
++                      phydev->mdio.dev.of_node->full_name, mode);
++              dump_sfp_eeprom(sfp_buffer);
++      }
++
++      vsc848x_write_global_var(phydev, dev_info->channel, 0x94, mode);
++
++      /* Adjust PMA_TXOUTCTRL2 based on cable length.  Vitesse recommends
++       * 0x1606 for copper cable lengths 5M and longer.
++       *
++       * The default value is 0x1300.
++       */
++      if (mode == VITESSE_FUNC_MODE_COPPER) {
++              if (sfp_buffer[18] >= 5)
++                      ret = phy_write(phydev, PMA_TXOUTCTRL2, 0x1606);
++              else
++                      ret = phy_write(phydev, PMA_TXOUTCTRL2, 0x1300);
++              if (ret)
++                      return ret;
++      }
++
++      /* Reset the state machine */
++      ret = phy_write(phydev, MII_ADDR_C45 | 0x18034, 0x11);
++
++      dev_info(&phydev->mdio.dev, "%s configured for %s\n",
++              phydev->mdio.dev.of_node->full_name, mode_str);
++
++      return ret;
++}
++
++static int vsc848x_read_status(struct phy_device *phydev)
++{
++      struct vsc848x_phy_info *dev_info = phydev->priv;
++      int rx_signal_detect;
++      int pcs_status;
++      int xgxs_lane_status;
++      int value;
++      int sfp_conn;
++      int ret;
++
++      /* Check if a module is plugged in */
++      value = phy_read(phydev, vcs848x_gpio_to_reg[dev_info->mod_abs_gpio]
++                                                      .config1_status_reg);
++      if (value < 0)
++              return value;
++
++      sfp_conn = !(value & 0x400);
++      if (sfp_conn != dev_info->sfp_conn) {
++              /* We detect a module being plugged in */
++              if (sfp_conn) {
++                      ret = vsc848x_read_sfp(phydev);
++                      if (ret < 0)
++                              goto no_link;
++                      dev_info->sfp_conn = sfp_conn;
++              } else {
++                      dev_info(&phydev->mdio.dev, "%s module unplugged\n",
++                               phydev->mdio.dev.of_node->full_name);
++                      dev_info->sfp_conn = sfp_conn;
++                      goto no_link;
++              }
++      }
++
++      rx_signal_detect = phy_read(phydev, PMD_RX_SIGNAL_DETECT);
++      if (rx_signal_detect < 0)
++              return rx_signal_detect;
++
++      if ((rx_signal_detect & 1) == 0)
++              goto no_link;
++
++      pcs_status = phy_read(phydev, BASER_PCS_STATUS);
++      if (pcs_status < 0)
++              return pcs_status;
++
++      if ((pcs_status & 1) == 0)
++              goto no_link;
++
++      xgxs_lane_status = phy_read(phydev, XGXS_LANE_STATUS);
++      if (xgxs_lane_status < 0)
++              return xgxs_lane_status;
++
++      if ((xgxs_lane_status & 0x1000) == 0)
++              goto no_link;
++
++      phydev->speed = 10000;
++      phydev->link = 1;
++      phydev->duplex = 1;
++      return 0;
++no_link:
++      phydev->link = 0;
++      return 0;
++}
++
++static struct of_device_id vsc848x_match[] = {
++      {
++              .compatible = "vitesse,vsc8488",
++      },
++      {
++              .compatible = "vitesse,vsc8486",
++      },
++      {
++              .compatible = "vitesse,vsc8484",
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, vsc848x_match);
++
++static struct phy_driver vsc848x_phy_driver = {
++      .phy_id         = 0x00070400,
++      .phy_id_mask    = 0xfffffff0,
++      .name           = "Vitesse VSC848X",
++      .config_init    = vsc848x_config_init,
++      .probe          = vsc848x_probe,
++      .remove         = vsc848x_remove,
++      .config_aneg    = vsc848x_config_aneg,
++      .read_status    = vsc848x_read_status,
++/*
++      .driver         = {
++              .owner = THIS_MODULE,
++              .of_match_table = vsc848x_match,
++      },
++*/
++};
++
++/* Phy nexus support below. */
++
++static int vsc848x_nexus_read(struct mii_bus *bus, int phy_id, int regnum)
++{
++      struct vsc848x_nexus_mdiobus *p = bus->priv;
++      return p->parent_mii_bus->read(p->parent_mii_bus,
++                                     phy_id + p->reg_offset,
++                                     regnum);
++}
++
++static int vsc848x_nexus_write(struct mii_bus *bus, int phy_id,
++                             int regnum, u16 val)
++{
++      struct vsc848x_nexus_mdiobus *p = bus->priv;
++      return p->parent_mii_bus->write(p->parent_mii_bus,
++                                      phy_id + p->reg_offset,
++                                      regnum, val);
++}
++
++static int vsc848x_nexus_probe(struct platform_device *pdev)
++{
++      struct vsc848x_nexus_mdiobus *bus;
++      const char *bus_id;
++      int len;
++      int err = 0;
++
++      bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
++      if (!bus)
++              return -ENOMEM;
++
++      bus->parent_mii_bus = container_of(pdev->dev.parent,
++                                         struct mii_bus, dev);
++
++      /* The PHY nexux  must have a reg property in the range [0-31] */
++      err = of_property_read_u32(pdev->dev.of_node, "reg", &bus->reg_offset);
++      if (err) {
++              dev_err(&pdev->dev, "%s has invalid PHY address\n",
++                      pdev->dev.of_node->full_name);
++              return err;
++      }
++
++      bus->mii_bus = mdiobus_alloc();
++      if (!bus->mii_bus)
++              return -ENOMEM;
++
++      bus->mii_bus->priv = bus;
++#if 0
++      bus->mii_bus->irq = bus->phy_irq;
++#endif
++      bus->mii_bus->name = "vsc848x_nexus";
++      bus_id = bus->parent_mii_bus->id;
++      len = strlen(bus_id);
++      if (len > MII_BUS_ID_SIZE - 4)
++              bus_id += len - (MII_BUS_ID_SIZE - 4);
++      snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s:%02x",
++               bus_id, bus->reg_offset);
++      bus->mii_bus->parent = &pdev->dev;
++
++      bus->mii_bus->read = vsc848x_nexus_read;
++      bus->mii_bus->write = vsc848x_nexus_write;
++      mutex_init(&bus->lock);
++
++      dev_set_drvdata(&pdev->dev, bus);
++
++      err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node);
++      if (err) {
++              dev_err(&pdev->dev, "Error registering with device tree\n");
++              goto fail_register;
++      }
++
++      return 0;
++
++fail_register:
++      dev_err(&pdev->dev, "Failed to register\n");
++      mdiobus_free(bus->mii_bus);
++      return err;
++}
++
++static int vsc848x_nexus_remove(struct platform_device *pdev)
++{
++      return 0;
++}
++
++static struct of_device_id vsc848x_nexus_match[] = {
++      {
++              .compatible = "vitesse,vsc8488-nexus",
++      },
++      {
++              .compatible = "vitesse,vsc8486-nexus",
++      },
++      {
++              .compatible = "vitesse,vsc8484-nexus",
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, vsc848x_nexus_match);
++
++static struct platform_driver vsc848x_nexus_driver = {
++      .driver = {
++              .name           = "vsc848x-nexus",
++              .owner          = THIS_MODULE,
++              .of_match_table = vsc848x_nexus_match,
++      },
++      .probe          = vsc848x_nexus_probe,
++      .remove         = vsc848x_nexus_remove,
++};
++
++static int __init vsc848x_mod_init(void)
++{
++      int rv;
++
++      rv = platform_driver_register(&vsc848x_nexus_driver);
++      if (rv)
++              return rv;
++
++      rv = phy_driver_register(&vsc848x_phy_driver, THIS_MODULE);
++
++      return rv;
++}
++module_init(vsc848x_mod_init);
++
++static void __exit vsc848x_mod_exit(void)
++{
++      phy_driver_unregister(&vsc848x_phy_driver);
++      platform_driver_unregister(&vsc848x_nexus_driver);
++}
++module_exit(vsc848x_mod_exit);
++
++MODULE_DESCRIPTION("Driver for Vitesse VSC848X PHY");
++MODULE_AUTHOR("David Daney and Aaron Williams");
++MODULE_LICENSE("GPL");