octeon: add support for snic10e
authorMartin Kennedy <hurricos@gmail.com>
Wed, 10 Feb 2021 03:40:27 +0000 (03:40 +0000)
committerStijn Tintel <stijn@linux-ipv6.be>
Thu, 9 Nov 2023 12:35:01 +0000 (14:35 +0200)
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
target/linux/octeon/base-files/etc/board.d/01_network
target/linux/octeon/base-files/lib/preinit/01_sysinfo
target/linux/octeon/files/arch/mips/boot/dts/cavium-octeon/snic10e.dts [new file with mode: 0644]
target/linux/octeon/image/Makefile
target/linux/octeon/patches-5.10/141-octeon_snic10e_support.patch [new file with mode: 0644]
target/linux/octeon/patches-5.10/300-MIPS-Octeon-fix-CN6640-hang-on-XAUI-init.patch [new file with mode: 0644]
target/linux/octeon/patches-5.10/301-MIPS-Octeon-support-all-interfaces-on-CN66XX.patch [new file with mode: 0644]
target/linux/octeon/patches-5.10/710-netdev-phy-of-Handle-nexus-Ethernet-PHY-devices.patch [new file with mode: 0644]
target/linux/octeon/patches-5.10/711-netdev-phy-Add-driver-for-Vitesse-vsc848x-single-dua.patch [new file with mode: 0644]
target/linux/octeon/patches-5.10/800-nvmem-core-add-of_nvmem_device_get_by_phandle.patch [new file with mode: 0644]

index 2443c90d60a6e3dc5f941ab3760265c8e3eb1379..92ed34250fe1a45cb8ad4fa61a9afb21c75129fb 100644 (file)
@@ -11,6 +11,9 @@ itus,shield-router|\
 ubnt,usg)
        ucidef_set_interfaces_lan_wan "eth1 eth2" "eth0"
        ;;
+snic10e)
+       ucidef_set_interfaces_lan_wan "xaui0" "xaui1"
+       ;;
 ubnt,edgerouter-4)
        ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "lan0"
        ;;
index 923e3824c71e990de8cc28472004801df353c36c..f4be99bac35d14d2fcfb8fc0d26fef51d159e781 100644 (file)
@@ -32,6 +32,10 @@ do_sysinfo_octeon() {
                return 0
                ;;
 
+       "SNIC10E"*)
+               name="snic10e"
+               ;;
+
        "ITUS_SHIELD"*)
                name="itus,shield-router"
                ;;
diff --git a/target/linux/octeon/files/arch/mips/boot/dts/cavium-octeon/snic10e.dts b/target/linux/octeon/files/arch/mips/boot/dts/cavium-octeon/snic10e.dts
new file mode 100644 (file)
index 0000000..08f7f6e
--- /dev/null
@@ -0,0 +1,841 @@
+/dts-v1/;
+/*
+ * Cavium Inc. (Small) NIC10e board
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "cavium,snic10e";
+       compatible = "cavium,snic10e";
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&ciu>;
+
+       soc@0 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges; /* Direct mapping */
+
+               ciu: interrupt-controller@1070000000000 {
+                       compatible = "cavium,octeon-3860-ciu";
+                       interrupt-controller;
+                       /* Interrupts are specified by two parts:
+                        * 1) Controller register (0 or 1)
+                        * 2) Bit within the register (0..63)
+                        */
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x10700 0x00000000 0x0 0x7000>;
+               };
+
+               gpio: gpio-controller@1070000000800 {
+                       #gpio-cells = <2>;
+                       compatible = "cavium,octeon-3860-gpio";
+                       reg = <0x10700 0x00000800 0x0 0x100>;
+                       gpio-controller;
+                       /* Interrupts are specified by two parts:
+                        * 1) GPIO pin number (0..15)
+                        * 2) Triggering (1 - edge rising
+                        *                2 - edge falling
+                        *                4 - level active high
+                        *                8 - level active low)
+                        */
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       /* The GPIO pins connect to 16 consecutive CUI bits */
+                       interrupts = <0 16>; /* <0 17> <0 18> <0 19>
+                                    <0 20> <0 21> <0 22> <0 23>
+                                    <0 24> <0 25> <0 26> <0 27>
+                                    <0 28> <0 29> <0 30> <0 31>; */
+               };
+
+               twsi0: i2c@1180000001000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "cavium,octeon-3860-twsi";
+                       reg = <0x11800 0x00001000 0x0 0x200>;
+                       interrupts = <0 45>;
+                       /* NOTE: In order to get the proper delay between
+                        * i2c bus transactions for the SFP we need to either
+                        * slow the bus down to no more than 30KHz or else
+                        * somehow insert a delay between transactions.  Only
+                        * U-Boot is capable of inserting the appropriate delay
+                        * at this time.
+                        */
+                       clock-frequency = <30000>;
+
+                       tmp@4c {
+                               compatible = "ti,tmp421";
+                               reg = <0x4c>;
+                       };
+                       sfp0: eeprom@50 {
+                               compatible = "atmel,24c01";
+                               reg = <0x50>;
+                       };
+                       tlv-eeprom@53 {
+                               compatible = "atmel,24c256";
+                               reg = <0x53>;
+                               pagesize = <64>;
+                       };
+               };
+
+               twsi1: i2c@1180000001200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "cavium,octeon-3860-twsi";
+                       reg = <0x11800 0x00001200 0x0 0x200>;
+                       interrupts = <0 59>;
+                       /* NOTE: In order to get the proper delay between
+                        * i2c bus transactions for the SFP we need to either
+                        * slow the bus down to no more than 30KHz or else
+                        * somehow insert a delay between transactions.  Only
+                        * U-Boot is capable of inserting the appropriate delay
+                        * at this time.
+                        */
+                       clock-frequency = <30000>;
+
+                       sfp1: eeprom@50 {
+                               compatible = "atmel,24c01";
+                               reg = <0x50>;
+                       };
+                       gpio1: gpio@20 {
+                               reg = <0x20>;
+                               compatible = "nxp,pca9554";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-parent = <&gpio>;
+                               interrupt = <13 2>; /* OCTEON GPIO 13, falling edge */
+                               #interrupt-cells = <1>;
+                       };
+
+               };
+
+               smi0: mdio@1180000001800 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00001800 0x0 0x40>;
+
+                       mphyA: ethernet-phy-nexus@A {
+                               reg = <0>;
+                               /* The Vitesse VSC8488 is a dual-PHY where
+                                * some of the configuration is common across
+                                * both of the phy devices such as the reset
+                                * line and the base MDIO address.
+                                */
+                               compatible = "vitesse,vsc8488-nexus", "ethernet-phy-nexus";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               ranges;
+
+                               /* Hardware reset signal */
+                               reset = <&gpio 17 GPIO_ACTIVE_HIGH>;
+
+                               phy0: ethernet-phy@0 {
+                                       /* Absolute address */
+                                       reg = <0>;
+                                       compatible = "vitesse,vsc8488", "ethernet-phy-ieee802.3-c45";
+                                       interrupt-parent = <&gpio>;
+                                       interrupts = <13 8>;
+
+                                       mod_abs = <0>;
+                                       /* TX Fault GPIO line */
+                                       tx_fault = <1>;
+                                       /* GPIO that enables output */
+                                       txon = <4>;
+                                       /* INT A GPIO output */
+                                       inta = <5>;
+
+                                       /* Optional equalization value to
+                                        * program into the PHY XS XAUI Rx
+                                        * Equalization control register.
+                                        * It is broken up into one nibble for
+                                        * each lane with lane 0 using bits
+                                        * 12 - 15.
+                                        * Use the following table:
+                                        *      0x0 - 0dB
+                                        *      0x1 - 1.41dB
+                                        *      0x2 - 2.24dB
+                                        *      0x3 - 2.83dB
+                                        *      0x5 - 4.48dB
+                                        *      0x6 - 5.39dB
+                                        *      0x7 - 6.07dB
+                                        *      0x9 - 6.18dB
+                                        *      0xA - 7.08dB (default)
+                                        *      0xB - 7.79dB
+                                        *      0xD - 9.96dB
+                                        *      0xE - 10.84dB
+                                        *      0xF - 11.55dB
+                                        *
+                                        * This is board specific and should
+                                        * only be defined by the hardware
+                                        * vendor.
+                                        */
+                                       vitesse,rx_equalization = <0x0000>;
+                                       /* Optional transmit pre-emphasis
+                                        * control.  This sets the
+                                        * PHY XS XAUI TX pre-emphasis control
+                                        * register.
+                                        *
+                                        * It uses bits 13-14 for lane 0,
+                                        * 10-11 for lane 1, 7-8 for lane 2
+                                        * and 4-5 for lane 3.
+                                        *
+                                        * Bits 2-3 are the LOS threshold
+                                        * setting and bit 1 enables
+                                        * the XAUI output high swing mode.
+                                        *
+                                        * Use the following table for
+                                        * pre-emphasis:
+                                        * 0b00 - 0dB
+                                        * 0b01 - 2.5dB
+                                        * 0b10 - 6dB (default)
+                                        * 0b11 - 12dB
+                                        *
+                                        * Use the following table for the LOS
+                                        * threshold setting:
+                                        *
+                                        * 0b00 - 50mV - 175mV (default)
+                                        * 0b01 - 60mV - 185mV
+                                        * 0b10 - 70mV - 195mV
+                                        * 0b11 - 80mV - 205mV
+                                        */
+                                       vitesse,tx_preemphasis = <0x0000>;
+
+                                       /* TX output driver slew rate control
+                                        * is bits 8-11 where 0x0 is the minimum
+                                        * and 0xF is the maximum.
+                                        * Default is 0xA.
+                                        *
+                                        * The TX output driver C(-1)
+                                        * coefficient is bits 0-4 where
+                                        * 0b00000 is the minimum (-4ma) and
+                                        * 0b11111 is the maximum (4ma).  The
+                                        * default 0x 0b01111.
+                                        */
+                                       vitesse,txout_driver_ctrl1 = <0x0A0F>;
+
+                                       /* The TX output driver C(0) coefficient
+                                        * is bits 8-12 with 0b00000 being the
+                                        * minimum (0mA) and 0b11111 being
+                                        * the maximum (16mA). The default is
+                                        * 0b10011
+                                        *
+                                        * The C(+1) coefficient is bits 0-5
+                                        * with 0b000000 being the minimum
+                                        * (-0.25mA) and 0b111111 being the
+                                        * maximum (-16mA).  The default is
+                                        * 0b000000.
+                                        */
+                                       /*vitesse,txout_driver_ctrl2 = <0x1300>;*/
+
+                                       /* DC_AGC_LOS_CONFIG1:
+                                        *   15: Suppress_Coarse_Adj_on_LOS_Clear
+                                        *      0: DC offset correction performed using coarse
+                                        *         resolution mode (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         mode when correction resumes after LOPC/LOS alarms
+                                        *         clear.  This guarantees there will be no big jumps in
+                                        *         the offset at the expense of taking longer to reach
+                                        *         optimal setting.
+                                        *   14: Force_DC2_Fine_Adj:
+                                        *      Forces the DC offset correction to operate in fine
+                                        *      resolution adjustment mode at times when the algorithm.
+                                        *      0: DC offset correction makes coarse adjustments when
+                                        *         correction mode is first enabled (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         at all times.  This is slower.
+                                        *   13: Force_DC1_Fine_Adj:
+                                        *      Forces the DC offset correction to operate in fine
+                                        *      resolution adjustment mode at times when the algorithm.
+                                        *      0: DC offset correction makes coarse adjustments when
+                                        *         correction mode is first enabled (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         at all times.  This is slower.
+                                        *   12: Force_DC0_Fine_Adj:
+                                        *      Forces the DC offset correction to operate in fine
+                                        *      resolution adjustment mode at times when the algorithm.
+                                        *      0: DC offset correction makes coarse adjustments when
+                                        *         correction mode is first enabled (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         at all times.  This is slower.
+                                        *   10: Skip_DC2_Adj, 1 = skip DC2 offset correction
+                                        *   9:  Skip_DC1_Adj, 1 = skip DC1 offset correction
+                                        *   8:  Skip_DC0_Adj, 1 = skip DC0 offset correction
+                                        *
+                                        *   6-4: DC_Offset_Alarm_Mode (default 1)
+                                        *      Selects the alarm condition that will halt the DC offset
+                                        *      correction logic when the alarm(s) are set.
+                                        *      111: reserved
+                                        *      110: reserved
+                                        *      101: LOPC and software LOS detection
+                                        *      100: LOPC and hardware LOS detection
+                                        *      011: Software LOS detection
+                                        *      010: Hardware LOS detection
+                                        *      001: LOPC
+                                        *      000: Never.  DC offset correction will continue to make
+                                        *           fine resolution adjustments to the offsets even
+                                        *           when LOPC and LOS alarms are present.
+                                        *
+                                        *  3: AGC_Enable
+                                        *      Selects when hardware AGC adjustment logic and LOS
+                                        *      detection logic is enabled (default 1)
+                                        *      0: disabled
+                                        *      1: enabled
+                                        *  2: AGC_Suspend
+                                        *      Suspends the LOS detection logic and AGC logic
+                                        *      from making adjustments to the gain.  Bit valid only
+                                        *      if AGC_Enable=1
+                                        *      0: AGC adjustment enabled (default)
+                                        *      1: AGC adjustment suspended
+                                        *  1: DC_Offset_Adj_Enable
+                                        *      Select when the hardware DC offset correction logic is
+                                        *      enabled.
+                                        *      0: disable
+                                        *      1: enable (default)
+                                        *  0: DC_Offset_Adj_Suspend
+                                        *      Suspends the DC offset correction logic from making
+                                        *      adjustments to all offset settings.  Bit valid only if
+                                        *      DC_Offset_Adj_Enable=1
+                                        *      0: DC offset correction enabled (default)
+                                        *      1: DC offset correction suspended
+                                        *
+                                        * This setting is only applied for
+                                        * passive copper.
+                                        */
+                                       vitesse,copper_dc_agc_los_config1 = <0x000A>;
+
+                                       /* Disable aggressive track phase during
+                                        * firmware convergence if 0, enabled
+                                        * otherwise (default).
+                                        *
+                                        * This setting is only applied for
+                                        * passive copper.
+                                        */
+                                       vitesse,copper_agg_track_phase = <0>;
+
+                                       /* AGC_Config4
+                                        *
+                                        * 13-8: Ampl_Tolerance
+                                        *      This defines the hysterisis
+                                        *      built in to the AGC adjustment
+                                        *      circuit.  The VGA gain will not
+                                        *      be adjusted as long as the
+                                        *      measured input amplitude is
+                                        *      Inp_Ampl_Target +/- Amnpl_Tolerance.
+                                        *       Default is 4.
+                                        * 7-0: Inp_Ampl_Target
+                                        *      This is the target amplitude
+                                        *      desired to be measured at the
+                                        *      peak detector when measuring
+                                        *      input amplitude.  The VGA gain
+                                        *      is adjusted to achieve this
+                                        *      target setting.
+                                        *      Default is 0x6E.
+                                        *
+                                        * This setting is only applied for
+                                        * passive copper.
+                                        */
+                                       vitesse,copper_agc_config4 = <0x0496>;
+
+                                       /* The Vitesse 10G PHY does not
+                                        * automatically read the SFP EEPROM
+                                        * so the host needs to do it to put
+                                        * the PHY in the proper mode for
+                                        * copper or optical.
+                                        */
+                                       sfp-eeprom = <&sfp0>;
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       /* Absolute address */
+                                       reg = <0x1>;
+                                       compatible = "vitesse,vsc8488", "ethernet-phy-ieee802.3-c45";
+                                       interrupt-parent = <&gpio>;
+                                       interrupts = <13 8>;
+
+                                       mod_abs = <9>;
+                                       /* TX Fault GPIO line */
+                                       tx_fault = <8>;
+                                       /* GPIO that enables output */
+                                       txon = <10>;
+                                       /* INT A GPIO output */
+                                       inta = <5>;
+
+                                       /* Optional equalization value to
+                                        * program into the PHY XS XAUI Rx
+                                        * Equalization control register.
+                                        * It is broken up into one nibble for
+                                        * each lane with lane 0 using bits
+                                        * 12 - 15.
+                                        * Use the following table:
+                                        *      0x0 - 0dB
+                                        *      0x1 - 1.41dB
+                                        *      0x2 - 2.24dB
+                                        *      0x3 - 2.83dB
+                                        *      0x5 - 4.48dB
+                                        *      0x6 - 5.39dB
+                                        *      0x7 - 6.07dB
+                                        *      0x9 - 6.18dB
+                                        *      0xA - 7.08dB (default)
+                                        *      0xB - 7.79dB
+                                        *      0xD - 9.96dB
+                                        *      0xE - 10.84dB
+                                        *      0xF - 11.55dB
+                                        *
+                                        * This is board specific and should
+                                        * only be defined by the hardware
+                                        * vendor.
+                                        */
+                                       rx_equalization = <0x0000>;
+                                       /* Optional transmit pre-emphasis
+                                        * control.  This sets the
+                                        * PHY XS XAUI TX pre-emphasis control
+                                        * register.
+                                        *
+                                        * It uses bits 13-14 for lane 0,
+                                        * 10-11 for lane 1, 7-8 for lane 2
+                                        * and 4-5 for lane 3.
+                                        *
+                                        * Bits 2-3 are the LOS threshold
+                                        * setting and bit 1 enables
+                                        * the XAUI output high swing mode.
+                                        *
+                                        * Use the following table for
+                                        * pre-emphasis:
+                                        * 0b00 - 0dB
+                                        * 0b01 - 2.5dB
+                                        * 0b10 - 6dB (default)
+                                        * 0b11 - 12dB
+                                        *
+                                        * Use the following table for the LOS
+                                        * threshold setting:
+                                        *
+                                        * 0b00 - 50mV - 175mV (default)
+                                        * 0b01 - 60mV - 185mV
+                                        * 0b10 - 70mV - 195mV
+                                        * 0b11 - 80mV - 205mV
+                                        */
+                                       tx_preemphasis = <0x0000>;
+
+                                       /* TX output driver slew rate control
+                                        * is bits 8-11 where 0x0 is the minimum
+                                        * and 0xF is the maximum.
+                                        * Default is 0xA.
+                                        *
+                                        * The TX output driver C(-1)
+                                        * coefficient is bits 0-4 where
+                                        * 0b00000 is the minimum (-4ma) and
+                                        * 0b11111 is the maximum (4ma).  The
+                                        * default 0x 0b01111.
+                                        */
+                                       txout_driver_ctrl1 = <0x0A0F>;
+
+                                       /* The TX output driver C(0) coefficient
+                                        * is bits 8-12 with 0b00000 being the
+                                        * minimum (0mA) and 0b11111 being
+                                        * the maximum (16mA). The default is
+                                        * 0b10011
+                                        *
+                                        * The C(+1) coefficient is bits 0-5
+                                        * with 0b000000 being the minimum
+                                        * (-0.25mA) and 0b111111 being the
+                                        * maximum (-16mA).  The default is
+                                        * 0b000000.
+                                        */
+                                       /*txout_driver_ctrl2 = <0x1300>;*/
+
+                                       /* DC_AGC_LOS_CONFIG1:
+                                        *   15: Suppress_Coarse_Adj_on_LOS_Clear
+                                        *      0: DC offset correction performed using coarse
+                                        *         resolution mode (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         mode when correction resumes after LOPC/LOS alarms
+                                        *         clear.  This guarantees there will be no big jumps in
+                                        *         the offset at the expense of taking longer to reach
+                                        *         optimal setting.
+                                        *   14: Force_DC2_Fine_Adj:
+                                        *      Forces the DC offset correction to operate in fine
+                                        *      resolution adjustment mode at times when the algorithm.
+                                        *      0: DC offset correction makes coarse adjustments when
+                                        *         correction mode is first enabled (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         at all times.  This is slower.
+                                        *   13: Force_DC1_Fine_Adj:
+                                        *      Forces the DC offset correction to operate in fine
+                                        *      resolution adjustment mode at times when the algorithm.
+                                        *      0: DC offset correction makes coarse adjustments when
+                                        *         correction mode is first enabled (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         at all times.  This is slower.
+                                        *   12: Force_DC0_Fine_Adj:
+                                        *      Forces the DC offset correction to operate in fine
+                                        *      resolution adjustment mode at times when the algorithm.
+                                        *      0: DC offset correction makes coarse adjustments when
+                                        *         correction mode is first enabled (default)
+                                        *      1: DC offset correction performed using fine resolution
+                                        *         at all times.  This is slower.
+                                        *   10: Skip_DC2_Adj, 1 = skip DC2 offset correction
+                                        *   9:  Skip_DC1_Adj, 1 = skip DC1 offset correction
+                                        *   8:  Skip_DC0_Adj, 1 = skip DC0 offset correction
+                                        *
+                                        *   6-4: DC_Offset_Alarm_Mode (default 1)
+                                        *      Selects the alarm condition that will halt the DC offset
+                                        *      correction logic when the alarm(s) are set.
+                                        *      111: reserved
+                                        *      110: reserved
+                                        *      101: LOPC and software LOS detection
+                                        *      100: LOPC and hardware LOS detection
+                                        *      011: Software LOS detection
+                                        *      010: Hardware LOS detection
+                                        *      001: LOPC
+                                        *      000: Never.  DC offset correction will continue to make
+                                        *           fine resolution adjustments to the offsets even
+                                        *           when LOPC and LOS alarms are present.
+                                        *
+                                        *  3: AGC_Enable
+                                        *      Selects when hardware AGC adjustment logic and LOS
+                                        *      detection logic is enabled (default 1)
+                                        *      0: disabled
+                                        *      1: enabled
+                                        *  2: AGC_Suspend
+                                        *      Suspends the LOS detection logic and AGC logic
+                                        *      from making adjustments to the gain.  Bit valid only
+                                        *      if AGC_Enable=1
+                                        *      0: AGC adjustment enabled (default)
+                                        *      1: AGC adjustment suspended
+                                        *  1: DC_Offset_Adj_Enable
+                                        *      Select when the hardware DC offset correction logic is
+                                        *      enabled.
+                                        *      0: disable
+                                        *      1: enable (default)
+                                        *  0: DC_Offset_Adj_Suspend
+                                        *      Suspends the DC offset correction logic from making
+                                        *      adjustments to all offset settings.  Bit valid only if
+                                        *      DC_Offset_Adj_Enable=1
+                                        *      0: DC offset correction enabled (default)
+                                        *      1: DC offset correction suspended
+                                        *
+                                        * This setting is only applied for
+                                        * passive copper.
+                                        */
+                                       vitesse,copper_dc_agc_los_config1 = <0x000A>;
+
+                                       /* Disable aggressive track phase during
+                                        * firmware convergence if 0, enabled
+                                        * otherwise (default).
+                                        *
+                                        * This setting is only applied for
+                                        * passive copper.
+                                        */
+                                       vitesse,copper_agg_track_phase = <0>;
+
+                                       /* AGC_Config4
+                                        *
+                                        * 13-8: Ampl_Tolerance
+                                        *      This defines the hysterisis
+                                        *      built in to the AGC adjustment
+                                        *      circuit.  The VGA gain will not
+                                        *      be adjusted as long as the
+                                        *      measured input amplitude is
+                                        *      Inp_Ampl_Target +/- Amnpl_Tolerance.
+                                        *       Default is 4.
+                                        * 7-0: Inp_Ampl_Target
+                                        *      This is the target amplitude
+                                        *      desired to be measured at the
+                                        *      peak detector when measuring
+                                        *      input amplitude.  The VGA gain
+                                        *      is adjusted to achieve this
+                                        *      target setting.
+                                        *      Default is 0x6E.
+                                        *
+                                        * This setting is only applied for
+                                        * passive copper.
+                                        */
+                                       vitesse,copper_agc_config4 = <0x0496>;
+
+                                       /* The Vitesse 10G PHY does not
+                                        * automatically read the SFP EEPROM
+                                        * so the host needs to do it to put
+                                        * the PHY in the proper mode for
+                                        * copper or optical.
+                                        */
+                                       sfp-eeprom = <&sfp1>;
+                               };
+                       };
+                       mphyB: ethernet-phy-nexus@B {
+                               reg = <0>;
+                               /* The TI TLK10232 is a dual-PHY where
+                                * some of the configuration is common across
+                                * both of the phy devices such as the reset
+                                * line and the base MDIO address.
+                                */
+                               compatible = "ti,tlk10232-nexus", "ethernet-phy-nexus";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               ranges;
+
+                               /* Hardware reset signal open-drain active low on GPIO 17, must not be driven high. */
+                               reset = <&gpio 17 GPIO_LINE_OPEN_DRAIN>;
+
+                               phy11: ethernet-phy@0 {
+                                       /* Absolute address */
+                                       reg = <0>;
+                                       compatible = "ti,tlk10232", "ethernet-phy-ieee802.3-c45";
+
+                                       /* The TI 10G PHY does not
+                                        * automatically read the SFP EEPROM
+                                        * so the host needs to do it to put
+                                        * the PHY in the proper mode for
+                                        * copper or optical.
+                                        */
+                                       sfp-eeprom = <&sfp0>;
+
+                                       /* TX fault input signal for PHY from SFP+ */
+                                       tx-fault        = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+                                       /* TX disable for PHY to SFP+ */
+                                       tx-disable      = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+                                       /* MOD ABS signal for PHY from SFP+ */
+                                       mod-abs         = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+                                       /* RX los of singal for PHY from SFP+ */
+                                       rx-los          = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+                               };
+
+                               phy10: ethernet-phy@1 {
+                                       /* Absolute address */
+                                       reg = <0x1>;
+                                       compatible = "ti,tlk10232", "ethernet-phy-ieee802.3-c45";
+
+                                       /* The TI 10G PHY does not
+                                        * automatically read the SFP EEPROM
+                                        * so the host needs to do it to put
+                                        * the PHY in the proper mode for
+                                        * copper or optical.
+                                        */
+                                       sfp-eeprom = <&sfp1>;
+                                       /* TX fault input signal for PHY */
+                                       tx-fault        = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+                                       /* TX disable for PHY */
+                                       tx-disable      = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+                                       /* MOD ABS signal for PHY */
+                                       mod-abs         = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+                                       /* RX los of singal for PHY */
+                                       rx-los          = <&gpio1 3 GPIO_ACTIVE_HIGH>;
+                               };
+                       };
+               };
+
+               pip: pip@11800a0000000 {
+                       compatible = "cavium,octeon-3860-pip";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+                       interface@A {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy0>;
+                               };
+                       };
+                       interface@B {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <1>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy1>;
+                               };
+                       };
+                       interface@C {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy10>;
+                               };
+                       };
+                       interface@D {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <1>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy11>;
+                               };
+                       };
+               };
+
+               uart0: serial@1180000000800 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000800 0x0 0x400>;
+                       clock-frequency = <800000000>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <0 34>;
+               };
+
+               uart1: serial@1180000000c00 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000c00 0x0 0x400>;
+                       clock-frequency = <800000000>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <0 35>;
+               };
+
+               bootbus: bootbus@1180000000000 {
+                       compatible = "cavium,octeon-3860-bootbus";
+                       reg = <0x11800 0x00000000 0x0 0x200>;
+                       /* The chip select number and offset */
+                       #address-cells = <2>;
+                       /* The size of the chip select region */
+                       #size-cells = <1>;
+                       ranges = <0 0  0       0x1f400000  0xc00000>,
+                                <1 0  0x10000 0x30000000  0>,
+                                <2 0  0       0x1f000000  0x100000>,
+                                <3 0  0x10000 0x50000000  0>,
+                                <4 0  0x10000 0x60000000  0>,
+                                <5 0  0x10000 0x70000000  0>,
+                                <6 0  0x10000 0x80000000  0>,
+                                <7 0  0x10000 0x90000000  0>;
+
+                       cavium,cs-config@0 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <0>;
+                               cavium,t-adr  = <10>;
+                               cavium,t-ce   = <50>;
+                               cavium,t-oe   = <50>;
+                               cavium,t-we   = <35>;
+                               cavium,t-rd-hld = <25>;
+                               cavium,t-wr-hld = <35>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <300>;
+                               cavium,t-page   = <25>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <8>;
+                       };
+                       cavium,cs-config@2 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <2>;
+                               cavium,t-adr  = <0>;
+                               cavium,t-ce   = <50>;
+                               cavium,t-oe   = <20>;
+                               cavium,t-we   = <46>;
+                               cavium,t-rd-hld = <8>;
+                               cavium,t-wr-hld = <10>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <0>;
+                               cavium,t-page   = <1>;
+                               cavium,t-ale    = <1>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <8>;
+                       };
+                       flash0: nor@0,0 {
+                               compatible = "cfi-flash";
+                               reg = <0 0 0x800000>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               partition@0 {
+                                       label = "bootloader";
+                                       reg = <0x0 0x1c0000>;
+                                       read-only;
+                               };
+                               partition@1c0000 {
+                                       label = "kernel";
+                                       reg = <0x1c0000 0x63e000>;
+                               };
+                               partition@7fe000 {
+                                       label = "environment";
+                                       reg = <0x7fe0000 0x2000>;
+                                       read-only;
+                               };
+                       };
+                       psram0: psram@2,0 {
+                               compatible = "micron,mt45w1mw16pd";
+                               reg = <2 0x20 0x20>, <2 0 0x20>;
+                       };
+               };
+
+               dma0: dma-engine@1180000000100 {
+                       compatible = "cavium,octeon-5750-bootbus-dma";
+                       reg = <0x11800 0x00000100 0x0 0x8>;
+                       interrupts = <0 63>;
+               };
+               dma1: dma-engine@1180000000108 {
+                       compatible = "cavium,octeon-5750-bootbus-dma";
+                       reg = <0x11800 0x00000108 0x0 0x8>;
+                       interrupts = <0 63>;
+               };
+               nand-flash-interface@1070001000000 {
+                       compatible = "cavium,octeon-5230-nand";
+                       reg = <0x10700 0x1000000 0x0 0x100 0x11800 0x168 0x0 0x20>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       interrupts = <0x0 0x3f>;
+                       flash@1 {
+                               compatible = "nand-flash";
+                               reg = <0x1>;
+                               nand-ecc-mode = "soft";
+                               nand-ecc-size = <0x200>;
+                               nand-ecc-bytes = <0x7>;
+                               nand-bus-width = <0x8>;
+                       };
+               };
+       };
+       gpio-leds {
+               compatible = "gpio-leds";
+
+               d1a {
+                       label = "bottom";
+                       gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+                       default-state = "keep";
+               };
+               d1b-t {
+                       label = "top";
+                       gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
+                       default-state = "keep";
+               };
+               d1b-v {
+                       label = "top";
+                       gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
+                       default-state = "keep";
+               };
+       };
+
+       aliases {
+               pip = &pip;
+               smi0 = &smi0;
+               twsi0 = &twsi0;
+               twsi1 = &twsi1;
+               uart0 = &uart0;
+               uart1 = &uart1;
+               flash0 = &flash0;
+       };
+ };
index dcab815791fd2bf0f83e912449d43e9f59a35306..1ca2d5eb16240af0e571756b709fcebaeed21ed7 100644 (file)
@@ -74,6 +74,17 @@ define Device/ubnt_edgerouter-6p
 endef
 TARGET_DEVICES += ubnt_edgerouter-6p
 
+define Device/snic10e
+  DEVICE_VENDOR := Cavium
+  DEVICE_MODEL := snic10e
+  DEVICE_DTS := snic10e
+  DEVICE_PACKAGES += kmod-gpio-button-hotplug kmod-hwmon-tmp421 kmod-leds-gpio kmod-of-mdio kmod-sfp
+  KERNEL := kernel-bin | append-dtb-to-elf
+  KERNEL_DEPENDS := $$(wildcard $(DTS_DIR)/$(DEVICE_DTS).dts)
+endef
+
+TARGET_DEVICES += snic10e
+
 ERLITE_CMDLINE:=-mtdparts=phys_mapped_flash:512k(boot0)ro,512k(boot1)ro,64k(eeprom)ro root=/dev/sda2 rootfstype=squashfs,ext4 rootwait
 define Device/ubnt_edgerouter-lite
   DEVICE_VENDOR := Ubiquiti
diff --git a/target/linux/octeon/patches-5.10/141-octeon_snic10e_support.patch b/target/linux/octeon/patches-5.10/141-octeon_snic10e_support.patch
new file mode 100644 (file)
index 0000000..8ff835c
--- /dev/null
@@ -0,0 +1,18 @@
+--- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h
++++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h
+@@ -253,6 +253,7 @@ enum cvmx_board_types_enum {
+       CVMX_BOARD_TYPE_REDWING = 43,
+       CVMX_BOARD_TYPE_NIC68_4 = 44,
+       CVMX_BOARD_TYPE_NIC10E_66 = 45,
++      CVMX_BOARD_TYPE_SNIC10E = 50,
+       CVMX_BOARD_TYPE_MAX,
+       /*
+@@ -369,6 +370,7 @@ static inline const char *cvmx_board_typ
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66)
++              ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SNIC10E)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX)
+                       /* Customer boards listed here */
diff --git a/target/linux/octeon/patches-5.10/300-MIPS-Octeon-fix-CN6640-hang-on-XAUI-init.patch b/target/linux/octeon/patches-5.10/300-MIPS-Octeon-fix-CN6640-hang-on-XAUI-init.patch
new file mode 100644 (file)
index 0000000..7e865d4
--- /dev/null
@@ -0,0 +1,29 @@
+From 8ecd40e17c16d997e0a031dfaea229b1bb906ec1 Mon Sep 17 00:00:00 2001
+From: Stijn Tintel <stijn@linux-ipv6.be>
+Date: Mon, 19 Apr 2021 01:09:56 +0300
+Subject: [PATCH 4/5] MIPS: Octeon: fix CN6640 hang on XAUI init
+
+Some CN66XX series Octeon II chips seem to hang if a reset is issued on
+XAUI initialization. Avoid the hang by disabling the reset.
+
+Tested on SNIC10E.
+
+Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
+---
+ arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
++++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
+@@ -156,8 +156,9 @@ int __cvmx_helper_xaui_enable(int interf
+       xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
+       xauiCtl.s.lo_pwr = 0;
+-      /* Issuing a reset here seems to hang some CN68XX chips. */
+-      if (!OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) &&
++      /* Issuing a reset here seems to hang some CN66XX/CN68XX chips. */
++      if (!OCTEON_IS_MODEL(OCTEON_CN66XX) &&
++          !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) &&
+           !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X))
+               xauiCtl.s.reset = 1;
diff --git a/target/linux/octeon/patches-5.10/301-MIPS-Octeon-support-all-interfaces-on-CN66XX.patch b/target/linux/octeon/patches-5.10/301-MIPS-Octeon-support-all-interfaces-on-CN66XX.patch
new file mode 100644 (file)
index 0000000..b0e6f31
--- /dev/null
@@ -0,0 +1,27 @@
+From 2334bd3f8627cf712fcba61aa22c8169b2326e50 Mon Sep 17 00:00:00 2001
+From: Stijn Tintel <stijn@linux-ipv6.be>
+Date: Mon, 19 Apr 2021 02:00:16 +0300
+Subject: [PATCH 5/5] MIPS: Octeon: support all interfaces on CN66XX
+
+CN66XX_PASS1_0 has 7 interfaces, other revisions have 8 interfaces.
+
+Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
+---
+ arch/mips/cavium-octeon/executive/cvmx-helper.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/mips/cavium-octeon/executive/cvmx-helper.c
++++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c
+@@ -61,6 +61,12 @@ int cvmx_helper_get_number_of_interfaces
+ {
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+               return 9;
++      if (OCTEON_IS_MODEL(OCTEON_CN66XX)) {
++              if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_0))
++                      return 7;
++              else
++                      return 8;
++      }
+       if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
+               return 4;
+       if (OCTEON_IS_MODEL(OCTEON_CN7XXX))
diff --git a/target/linux/octeon/patches-5.10/710-netdev-phy-of-Handle-nexus-Ethernet-PHY-devices.patch b/target/linux/octeon/patches-5.10/710-netdev-phy-of-Handle-nexus-Ethernet-PHY-devices.patch
new file mode 100644 (file)
index 0000000..4f7efe2
--- /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/module.h>
+ #define DEFAULT_GPIO_RESET_DELAY      10      /* in microseconds */
+@@ -278,6 +279,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-5.10/711-netdev-phy-Add-driver-for-Vitesse-vsc848x-single-dua.patch b/target/linux/octeon/patches-5.10/711-netdev-phy-Add-driver-for-Vitesse-vsc848x-single-dua.patch
new file mode 100644 (file)
index 0000000..b29f39f
--- /dev/null
@@ -0,0 +1,833 @@
+From f5985b22b20c704e33394a28a9add765fc2b8312 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 3/5] 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.10, 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 | 770 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 778 insertions(+)
+ create mode 100644 drivers/net/phy/vsc848x.c
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -381,6 +381,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
+@@ -92,4 +92,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,770 @@
++/*
++ * 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 device_node *sfp_node;   /* EEPROM NODE for SFP */
++      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;
++      }
++
++      dev_info->sfp_node = of_parse_phandle(phydev->mdio.dev.of_node,
++                                            "sfp-eeprom", 0);
++      if (!dev_info->sfp_node) {
++              dev_err(&phydev->mdio.dev, "%s has invalid sfp-eeprom node\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_by_phandle(dev_info->sfp_node);
++
++      /* 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.
++       */
++      if (!IS_ERR(nvmem)) {
++              ret = nvmem_device_read(nvmem, 0, 64, sfp_buffer);
++
++              if (!ret)
++                      return -ENODEV;
++      }
++
++      /* 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");
diff --git a/target/linux/octeon/patches-5.10/800-nvmem-core-add-of_nvmem_device_get_by_phandle.patch b/target/linux/octeon/patches-5.10/800-nvmem-core-add-of_nvmem_device_get_by_phandle.patch
new file mode 100644 (file)
index 0000000..6eceb80
--- /dev/null
@@ -0,0 +1,59 @@
+From b4899d5d97b42cf994970d36f00e5cb1af51702f Mon Sep 17 00:00:00 2001
+From: Stijn Tintel <stijn@linux-ipv6.be>
+Date: Wed, 21 Apr 2021 19:09:41 +0300
+Subject: [PATCH 1/5] nvmem: core: add of_nvmem_device_get_by_phandle()
+
+This will be used by the vsc848x PHY driver to read the SFP+ eeprom.
+
+Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
+---
+ drivers/nvmem/core.c           | 14 ++++++++++++++
+ include/linux/nvmem-consumer.h |  7 +++++++
+ 2 files changed, 21 insertions(+)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -868,6 +868,20 @@ struct nvmem_device *of_nvmem_device_get
+       return nvmem;
+ }
+ EXPORT_SYMBOL_GPL(of_nvmem_device_get);
++
++/**
++ * of_nvmem_device_get_by_phandle() - Get nvmem device by a phandle
++ *
++ * @np: Device tree node of the nvmem device.
++ *
++ * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
++ * on success.
++ */
++struct nvmem_device *of_nvmem_device_get_by_phandle(struct device_node* np)
++{
++      return __nvmem_device_get(np, device_match_of_node);
++}
++EXPORT_SYMBOL_GPL(of_nvmem_device_get_by_phandle);
+ #endif
+ /**
+--- a/include/linux/nvmem-consumer.h
++++ b/include/linux/nvmem-consumer.h
+@@ -228,6 +228,7 @@ struct nvmem_cell *of_nvmem_cell_get(str
+                                    const char *id);
+ struct nvmem_device *of_nvmem_device_get(struct device_node *np,
+                                        const char *name);
++struct nvmem_device *of_nvmem_device_get_by_phandle(struct device_node* np);
+ #else
+ static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+                                                  const char *id)
+@@ -240,6 +241,12 @@ static inline struct nvmem_device *of_nv
+ {
+       return ERR_PTR(-EOPNOTSUPP);
+ }
++
++static inline struct nvmem_device
++*of_nvmem_device_get_by_phandle(struct device_node* np)
++{
++      return ERR_PTR(-EOPNOTSUPP);
++}
+ #endif /* CONFIG_NVMEM && CONFIG_OF */
+ #endif  /* ifndef _LINUX_NVMEM_CONSUMER_H */